xref: /haiku/src/servers/app/ServerWindow.cpp (revision 582da17386c4a192ca30270d6b0b95f561cf5843)
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_BEGIN_UPDATE:
1038 			DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title()));
1039 			fWindowLayer->BeginUpdate(fLink);
1040 			break;
1041 
1042 		case AS_END_UPDATE:
1043 			DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title()));
1044 			fWindowLayer->EndUpdate();
1045 			break;
1046 
1047 		case AS_GET_MOUSE:
1048 		{
1049 			DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
1050 
1051 			fDesktop->UnlockSingleWindow();
1052 			// Returns
1053 			// 1) BPoint mouse location
1054 			// 2) int32 button state
1055 
1056 			BPoint where;
1057 			int32 buttons;
1058 			fDesktop->EventDispatcher().GetMouse(where, buttons);
1059 			fDesktop->LockSingleWindow();
1060 
1061 			fLink.StartMessage(B_OK);
1062 			fLink.Attach<BPoint>(where);
1063 			fLink.Attach<int32>(buttons);
1064 			fLink.Flush();
1065 			break;
1066 		}
1067 
1068 		// BDirectWindow communication
1069 
1070 		case AS_DIRECT_WINDOW_GET_SYNC_DATA:
1071 		{
1072 			status_t status = _EnableDirectWindowMode();
1073 
1074 			fLink.StartMessage(status);
1075 			if (status == B_OK) {
1076 				struct direct_window_sync_data syncData = {
1077 					fDirectWindowData->area,
1078 					fDirectWindowData->sem,
1079 					fDirectWindowData->sem_ack
1080 				};
1081 
1082 				fLink.Attach(&syncData, sizeof(syncData));
1083 			}
1084 
1085 			fLink.Flush();
1086 			break;
1087 		}
1088 		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
1089 		{
1090 			// TODO: maybe there is more to do than this?
1091 			bool enable;
1092 			link.Read<bool>(&enable);
1093 
1094 			status_t status = B_OK;
1095 			if (!fWindowLayer->IsOffscreenWindow()) {
1096 				fDesktop->UnlockSingleWindow();
1097 				fDesktop->SetWindowFeel(fWindowLayer,
1098 					enable ? kWindowScreenFeel : B_NORMAL_WINDOW_FEEL);
1099 				fDesktop->LockSingleWindow();
1100 			} else
1101 				status = B_BAD_TYPE;
1102 
1103 			fLink.StartMessage(status);
1104 			fLink.Flush();
1105 			break;
1106 		}
1107 
1108 		// View creation and destruction (don't need a valid fCurrentLayer)
1109 
1110 		case AS_SET_CURRENT_LAYER:
1111 		{
1112 			int32 token;
1113 			if (link.Read<int32>(&token) != B_OK)
1114 				break;
1115 
1116 			ViewLayer *current;
1117 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1118 					(void**)&current) != B_OK
1119 				|| current->Window()->ServerWindow() != this) {
1120 				// ToDo: if this happens, we probably want to kill the app and clean up
1121 				fprintf(stderr, "ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle, token);
1122 				current = NULL;
1123 			} else {
1124 				DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle, current->Name(), token));
1125 				_SetCurrentLayer(current);
1126 			}
1127 			break;
1128 		}
1129 
1130 		case AS_LAYER_CREATE_ROOT:
1131 		{
1132 			STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle));
1133 
1134 			// Start receiving top_view data -- pass NULL as the parent view.
1135 			// This should be the *only* place where this happens.
1136 			if (fCurrentLayer != NULL) {
1137 				fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE_ROOT: fCurrentLayer already set!!\n", fTitle);
1138 				break;
1139 			}
1140 
1141 			_SetCurrentLayer(_CreateLayerTree(link, NULL));
1142 			fWindowLayer->SetTopLayer(fCurrentLayer);
1143 			break;
1144 		}
1145 
1146 		case AS_LAYER_CREATE:
1147 		{
1148 			STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1149 
1150 			ViewLayer* parent = NULL;
1151 			ViewLayer* newLayer = _CreateLayerTree(link, &parent);
1152 			if (parent != NULL && newLayer != NULL)
1153 				parent->AddChild(newLayer);
1154 			else
1155 				fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE: parent or newLayer NULL!!\n", fTitle);
1156 			break;
1157 		}
1158 
1159 		default:
1160 			// TODO: when creating a ViewLayer, check for yet non-existing ViewLayer::InitCheck()
1161 			// and take appropriate actions, then checking for fCurrentLayer->CurrentState()
1162 			// is unnecessary
1163 			if (fCurrentLayer == NULL || fCurrentLayer->CurrentState() == NULL) {
1164 				printf("ServerWindow %s received unexpected code - message offset %ld before top_view attached.\n", Title(), code - B_OK);
1165 				return;
1166 			}
1167 
1168 			_DispatchViewMessage(code, link);
1169 			break;
1170 	}
1171 }
1172 
1173 
1174 /*!
1175 	Dispatches all view messages that need a valid fCurrentLayer.
1176 */
1177 void
1178 ServerWindow::_DispatchViewMessage(int32 code,
1179 	BPrivate::LinkReceiver &link)
1180 {
1181 	if (_DispatchPictureMessage(code, link))
1182 		return;
1183 
1184 	switch (code) {
1185 		case AS_LAYER_SCROLL:
1186 		{
1187 			DTRACE(("ServerWindow %s: Message AS_LAYER_SCROLL: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1188 			float dh;
1189 			float dv;
1190 
1191 			link.Read<float>(&dh);
1192 			link.Read<float>(&dv);
1193 			fWindowLayer->ScrollViewBy(fCurrentLayer, dh, dv);
1194 			break;
1195 		}
1196 		case AS_LAYER_COPY_BITS:
1197 		{
1198 			BRect src;
1199 			BRect dst;
1200 
1201 			link.Read<BRect>(&src);
1202 			link.Read<BRect>(&dst);
1203 
1204 			BRegion contentRegion;
1205 			// TODO: avoid copy operation maybe?
1206 			fWindowLayer->GetContentRegion(&contentRegion);
1207 			fCurrentLayer->CopyBits(src, dst, contentRegion);
1208 			break;
1209 		}
1210 		case AS_LAYER_DELETE:
1211 		{
1212 			// Received when a view is detached from a window
1213 
1214 			int32 token;
1215 			if (link.Read<int32>(&token) != B_OK)
1216 				break;
1217 
1218 			ViewLayer *view;
1219 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1220 					(void**)&view) == B_OK
1221 				&& view->Window()->ServerWindow() == this) {
1222 				ViewLayer* parent = view->Parent();
1223 
1224 				STRACE(("ServerWindow %s: AS_LAYER_DELETE view: %p, parent: %p\n",
1225 					fTitle, view, parent));
1226 
1227 				if (parent != NULL) {
1228 					parent->RemoveChild(view);
1229 
1230 					if (view->EventMask() != 0) {
1231 						fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1232 							token);
1233 					}
1234 					delete view;
1235 				}
1236 			}
1237 			break;
1238 		}
1239 		case AS_LAYER_SET_STATE:
1240 		{
1241 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1242 
1243 			fCurrentLayer->CurrentState()->ReadFromLink(link);
1244 			// TODO: When is this used?!?
1245 			fCurrentLayer->RebuildClipping(true);
1246 			_UpdateDrawState(fCurrentLayer);
1247 
1248 			break;
1249 		}
1250 		case AS_LAYER_SET_FONT_STATE:
1251 		{
1252 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1253 			fCurrentLayer->CurrentState()->ReadFontFromLink(link);
1254 			_UpdateDrawState(fCurrentLayer);
1255 			break;
1256 		}
1257 		case AS_LAYER_GET_STATE:
1258 		{
1259 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1260 
1261 			fLink.StartMessage(B_OK);
1262 
1263 			// attach state data
1264 			fCurrentLayer->CurrentState()->WriteToLink(fLink.Sender());
1265 			fLink.Flush();
1266 			break;
1267 		}
1268 		case AS_LAYER_SET_EVENT_MASK:
1269 		{
1270 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1271 			uint32 eventMask, options;
1272 
1273 			link.Read<uint32>(&eventMask);
1274 			if (link.Read<uint32>(&options) == B_OK) {
1275 				fDesktop->UnlockSingleWindow();
1276 				fCurrentLayer->SetEventMask(eventMask, options);
1277 
1278 				if (eventMask != 0 || options != 0) {
1279 					fDesktop->EventDispatcher().AddListener(EventTarget(),
1280 						fCurrentLayer->Token(), eventMask, options);
1281 				} else {
1282 					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1283 						fCurrentLayer->Token());
1284 				}
1285 				fDesktop->LockSingleWindow();
1286 			}
1287 			break;
1288 		}
1289 		case AS_LAYER_SET_MOUSE_EVENT_MASK:
1290 		{
1291 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1292 			uint32 eventMask, options;
1293 
1294 			link.Read<uint32>(&eventMask);
1295 			if (link.Read<uint32>(&options) == B_OK) {
1296 				fDesktop->UnlockSingleWindow();
1297 				if (eventMask != 0 || options != 0) {
1298 					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1299 						fCurrentLayer->Token(), eventMask, options);
1300 				} else {
1301 					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1302 						fCurrentLayer->Token());
1303 				}
1304 				fDesktop->LockSingleWindow();
1305 			}
1306 
1307 			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1308 			break;
1309 		}
1310 		case AS_LAYER_MOVE_TO:
1311 		{
1312 			STRACE(("ServerWindow %s: Message AS_LAYER_MOVE_TO: ViewLayer name: %s\n",
1313 				fTitle, fCurrentLayer->Name()));
1314 
1315 			float x, y;
1316 			link.Read<float>(&x);
1317 			link.Read<float>(&y);
1318 
1319 			float offsetX = x - fCurrentLayer->Frame().left;
1320 			float offsetY = y - fCurrentLayer->Frame().top;
1321 
1322 			BRegion dirty;
1323 			fCurrentLayer->MoveBy(offsetX, offsetY, &dirty);
1324 
1325 			// TODO: think about how to avoid this hack:
1326 			// the parent clipping needs to be updated, it is not
1327 			// done in MoveBy() since it would need to avoid
1328 			// too much computations when children are resized because
1329 			// follow modes
1330 			if (ViewLayer* parent = fCurrentLayer->Parent())
1331 				parent->RebuildClipping(false);
1332 
1333 			fWindowLayer->MarkContentDirty(dirty);
1334 			break;
1335 		}
1336 		case AS_LAYER_RESIZE_TO:
1337 		{
1338 			STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_TO: ViewLayer name: %s\n",
1339 				fTitle, fCurrentLayer->Name()));
1340 
1341 			float newWidth, newHeight;
1342 			link.Read<float>(&newWidth);
1343 			link.Read<float>(&newHeight);
1344 
1345 			float deltaWidth = newWidth - fCurrentLayer->Frame().Width();
1346 			float deltaHeight = newHeight - fCurrentLayer->Frame().Height();
1347 
1348 			BRegion dirty;
1349 			fCurrentLayer->ResizeBy(deltaWidth, deltaHeight, &dirty);
1350 
1351 			// TODO: see above
1352 			if (ViewLayer* parent = fCurrentLayer->Parent())
1353 				parent->RebuildClipping(false);
1354 
1355 			fWindowLayer->MarkContentDirty(dirty);
1356 			break;
1357 		}
1358 		case AS_LAYER_GET_COORD:
1359 		{
1360 			STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1361 			fLink.StartMessage(B_OK);
1362 			// our offset in the parent -> will be originX and originY in BView
1363 			fLink.Attach<float>(fCurrentLayer->Frame().left);
1364 			fLink.Attach<float>(fCurrentLayer->Frame().top);
1365 			fLink.Attach<BRect>(fCurrentLayer->Bounds());
1366 			fLink.Flush();
1367 			break;
1368 		}
1369 		case AS_LAYER_SET_ORIGIN:
1370 		{
1371 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1372 
1373 			float x, y;
1374 			link.Read<float>(&x);
1375 			link.Read<float>(&y);
1376 
1377 			fCurrentLayer->SetDrawingOrigin(BPoint(x, y));
1378 			_UpdateDrawState(fCurrentLayer);
1379 			break;
1380 		}
1381 		case AS_LAYER_GET_ORIGIN:
1382 		{
1383 			STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1384 			fLink.StartMessage(B_OK);
1385 			// TODO: rename this where it is used in the BView code!
1386 			// (it wants to know scrolling offset, not drawing origin)
1387 			fLink.Attach<BPoint>(fCurrentLayer->ScrollingOffset());
1388 			fLink.Flush();
1389 			break;
1390 		}
1391 		case AS_LAYER_RESIZE_MODE:
1392 		{
1393 			STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: ViewLayer: %s\n",
1394 				Title(), fCurrentLayer->Name()));
1395 
1396 			uint32 resizeMode;
1397 			if (link.Read<uint32>(&resizeMode) == B_OK)
1398 				fCurrentLayer->SetResizeMode(resizeMode);
1399 			break;
1400 		}
1401 		case AS_LAYER_SET_CURSOR:
1402 		{
1403 			DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: ViewLayer: %s\n", Title(),
1404 				fCurrentLayer->Name()));
1405 
1406 			int32 token;
1407 			bool sync;
1408 			link.Read<int32>(&token);
1409 			if (link.Read<bool>(&sync) != B_OK)
1410 				break;
1411 
1412 			if (!fDesktop->GetCursorManager().Lock())
1413 				break;
1414 
1415 			ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token);
1416 			fCurrentLayer->SetCursor(cursor);
1417 
1418 			fDesktop->GetCursorManager().Unlock();
1419 
1420 			if (fWindowLayer->IsFocus()) {
1421 				// The cursor might need to be updated now
1422 				if (fDesktop->ViewUnderMouse(fWindowLayer) == fCurrentLayer->Token())
1423 					fServerApp->SetCurrentCursor(cursor);
1424 			}
1425 			if (sync) {
1426 				// sync the client (it can now delete the cursor)
1427 				fLink.StartMessage(B_OK);
1428 				fLink.Flush();
1429 			}
1430 
1431 			break;
1432 		}
1433 		case AS_LAYER_SET_FLAGS:
1434 		{
1435 			uint32 flags;
1436 			link.Read<uint32>(&flags);
1437 			fCurrentLayer->SetFlags(flags);
1438 			_UpdateDrawState(fCurrentLayer);
1439 
1440 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1441 			break;
1442 		}
1443 		case AS_LAYER_HIDE:
1444 		{
1445 			STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1446 			fCurrentLayer->SetHidden(true);
1447 			break;
1448 		}
1449 		case AS_LAYER_SHOW:
1450 		{
1451 			STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1452 			fCurrentLayer->SetHidden(false);
1453 			break;
1454 		}
1455 		case AS_LAYER_SET_LINE_MODE:
1456 		{
1457 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1458 			int8 lineCap, lineJoin;
1459 			float miterLimit;
1460 
1461 			link.Read<int8>(&lineCap);
1462 			link.Read<int8>(&lineJoin);
1463 			link.Read<float>(&miterLimit);
1464 
1465 			fCurrentLayer->CurrentState()->SetLineCapMode((cap_mode)lineCap);
1466 			fCurrentLayer->CurrentState()->SetLineJoinMode((join_mode)lineJoin);
1467 			fCurrentLayer->CurrentState()->SetMiterLimit(miterLimit);
1468 
1469 			_UpdateDrawState(fCurrentLayer);
1470 
1471 			break;
1472 		}
1473 		case AS_LAYER_GET_LINE_MODE:
1474 		{
1475 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1476 			fLink.StartMessage(B_OK);
1477 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineCapMode()));
1478 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineJoinMode()));
1479 			fLink.Attach<float>(fCurrentLayer->CurrentState()->MiterLimit());
1480 			fLink.Flush();
1481 
1482 			break;
1483 		}
1484 		case AS_LAYER_PUSH_STATE:
1485 		{
1486 			DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1487 
1488 			fCurrentLayer->PushState();
1489 			// TODO: is this necessary?
1490 			_UpdateDrawState(fCurrentLayer);
1491 			break;
1492 		}
1493 		case AS_LAYER_POP_STATE:
1494 		{
1495 			DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1496 
1497 			fCurrentLayer->PopState();
1498 			_UpdateDrawState(fCurrentLayer);
1499 			break;
1500 		}
1501 		case AS_LAYER_SET_SCALE:
1502 		{
1503 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1504 			float scale;
1505 			link.Read<float>(&scale);
1506 
1507 			fCurrentLayer->SetScale(scale);
1508 			_UpdateDrawState(fCurrentLayer);
1509 			break;
1510 		}
1511 		case AS_LAYER_GET_SCALE:
1512 		{
1513 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1514 
1515 			fLink.StartMessage(B_OK);
1516 			fLink.Attach<float>(fCurrentLayer->CurrentState()->Scale());
1517 			fLink.Flush();
1518 			break;
1519 		}
1520 		case AS_LAYER_SET_PEN_LOC:
1521 		{
1522 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1523 			float x, y;
1524 
1525 			link.Read<float>(&x);
1526 			link.Read<float>(&y);
1527 
1528 			fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y));
1529 			// TODO: is this necessary?
1530 			_UpdateDrawState(fCurrentLayer);
1531 			break;
1532 		}
1533 		case AS_LAYER_GET_PEN_LOC:
1534 		{
1535 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1536 			fLink.StartMessage(B_OK);
1537 			fLink.Attach<BPoint>(fCurrentLayer->CurrentState()->PenLocation());
1538 			fLink.Flush();
1539 
1540 			break;
1541 		}
1542 		case AS_LAYER_SET_PEN_SIZE:
1543 		{
1544 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1545 			float penSize;
1546 			link.Read<float>(&penSize);
1547 
1548 			fCurrentLayer->CurrentState()->SetPenSize(penSize);
1549 			//_UpdateDrawState(fCurrentLayer);
1550 			fWindowLayer->GetDrawingEngine()->SetPenSize(penSize);
1551 			break;
1552 		}
1553 		case AS_LAYER_GET_PEN_SIZE:
1554 		{
1555 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1556 			fLink.StartMessage(B_OK);
1557 			fLink.Attach<float>(fCurrentLayer->CurrentState()->PenSize());
1558 			fLink.Flush();
1559 
1560 			break;
1561 		}
1562 		case AS_LAYER_SET_VIEW_COLOR:
1563 		{
1564 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1565 			rgb_color c;
1566 
1567 			link.Read(&c, sizeof(rgb_color));
1568 
1569 			fCurrentLayer->SetViewColor(RGBColor(c));
1570 			break;
1571 		}
1572 
1573 		case AS_LAYER_GET_HIGH_COLOR:
1574 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_HIGH_COLOR: ViewLayer: %s\n",
1575 				Title(), fCurrentLayer->Name()));
1576 
1577 			fLink.StartMessage(B_OK);
1578 			fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->HighColor().GetColor32());
1579 			fLink.Flush();
1580 			break;
1581 
1582 		case AS_LAYER_GET_LOW_COLOR:
1583 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LOW_COLOR: ViewLayer: %s\n",
1584 				Title(), fCurrentLayer->Name()));
1585 
1586 			fLink.StartMessage(B_OK);
1587 			fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->LowColor().GetColor32());
1588 			fLink.Flush();
1589 			break;
1590 
1591 		case AS_LAYER_GET_VIEW_COLOR:
1592 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_VIEW_COLOR: ViewLayer: %s\n",
1593 				Title(), fCurrentLayer->Name()));
1594 
1595 			fLink.StartMessage(B_OK);
1596 			fLink.Attach<rgb_color>(fCurrentLayer->ViewColor().GetColor32());
1597 			fLink.Flush();
1598 			break;
1599 
1600 		case AS_LAYER_SET_BLENDING_MODE:
1601 		{
1602 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1603 			int8 srcAlpha, alphaFunc;
1604 
1605 			link.Read<int8>(&srcAlpha);
1606 			link.Read<int8>(&alphaFunc);
1607 
1608 			fCurrentLayer->CurrentState()->SetBlendingMode((source_alpha)srcAlpha,
1609 											(alpha_function)alphaFunc);
1610 			_UpdateDrawState(fCurrentLayer);
1611 			break;
1612 		}
1613 		case AS_LAYER_GET_BLENDING_MODE:
1614 		{
1615 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1616 			fLink.StartMessage(B_OK);
1617 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaSrcMode()));
1618 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaFncMode()));
1619 			fLink.Flush();
1620 
1621 			break;
1622 		}
1623 		case AS_LAYER_SET_DRAWING_MODE:
1624 		{
1625 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1626 			int8 drawingMode;
1627 
1628 			link.Read<int8>(&drawingMode);
1629 
1630 			fCurrentLayer->CurrentState()->SetDrawingMode((drawing_mode)drawingMode);
1631 			//_UpdateDrawState(fCurrentLayer);
1632 			fWindowLayer->GetDrawingEngine()->SetDrawingMode((drawing_mode)drawingMode);
1633 			break;
1634 		}
1635 		case AS_LAYER_GET_DRAWING_MODE:
1636 		{
1637 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1638 			fLink.StartMessage(B_OK);
1639 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->GetDrawingMode()));
1640 			fLink.Flush();
1641 
1642 			break;
1643 		}
1644 		case AS_LAYER_SET_VIEW_BITMAP:
1645 		{
1646 			int32 bitmapToken, resizingMode, options;
1647 			BRect srcRect, dstRect;
1648 
1649 			link.Read<int32>(&bitmapToken);
1650 			link.Read<BRect>(&srcRect);
1651 			link.Read<BRect>(&dstRect);
1652 			link.Read<int32>(&resizingMode);
1653 			status_t status = link.Read<int32>(&options);
1654 
1655 			rgb_color colorKey = {0};
1656 
1657 			if (status == B_OK) {
1658 				ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1659 				if (bitmapToken == -1 || bitmap != NULL) {
1660 					bool wasOverlay = fCurrentLayer->ViewBitmap() != NULL
1661 						&& fCurrentLayer->ViewBitmap()->Overlay() != NULL;
1662 
1663 					// TODO: this is a race condition: the bitmap could have been
1664 					//	deleted in the mean time!!
1665 					fCurrentLayer->SetViewBitmap(bitmap, srcRect, dstRect,
1666 						resizingMode, options);
1667 
1668 					// TODO: if we revert the view color overlay handling
1669 					//	in ViewLayer::Draw() to the R5 version, we never
1670 					//	need to invalidate the view for overlays.
1671 
1672 					// invalidate view - but only if this is a non-overlay switch
1673 					if (bitmap == NULL || bitmap->Overlay() == NULL || !wasOverlay) {
1674 						BRegion dirty((BRect)fCurrentLayer->Bounds());
1675 						fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1676 					}
1677 
1678 					if (bitmap != NULL && bitmap->Overlay() != NULL) {
1679 						bitmap->Overlay()->SetFlags(options);
1680 						colorKey = bitmap->Overlay()->Color().GetColor32();
1681 					}
1682 				} else
1683 					status = B_BAD_VALUE;
1684 			}
1685 
1686 			fLink.StartMessage(status);
1687 			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
1688 				// Attach color key for the overlay bitmap
1689 				fLink.Attach<rgb_color>(colorKey);
1690 			}
1691 
1692 			fLink.Flush();
1693 			break;
1694 		}
1695 		case AS_LAYER_PRINT_ALIASING:
1696 		{
1697 			DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1698 			bool fontAliasing;
1699 			if (link.Read<bool>(&fontAliasing) == B_OK) {
1700 				fCurrentLayer->CurrentState()->SetForceFontAliasing(fontAliasing);
1701 				_UpdateDrawState(fCurrentLayer);
1702 			}
1703 			break;
1704 		}
1705 		case AS_LAYER_CLIP_TO_PICTURE:
1706 		{
1707 			DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1708 			// TODO: you are not allowed to use ViewLayer regions here!!!
1709 
1710 			int32 pictureToken;
1711 			BPoint where;
1712 			bool inverse = false;
1713 
1714 			link.Read<int32>(&pictureToken);
1715 			link.Read<BPoint>(&where);
1716 			link.Read<bool>(&inverse);
1717 
1718 			// search for a picture with the specified token.
1719 			ServerPicture *picture = fServerApp->FindPicture(pictureToken);
1720 			// TODO: Increase that picture's reference count.(~ allocate a picture)
1721 			if (picture == NULL)
1722 				break;
1723 
1724 			BRegion region;
1725 			// TODO: I think we also need the BView's token
1726 			// I think PictureToRegion would fit better into the ViewLayer class (?)
1727 			if (PictureToRegion(picture, region, inverse, where) < B_OK)
1728 				break;
1729 
1730 			fCurrentLayer->SetUserClipping(&region);
1731 
1732 // TODO: reenable AS_LAYER_CLIP_TO_PICTURE
1733 #if 0
1734 			if (rootLayer && !(fCurrentLayer->IsHidden()) && !fWindowLayer->InUpdate()) {
1735 				BRegion invalidRegion;
1736 				fCurrentLayer->GetOnScreenRegion(invalidRegion);
1737 
1738 				// TODO: this is broken! a smaller area may be invalidated!
1739 
1740 				fCurrentLayer->fParent->MarkForRebuild(invalidRegion);
1741 				fCurrentLayer->fParent->TriggerRebuild();
1742 				rootLayer->MarkForRedraw(invalidRegion);
1743 				rootLayer->TriggerRedraw();
1744 			}
1745 #endif
1746 			break;
1747 		}
1748 
1749 		case AS_LAYER_GET_CLIP_REGION:
1750 		{
1751 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1752 
1753 			// if this ViewLayer is hidden, it is clear that its visible region is void.
1754 			fLink.StartMessage(B_OK);
1755 			if (fCurrentLayer->IsHidden()) {
1756 				BRegion empty;
1757 				fLink.AttachRegion(empty);
1758 			} else {
1759 				BRegion drawingRegion = fCurrentLayer->LocalClipping();
1760 				fLink.AttachRegion(drawingRegion);
1761 			}
1762 			fLink.Flush();
1763 
1764 			break;
1765 		}
1766 		case AS_LAYER_SET_CLIP_REGION:
1767 		{
1768 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1769 
1770 			int32 rectCount;
1771 			status_t status = link.Read<int32>(&rectCount);
1772 				// a negative count means no
1773 				// region for the current draw state,
1774 				// but an *empty* region is actually valid!
1775 				// even if it means no drawing is allowed
1776 
1777 			if (status < B_OK)
1778 				break;
1779 
1780 			if (rectCount >= 0) {
1781 				// we are supposed to set the clipping region
1782 				BRegion region;
1783 				if (link.ReadRegion(&region) < B_OK)
1784 					break;
1785 				fCurrentLayer->SetUserClipping(&region);
1786 			} else {
1787 				// we are supposed to unset the clipping region
1788 				// passing NULL sets this states region to that
1789 				// of the previous state
1790 				fCurrentLayer->SetUserClipping(NULL);
1791 			}
1792 
1793 			break;
1794 		}
1795 
1796 		case AS_LAYER_INVALIDATE_RECT:
1797 		{
1798 			DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1799 
1800 			// NOTE: looks like this call is NOT affected by origin and scale on R5
1801 			// so this implementation is "correct"
1802 			BRect invalidRect;
1803 			if (link.Read<BRect>(&invalidRect) == B_OK) {
1804 				BRegion dirty(invalidRect);
1805 				fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1806 			}
1807 			break;
1808 		}
1809 		case AS_LAYER_INVALIDATE_REGION:
1810 		{
1811 			DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1812 
1813 			// NOTE: looks like this call is NOT affected by origin and scale on R5
1814 			// so this implementation is "correct"
1815 			BRegion region;
1816 			if (link.ReadRegion(&region) < B_OK)
1817 				break;
1818 
1819 			fWindowLayer->InvalidateView(fCurrentLayer, region);
1820 			break;
1821 		}
1822 
1823 		case AS_LAYER_SET_HIGH_COLOR:
1824 		{
1825 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1826 
1827 			rgb_color c;
1828 			link.Read(&c, sizeof(rgb_color));
1829 
1830 			fCurrentLayer->CurrentState()->SetHighColor(RGBColor(c));
1831 //			_UpdateDrawState(fCurrentLayer);
1832 			fWindowLayer->GetDrawingEngine()->SetHighColor(c);
1833 			break;
1834 		}
1835 		case AS_LAYER_SET_LOW_COLOR:
1836 		{
1837 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1838 
1839 			rgb_color c;
1840 			link.Read(&c, sizeof(rgb_color));
1841 
1842 			fCurrentLayer->CurrentState()->SetLowColor(RGBColor(c));
1843 //			_UpdateDrawState(fCurrentLayer);
1844 			fWindowLayer->GetDrawingEngine()->SetLowColor(c);
1845 			break;
1846 		}
1847 		case AS_LAYER_SET_PATTERN:
1848 		{
1849 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: ViewLayer: %s\n", fTitle, fCurrentLayer->Name()));
1850 
1851 			pattern pat;
1852 			link.Read(&pat, sizeof(pattern));
1853 
1854 			fCurrentLayer->CurrentState()->SetPattern(Pattern(pat));
1855 //			_UpdateDrawState(fCurrentLayer);
1856 			fWindowLayer->GetDrawingEngine()->SetPattern(pat);
1857 			break;
1858 		}
1859 		case AS_SET_FONT:
1860 		{
1861 			DTRACE(("ServerWindow %s: Message AS_SET_FONT\n", Title()));
1862 			// TODO: Implement AS_SET_FONT?
1863 			// Confusing!! But it works already!
1864 			break;
1865 		}
1866 		case AS_SET_FONT_SIZE:
1867 		{
1868 			DTRACE(("ServerWindow %s: Message AS_SET_FONT_SIZE\n", Title()));
1869 			// TODO: Implement AS_SET_FONT_SIZE?
1870 			break;
1871 		}
1872 		case AS_SYNC:
1873 		{
1874 			// the synchronisation works by the fact that the client
1875 			// window is waiting for this reply, after having received it,
1876 			// client and server queues are in sync (earlier, the client
1877 			// may have pushed drawing commands at the server and now it
1878 			// knows they have all been carried out)
1879 			fLink.StartMessage(B_OK);
1880 			fLink.Flush();
1881 			break;
1882 		}
1883 		case AS_LAYER_DRAG_IMAGE:
1884 		{
1885 			// TODO: flesh out AS_LAYER_DRAG_IMAGE
1886 			STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
1887 
1888 			int32 bitmapToken;
1889 			drawing_mode dragMode;
1890 			BPoint offset;
1891 			int32 bufferSize;
1892 
1893 			link.Read<int32>(&bitmapToken);
1894 			link.Read<int32>((int32*)&dragMode);
1895 			link.Read<BPoint>(&offset);
1896 			link.Read<int32>(&bufferSize);
1897 
1898 			if (bufferSize > 0) {
1899 				char* buffer = new (nothrow) char[bufferSize];
1900 				BMessage dragMessage;
1901 				if (link.Read(buffer, bufferSize) == B_OK
1902 					&& dragMessage.Unflatten(buffer) == B_OK) {
1903 						ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1904 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1905 																   bitmap, offset);
1906 				}
1907 				delete[] buffer;
1908 			}
1909 			// sync the client (it can now delete the bitmap)
1910 			fLink.StartMessage(B_OK);
1911 			fLink.Flush();
1912 
1913 			break;
1914 		}
1915 		case AS_LAYER_DRAG_RECT:
1916 		{
1917 			// TODO: flesh out AS_LAYER_DRAG_RECT
1918 			STRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
1919 
1920 			BRect dragRect;
1921 			BPoint offset;
1922 			int32 bufferSize;
1923 
1924 			link.Read<BRect>(&dragRect);
1925 			link.Read<BPoint>(&offset);
1926 			link.Read<int32>(&bufferSize);
1927 
1928 			if (bufferSize > 0) {
1929 				char* buffer = new (nothrow) char[bufferSize];
1930 				BMessage dragMessage;
1931 				if (link.Read(buffer, bufferSize) == B_OK
1932 					&& dragMessage.Unflatten(buffer) == B_OK) {
1933 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1934 							NULL /* should be dragRect */, offset);
1935 				}
1936 				delete[] buffer;
1937 			}
1938 
1939 			break;
1940 		}
1941 
1942 		case AS_LAYER_BEGIN_PICTURE:
1943 		{
1944 			DTRACE(("ServerWindow %s: Message AS_LAYER_BEGIN_PICTURE\n", Title()));
1945 			ServerPicture *picture = App()->CreatePicture();
1946 			picture->SyncState(fCurrentLayer);
1947 			fCurrentLayer->SetPicture(picture);
1948 			break;
1949 		}
1950 
1951 		case AS_LAYER_APPEND_TO_PICTURE:
1952 		{
1953 			DTRACE(("ServerWindow %s: Message AS_LAYER_APPEND_TO_PICTURE\n", Title()));
1954 
1955 			int32 pictureToken;
1956 			link.Read<int32>(&pictureToken);
1957 			ServerPicture *picture = App()->FindPicture(pictureToken);
1958 			if (picture)
1959 				picture->SyncState(fCurrentLayer);
1960 			fCurrentLayer->SetPicture(picture);
1961 				// we don't care if it's NULL
1962 			break;
1963 		}
1964 
1965 		case AS_LAYER_END_PICTURE:
1966 		{
1967 			DTRACE(("ServerWindow %s: Message AS_LAYER_END_PICTURE\n", Title()));
1968 
1969 			ServerPicture *picture = fCurrentLayer->Picture();
1970 			if (picture != NULL) {
1971 				fCurrentLayer->SetPicture(NULL);
1972 				fLink.StartMessage(B_OK);
1973 				fLink.Attach<int32>(picture->Token());
1974 			} else
1975 				fLink.StartMessage(B_ERROR);
1976 
1977 			fLink.Flush();
1978 			break;
1979 		}
1980 
1981 		default:
1982 			_DispatchViewDrawingMessage(code, link);
1983 			break;
1984 	}
1985 }
1986 
1987 
1988 /*!
1989 	Dispatches all view drawing messages.
1990 	The desktop clipping must be read locked when entering this method.
1991 	Requires a valid fCurrentLayer.
1992 */
1993 void
1994 ServerWindow::_DispatchViewDrawingMessage(int32 code, BPrivate::LinkReceiver &link)
1995 {
1996 	if (!fCurrentLayer->IsVisible() || !fWindowLayer->IsVisible()) {
1997 		if (link.NeedsReply()) {
1998 			printf("ServerWindow::DispatchViewDrawingMessage() got message %ld that needs a reply!\n", code);
1999 			// the client is now blocking and waiting for a reply!
2000 			fLink.StartMessage(B_ERROR);
2001 			fLink.Flush();
2002 		}
2003 		return;
2004 	}
2005 
2006 	DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2007 	if (!drawingEngine) {
2008 		// ?!?
2009 		DTRACE(("ServerWindow %s: no drawing engine!!\n", Title()));
2010 		if (link.NeedsReply()) {
2011 			// the client is now blocking and waiting for a reply!
2012 			fLink.StartMessage(B_ERROR);
2013 			fLink.Flush();
2014 		}
2015 		return;
2016 	}
2017 
2018 	if (!fCurrentDrawingRegionValid || fWindowLayer->DrawingRegionChanged(fCurrentLayer)) {
2019 		fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
2020 		fCurrentDrawingRegionValid = true;
2021 	}
2022 
2023 	if (fCurrentDrawingRegion.CountRects() <= 0) {
2024 		if (link.NeedsReply()) {
2025 			// the client is now blocking and waiting for a reply!
2026 			fLink.StartMessage(B_ERROR);
2027 			fLink.Flush();
2028 		}
2029 		return;
2030 	}
2031 
2032 	drawingEngine->LockParallelAccess();
2033 	// NOTE: the region is not copied, Painter keeps a pointer,
2034 	// that's why you need to use the clipping only for as long
2035 	// as you have it locked
2036 	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
2037 
2038 	switch (code) {
2039 		case AS_STROKE_LINE:
2040 		{
2041 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE\n", Title()));
2042 
2043 			float x1, y1, x2, y2;
2044 
2045 			link.Read<float>(&x1);
2046 			link.Read<float>(&y1);
2047 			link.Read<float>(&x2);
2048 			link.Read<float>(&y2);
2049 
2050 			BPoint p1(x1, y1);
2051 			BPoint p2(x2, y2);
2052 			BPoint penPos = p2;
2053 			fCurrentLayer->ConvertToScreenForDrawing(&p1);
2054 			fCurrentLayer->ConvertToScreenForDrawing(&p2);
2055 			drawingEngine->StrokeLine(p1, p2, fCurrentLayer->CurrentState());
2056 
2057 			// We update the pen here because many DrawingEngine calls which do not update the
2058 			// pen position actually call StrokeLine
2059 
2060 			// TODO: Decide where to put this, for example, it cannot be done
2061 			// for DrawString(), also there needs to be a decision, if penlocation
2062 			// is in View coordinates (I think it should be) or in screen coordinates.
2063 			fCurrentLayer->CurrentState()->SetPenLocation(penPos);
2064 			break;
2065 		}
2066 		case AS_LAYER_INVERT_RECT:
2067 		{
2068 			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT\n", Title()));
2069 
2070 			BRect rect;
2071 			link.Read<BRect>(&rect);
2072 
2073 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2074 			drawingEngine->InvertRect(rect);
2075 			break;
2076 		}
2077 		case AS_STROKE_RECT:
2078 		{
2079 			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT\n", Title()));
2080 
2081 			float left, top, right, bottom;
2082 			link.Read<float>(&left);
2083 			link.Read<float>(&top);
2084 			link.Read<float>(&right);
2085 			link.Read<float>(&bottom);
2086 			BRect rect(left,top,right,bottom);
2087 
2088 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2089 			drawingEngine->StrokeRect(rect, fCurrentLayer->CurrentState());
2090 			break;
2091 		}
2092 		case AS_FILL_RECT:
2093 		{
2094 			DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n", Title()));
2095 
2096 			BRect rect;
2097 			link.Read<BRect>(&rect);
2098 
2099 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2100 			drawingEngine->FillRect(rect, fCurrentLayer->CurrentState());
2101 			break;
2102 		}
2103 		case AS_LAYER_DRAW_BITMAP:
2104 		{
2105 			DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
2106 			int32 bitmapToken;
2107 			BRect srcRect, dstRect;
2108 
2109 			link.Read<int32>(&bitmapToken);
2110 			link.Read<BRect>(&dstRect);
2111 			link.Read<BRect>(&srcRect);
2112 
2113 			ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
2114 			if (bitmap) {
2115 				fCurrentLayer->ConvertToScreenForDrawing(&dstRect);
2116 
2117 				drawingEngine->DrawBitmap(bitmap, srcRect, dstRect, fCurrentLayer->CurrentState());
2118 			}
2119 
2120 			break;
2121 		}
2122 		case AS_STROKE_ARC:
2123 		case AS_FILL_ARC:
2124 		{
2125 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2126 
2127 			float angle, span;
2128 			BRect r;
2129 
2130 			link.Read<BRect>(&r);
2131 			link.Read<float>(&angle);
2132 			link.Read<float>(&span);
2133 
2134 			fCurrentLayer->ConvertToScreenForDrawing(&r);
2135 			drawingEngine->DrawArc(r, angle, span, fCurrentLayer->CurrentState(),
2136 								   code == AS_FILL_ARC);
2137 			break;
2138 		}
2139 		case AS_STROKE_BEZIER:
2140 		case AS_FILL_BEZIER:
2141 		{
2142 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title()));
2143 
2144 			BPoint pts[4];
2145 			for (int32 i = 0; i < 4; i++) {
2146 				link.Read<BPoint>(&(pts[i]));
2147 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2148 			}
2149 
2150 			drawingEngine->DrawBezier(pts, fCurrentLayer->CurrentState(),
2151 									  code == AS_FILL_BEZIER);
2152 			break;
2153 		}
2154 		case AS_STROKE_ELLIPSE:
2155 		case AS_FILL_ELLIPSE:
2156 		{
2157 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", Title()));
2158 
2159 			BRect rect;
2160 			link.Read<BRect>(&rect);
2161 
2162 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2163 			drawingEngine->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE);
2164 			break;
2165 		}
2166 		case AS_STROKE_ROUNDRECT:
2167 		case AS_FILL_ROUNDRECT:
2168 		{
2169 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", Title()));
2170 
2171 			BRect rect;
2172 			float xrad,yrad;
2173 			link.Read<BRect>(&rect);
2174 			link.Read<float>(&xrad);
2175 			link.Read<float>(&yrad);
2176 
2177 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2178 			drawingEngine->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT);
2179 			break;
2180 		}
2181 		case AS_STROKE_TRIANGLE:
2182 		case AS_FILL_TRIANGLE:
2183 		{
2184 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", Title()));
2185 
2186 			BPoint pts[3];
2187 			BRect rect;
2188 
2189 			for (int32 i = 0; i < 3; i++) {
2190 				link.Read<BPoint>(&(pts[i]));
2191 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2192 			}
2193 
2194 			link.Read<BRect>(&rect);
2195 
2196 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2197 			drawingEngine->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE);
2198 			break;
2199 		}
2200 		case AS_STROKE_POLYGON:
2201 		case AS_FILL_POLYGON:
2202 		{
2203 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", Title()));
2204 
2205 			BRect polyFrame;
2206 			bool isClosed = true;
2207 			int32 pointCount;
2208 
2209 			link.Read<BRect>(&polyFrame);
2210 			if (code == AS_STROKE_POLYGON)
2211 				link.Read<bool>(&isClosed);
2212 			link.Read<int32>(&pointCount);
2213 
2214 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2215 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2216 				for (int32 i = 0; i < pointCount; i++)
2217 					fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]);
2218 				fCurrentLayer->ConvertToScreenForDrawing(&polyFrame);
2219 
2220 				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2221 					fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON,
2222 					isClosed && pointCount > 2);
2223 			}
2224 			delete[] pointList;
2225 			break;
2226 		}
2227 		case AS_STROKE_SHAPE:
2228 		case AS_FILL_SHAPE:
2229 		{
2230 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", Title()));
2231 
2232 			BRect shapeFrame;
2233 			int32 opCount;
2234 			int32 ptCount;
2235 
2236 			link.Read<BRect>(&shapeFrame);
2237 			link.Read<int32>(&opCount);
2238 			link.Read<int32>(&ptCount);
2239 
2240 			uint32* opList = new(nothrow) uint32[opCount];
2241 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2242 			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2243 				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2244 
2245 				for (int32 i = 0; i < ptCount; i++)
2246 					fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]);
2247 
2248 				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList,
2249 					fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE);
2250 			}
2251 
2252 			delete[] opList;
2253 			delete[] ptList;
2254 			break;
2255 		}
2256 		case AS_FILL_REGION:
2257 		{
2258 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2259 
2260 			BRegion region;
2261 			if (link.ReadRegion(&region) < B_OK)
2262 				break;
2263 
2264 			fCurrentLayer->ConvertToScreenForDrawing(&region);
2265 			drawingEngine->FillRegion(region, fCurrentLayer->CurrentState());
2266 
2267 			break;
2268 		}
2269 		case AS_STROKE_LINEARRAY:
2270 		{
2271 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", Title()));
2272 
2273 			// Attached Data:
2274 			// 1) int32 Number of lines in the array
2275 			// 2) LineArrayData
2276 
2277 			int32 lineCount;
2278 
2279 			link.Read<int32>(&lineCount);
2280 			if (lineCount > 0) {
2281 				LineArrayData lineData[lineCount];
2282 
2283 				for (int32 i = 0; i < lineCount; i++) {
2284 					LineArrayData* index = &lineData[i];
2285 
2286 					link.Read<float>(&(index->pt1.x));
2287 					link.Read<float>(&(index->pt1.y));
2288 					link.Read<float>(&(index->pt2.x));
2289 					link.Read<float>(&(index->pt2.y));
2290 					link.Read<rgb_color>(&(index->color));
2291 
2292 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt1);
2293 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt2);
2294 				}
2295 				drawingEngine->StrokeLineArray(lineCount, lineData,
2296 					fCurrentLayer->CurrentState());
2297 			}
2298 			break;
2299 		}
2300 		case AS_DRAW_STRING:
2301 		{
2302 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n", Title()));
2303 			char* string;
2304 			int32 length;
2305 			BPoint location;
2306 			escapement_delta delta;
2307 
2308 			link.Read<int32>(&length);
2309 			link.Read<BPoint>(&location);
2310 			link.Read<escapement_delta>(&delta);
2311 			link.ReadString(&string);
2312 
2313 			fCurrentLayer->ConvertToScreenForDrawing(&location);
2314 			BPoint penLocation = drawingEngine->DrawString(string, length, location,
2315 				fCurrentLayer->CurrentState(), &delta);
2316 
2317 			fCurrentLayer->ConvertFromScreenForDrawing(&penLocation);
2318 			fCurrentLayer->CurrentState()->SetPenLocation(penLocation);
2319 			// TODO: optimize with flags
2320 			_UpdateDrawState(fCurrentLayer);
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->ConvertToScreenForDrawing(&where);
2336 					fCurrentLayer->CurrentState()->SetPenLocation(where);
2337 					// TODO: pass the location to the play method and handle it there
2338 					picture->Play(fCurrentLayer);
2339 				}
2340 			}
2341 			break;
2342 		}
2343 
2344 		default:
2345 			printf("ServerWindow %s received unexpected code - message offset %ld\n",
2346 				Title(), code - B_OK);
2347 
2348 			if (link.NeedsReply()) {
2349 				// the client is now blocking and waiting for a reply!
2350 				fLink.StartMessage(B_ERROR);
2351 				fLink.Flush();
2352 			}
2353 			break;
2354 	}
2355 
2356 	drawingEngine->UnlockParallelAccess();
2357 }
2358 
2359 
2360 bool
2361 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
2362 {
2363 	ServerPicture *picture = fCurrentLayer->Picture();
2364 	if (picture == NULL)
2365 		return false;
2366 
2367 	switch (code) {
2368 		case AS_LAYER_SET_ORIGIN:
2369 		{
2370 			float x, y;
2371 			link.Read<float>(&x);
2372 			link.Read<float>(&y);
2373 
2374 			picture->WriteSetOrigin(BPoint(x, y));
2375 			break;
2376 		}
2377 
2378 		case AS_LAYER_INVERT_RECT:
2379 		{
2380 			BRect rect;
2381 			link.Read<BRect>(&rect);
2382 			picture->WriteInvertRect(rect);
2383 
2384 			break;
2385 		}
2386 
2387 		case AS_LAYER_PUSH_STATE:
2388 		{
2389 			picture->WritePushState();
2390 			break;
2391 		}
2392 
2393 		case AS_LAYER_POP_STATE:
2394 		{
2395 			picture->WritePopState();
2396 			break;
2397 		}
2398 
2399 		case AS_LAYER_SET_DRAWING_MODE:
2400 		{
2401 			int8 drawingMode;
2402 			link.Read<int8>(&drawingMode);
2403 
2404 			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
2405 			break;
2406 		}
2407 
2408 		case AS_LAYER_SET_PEN_SIZE:
2409 		{
2410 			float penSize;
2411 			link.Read<float>(&penSize);
2412 			picture->WriteSetPenSize(penSize);
2413 			break;
2414 		}
2415 
2416 		case AS_LAYER_SET_LINE_MODE:
2417 		{
2418 			int8 lineCap, lineJoin;
2419 			float miterLimit;
2420 
2421 			link.Read<int8>(&lineCap);
2422 			link.Read<int8>(&lineJoin);
2423 			link.Read<float>(&miterLimit);
2424 
2425 			picture->WriteSetLineMode((cap_mode)lineCap, (join_mode)lineJoin, miterLimit);
2426 
2427 			break;
2428 		}
2429 		case AS_LAYER_SET_SCALE:
2430 		{
2431 			float scale;
2432 			link.Read<float>(&scale);
2433 			picture->WriteSetScale(scale);
2434 			break;
2435 		}
2436 
2437 		case AS_FILL_RECT:
2438 		case AS_STROKE_RECT:
2439 		{
2440 			BRect rect;
2441 			link.Read<BRect>(&rect);
2442 
2443 			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
2444 			break;
2445 		}
2446 
2447 		case AS_STROKE_ROUNDRECT:
2448 		case AS_FILL_ROUNDRECT:
2449 		{
2450 			BRect rect;
2451 			link.Read<BRect>(&rect);
2452 
2453 			BPoint radii;
2454 			link.Read<float>(&radii.x);
2455 			link.Read<float>(&radii.y);
2456 
2457 			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
2458 			break;
2459 		}
2460 
2461 		case AS_STROKE_ELLIPSE:
2462 		case AS_FILL_ELLIPSE:
2463 		{
2464 			BRect rect;
2465 			link.Read<BRect>(&rect);
2466 			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
2467 			break;
2468 		}
2469 
2470 		case AS_STROKE_ARC:
2471 		case AS_FILL_ARC:
2472 		{
2473 			BRect rect;
2474 			link.Read<BRect>(&rect);
2475 			float startTheta, arcTheta;
2476 			link.Read<float>(&startTheta);
2477 			link.Read<float>(&arcTheta);
2478 
2479 			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
2480 			BPoint center = rect.LeftTop() + radii;
2481 
2482 			picture->WriteDrawArc(center, radii, startTheta, arcTheta, code == AS_FILL_ARC);
2483 			break;
2484 		}
2485 
2486 		case AS_STROKE_LINE:
2487 		{
2488 			float x1, y1, x2, y2;
2489 
2490 			link.Read<float>(&x1);
2491 			link.Read<float>(&y1);
2492 			link.Read<float>(&x2);
2493 			link.Read<float>(&y2);
2494 
2495 			picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2));
2496 			break;
2497 		}
2498 
2499 		case AS_STROKE_LINEARRAY:
2500 		{
2501 			int32 lineCount;
2502 			link.Read<int32>(&lineCount);
2503 			if (lineCount <= 0)
2504 				break;
2505 
2506 			picture->WritePushState();
2507 
2508 			for (int32 i = 0; i < lineCount; i++) {
2509 				float x1, y1, x2, y2;
2510 				link.Read<float>(&x1);
2511 				link.Read<float>(&y1);
2512 				link.Read<float>(&x2);
2513 				link.Read<float>(&y2);
2514 
2515 				rgb_color color;
2516 				link.Read<rgb_color>(&color);
2517 
2518 				picture->WriteSetHighColor(color);
2519 				picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2));
2520 			}
2521 
2522 			picture->WritePopState();
2523 			break;
2524 		}
2525 
2526 		case AS_LAYER_SET_LOW_COLOR:
2527 		case AS_LAYER_SET_HIGH_COLOR:
2528 		{
2529 			rgb_color color;
2530 			link.Read(&color, sizeof(rgb_color));
2531 
2532 			if (code == AS_LAYER_SET_HIGH_COLOR)
2533 				picture->WriteSetHighColor(color);
2534 			else
2535 				picture->WriteSetLowColor(color);
2536 			break;
2537 		}
2538 
2539 		case AS_DRAW_STRING:
2540 		{
2541 			char* string = NULL;
2542 			int32 length;
2543 			BPoint location;
2544 			escapement_delta delta;
2545 
2546 			link.Read<int32>(&length);
2547 			link.Read<BPoint>(&location);
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 				const bool fill = (code == AS_FILL_SHAPE);
2575 				picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill);
2576 			}
2577 			delete[] opList;
2578 			delete[] ptList;
2579 
2580 			break;
2581 		}
2582 
2583 		case AS_LAYER_DRAW_BITMAP:
2584 		{
2585 			int32 token;
2586 			link.Read<int32>(&token);
2587 
2588 			BRect destRect;
2589 			link.Read<BRect>(&destRect);
2590 
2591 			BRect sourceRect;
2592 			link.Read<BRect>(&sourceRect);
2593 
2594 			ServerBitmap *bitmap = App()->FindBitmap(token);
2595 			if (bitmap == NULL)
2596 				break;
2597 
2598 			picture->WriteDrawBitmap(sourceRect, destRect, bitmap->Width(), bitmap->Height(),
2599 						bitmap->BytesPerRow(), bitmap->ColorSpace(), /*bitmap->Flags()*/0,
2600 						bitmap->Bits(), bitmap->BitsLength());
2601 
2602 			break;
2603 		}
2604 /*
2605 		case AS_LAYER_SET_BLENDING_MODE:
2606 		{
2607 			int8 srcAlpha, alphaFunc;
2608 
2609 			link.Read<int8>(&srcAlpha);
2610 			link.Read<int8>(&alphaFunc);
2611 
2612 			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
2613 			picture->AddInt16((int16)srcAlpha);
2614 			picture->AddInt16((int16)alphaFunc);
2615 			picture->EndOp();
2616 
2617 			break;
2618 		}*/
2619 		default:
2620 			return false;
2621 	}
2622 
2623 	if (link.NeedsReply()) {
2624 		fLink.StartMessage(B_ERROR);
2625 		fLink.Flush();
2626 	}
2627 	return true;
2628 }
2629 
2630 
2631 /*!
2632 	\brief Message-dispatching loop for the ServerWindow
2633 
2634 	Watches the ServerWindow's message port and dispatches as necessary
2635 */
2636 void
2637 ServerWindow::_MessageLooper()
2638 {
2639 	BPrivate::LinkReceiver& receiver = fLink.Receiver();
2640 	bool quitLoop = false;
2641 
2642 	while (!quitLoop) {
2643 		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
2644 		//	fMessagePort));
2645 
2646 		int32 code;
2647 		status_t status = receiver.GetNextMessage(code);
2648 		if (status < B_OK) {
2649 			// that shouldn't happen, it's our port
2650 			printf("Someone deleted our message port!\n");
2651 
2652 			// try to let our client die happily
2653 			NotifyQuitRequested();
2654 			break;
2655 		}
2656 
2657 #ifdef PROFILE_MESSAGE_LOOP
2658 		bigtime_t start = system_time();
2659 #endif
2660 
2661 		Lock();
2662 
2663 #ifdef PROFILE_MESSAGE_LOOP
2664 		bigtime_t diff = system_time() - start;
2665 		if (diff > 10000)
2666 			printf("ServerWindow %s: lock acquisition took %Ld usecs\n", Title(), diff);
2667 #endif
2668 
2669 		int32 messagesProcessed = 0;
2670 		bool lockedDesktop = false;
2671 
2672 		while (true) {
2673 			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
2674 				// this means the client has been killed
2675 				STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n",
2676 					Title()));
2677 
2678 				if (code == AS_DELETE_WINDOW) {
2679 					fLink.StartMessage(B_OK);
2680 					fLink.Flush();
2681 				}
2682 
2683 				if (lockedDesktop)
2684 					fDesktop->UnlockSingleWindow();
2685 
2686 				quitLoop = true;
2687 
2688 				// ServerWindow's destructor takes care of pulling this object off the desktop.
2689 				if (!fWindowLayer->IsHidden())
2690 					CRITICAL("ServerWindow: a window must be hidden before it's deleted\n");
2691 
2692 				break;
2693 			}
2694 
2695 			if (!lockedDesktop) {
2696 				// only lock it once
2697 				fDesktop->LockSingleWindow();
2698 				lockedDesktop = true;
2699 			}
2700 
2701 			if (atomic_and(&fRedrawRequested, 0) != 0) {
2702 #ifdef PROFILE_MESSAGE_LOOP
2703 				bigtime_t redrawStart = system_time();
2704 #endif
2705 				fWindowLayer->RedrawDirtyRegion();
2706 #ifdef PROFILE_MESSAGE_LOOP
2707 				diff = system_time() - redrawStart;
2708 				atomic_add(&sRedrawProcessingTime.count, 1);
2709 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2710 				atomic_add64(&sRedrawProcessingTime.time, diff);
2711 # else
2712 				sRedrawProcessingTime.time += diff;
2713 # endif
2714 #endif
2715 			}
2716 
2717 
2718 
2719 #ifdef PROFILE_MESSAGE_LOOP
2720 			bigtime_t dispatchStart = system_time();
2721 #endif
2722 			_DispatchMessage(code, receiver);
2723 
2724 #ifdef PROFILE_MESSAGE_LOOP
2725 			if (code >= 0 && code < AS_LAST_CODE) {
2726 				diff = system_time() - dispatchStart;
2727 				atomic_add(&sMessageProfile[code].count, 1);
2728 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2729 				atomic_add64(&sMessageProfile[code].time, diff);
2730 #else
2731 				sMessageProfile[code].time += diff;
2732 #endif
2733 				if (diff > 10000)
2734 					printf("ServerWindow %s: message %ld took %Ld usecs\n", Title(), code, diff);
2735 			}
2736 #endif
2737 
2738 			// only process up to 70 waiting messages at once (we have the Desktop locked)
2739 			if (!receiver.HasMessages() || ++messagesProcessed > 70) {
2740 				fDesktop->UnlockSingleWindow();
2741 				break;
2742 			}
2743 
2744 			// next message
2745 			status_t status = receiver.GetNextMessage(code);
2746 			if (status < B_OK) {
2747 				// that shouldn't happen, it's our port
2748 				printf("Someone deleted our message port!\n");
2749 				fDesktop->UnlockSingleWindow();
2750 
2751 				// try to let our client die happily
2752 				NotifyQuitRequested();
2753 				break;
2754 			}
2755 		}
2756 
2757 		Unlock();
2758 	}
2759 
2760 	// we were asked to quit the message loop - either on request or because of an error
2761 	Quit();
2762 		// does not return
2763 }
2764 
2765 
2766 status_t
2767 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
2768 {
2769 	if (target == B_NULL_TOKEN)
2770 		target = fClientToken;
2771 
2772 	BMessenger reply;
2773 	BMessage::Private messagePrivate((BMessage *)msg);
2774 	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
2775 		0, false, reply);
2776 }
2777 
2778 
2779 WindowLayer*
2780 ServerWindow::MakeWindowLayer(BRect frame, const char* name,
2781 	window_look look, window_feel feel, uint32 flags, uint32 workspace)
2782 {
2783 	// The non-offscreen ServerWindow uses the DrawingEngine instance from the desktop.
2784 	return new (nothrow) WindowLayer(frame, name, look, feel, flags,
2785 //		workspace, this, fDesktop->GetDrawingEngine());
2786 		workspace, this, new DrawingEngine(fDesktop->HWInterface()));
2787 }
2788 
2789 
2790 status_t
2791 ServerWindow::_EnableDirectWindowMode()
2792 {
2793 	if (fDirectWindowData != NULL) {
2794 		// already in direct window mode
2795 		return B_ERROR;
2796 	}
2797 
2798 	fDirectWindowData = new (nothrow) direct_window_data;
2799 	if (fDirectWindowData == NULL)
2800 		return B_NO_MEMORY;
2801 
2802 	status_t status = fDirectWindowData->InitCheck();
2803 	if (status < B_OK) {
2804 		delete fDirectWindowData;
2805 		fDirectWindowData = NULL;
2806 
2807 		return status;
2808 	}
2809 
2810 	return B_OK;
2811 }
2812 
2813 
2814 void
2815 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
2816 {
2817 	STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n",
2818 		bufferState, driverState));
2819 
2820 	if (fDirectWindowData == NULL
2821 		|| (!fDirectWindowData->started
2822 			&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START))
2823 		return;
2824 
2825 	// If the direct connection is stopped, only continue if a start notification is received.
2826 	// But save the "reason" of the call (B_BUFFER_RESIZED, B_CLIPPING_MODIFIED, etc)
2827 	if ((fDirectWindowData->buffer_info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP
2828 		&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START) {
2829 		fDirectWindowData->next_buffer_state |= bufferState & ~B_DIRECT_MODE_MASK;
2830 		return;
2831 	}
2832 
2833 	fDirectWindowData->started = true;
2834 
2835 	fDirectWindowData->buffer_info->buffer_state =
2836 		(direct_buffer_state)(bufferState | fDirectWindowData->next_buffer_state);
2837 	fDirectWindowData->next_buffer_state = 0;
2838 
2839 	if (driverState != -1)
2840 		fDirectWindowData->buffer_info->driver_state = (direct_driver_state)driverState;
2841 
2842 	if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) {
2843 		// TODO: Locking ?
2844 		RenderingBuffer *buffer = fDesktop->HWInterface()->FrontBuffer();
2845 		fDirectWindowData->buffer_info->bits = buffer->Bits();
2846 		fDirectWindowData->buffer_info->pci_bits = NULL; // TODO
2847 		fDirectWindowData->buffer_info->bytes_per_row = buffer->BytesPerRow();
2848 		switch (buffer->ColorSpace()) {
2849 			case B_RGB32:
2850 			case B_RGBA32:
2851 			case B_RGB32_BIG:
2852 			case B_RGBA32_BIG:
2853 				fDirectWindowData->buffer_info->bits_per_pixel = 32;
2854 				break;
2855 			case B_RGB24:
2856 			case B_RGB24_BIG:
2857 				fDirectWindowData->buffer_info->bits_per_pixel = 24;
2858 				break;
2859 			case B_RGB16:
2860 			case B_RGB16_BIG:
2861 			case B_RGB15:
2862 			case B_RGB15_BIG:
2863 				fDirectWindowData->buffer_info->bits_per_pixel = 16;
2864 				break;
2865 			case B_CMAP8:
2866 				fDirectWindowData->buffer_info->bits_per_pixel = 8;
2867 				break;
2868 			default:
2869 				fprintf(stderr, "unkown colorspace in HandleDirectConnection()!\n");
2870 				fDirectWindowData->buffer_info->bits_per_pixel = 0;
2871 				break;
2872 		}
2873 		fDirectWindowData->buffer_info->pixel_format = buffer->ColorSpace();
2874 		fDirectWindowData->buffer_info->layout = B_BUFFER_NONINTERLEAVED;
2875 		fDirectWindowData->buffer_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO
2876 		fDirectWindowData->buffer_info->window_bounds = to_clipping_rect(fWindowLayer->Frame());
2877 
2878 		// TODO: Review this
2879 		const int32 kMaxClipRectsCount = (B_PAGE_SIZE - sizeof(direct_buffer_info))
2880 			/ sizeof(clipping_rect);
2881 
2882 		// We just want the region inside the window, border excluded.
2883 		BRegion clipRegion = fWindowLayer->VisibleContentRegion();
2884 
2885 		fDirectWindowData->buffer_info->clip_list_count = min_c(clipRegion.CountRects(),
2886 			kMaxClipRectsCount);
2887 		fDirectWindowData->buffer_info->clip_bounds = clipRegion.FrameInt();
2888 
2889 		for (uint32 i = 0; i < fDirectWindowData->buffer_info->clip_list_count; i++)
2890 			fDirectWindowData->buffer_info->clip_list[i] = clipRegion.RectAtInt(i);
2891 	}
2892 
2893 	// Releasing this sem causes the client to call BDirectWindow::DirectConnected()
2894 	release_sem(fDirectWindowData->sem);
2895 
2896 	// TODO: Waiting half a second in the ServerWindow thread is not a problem,
2897 	// but since we are called from the Desktop's thread too, very bad things could happen.
2898 	// Find some way to call this method only within ServerWindow's thread (messaging ?)
2899 	status_t status;
2900 	do {
2901 		// TODO: The timeout is 3000000 usecs (3 seconds) on beos.
2902 		// Test, but I think half a second is enough.
2903 		status = acquire_sem_etc(fDirectWindowData->sem_ack, 1, B_TIMEOUT, 500000);
2904 	} while (status == B_INTERRUPTED);
2905 
2906 	if (status < B_OK) {
2907 		// The client application didn't release the semaphore
2908 		// within the given timeout. Or something else went wrong.
2909 		// Deleting this member should make it crash.
2910 		delete fDirectWindowData;
2911 		fDirectWindowData = NULL;
2912 	}
2913 }
2914 
2915 
2916 void
2917 ServerWindow::_SetCurrentLayer(ViewLayer* layer)
2918 {
2919 	if (fCurrentLayer == layer)
2920 		return;
2921 
2922 	fCurrentLayer = layer;
2923 	fCurrentDrawingRegionValid = false;
2924 	_UpdateDrawState(fCurrentLayer);
2925 
2926 #if 0
2927 #if DELAYED_BACKGROUND_CLEARING
2928 	if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty()
2929 		&& fWindowLayer->InUpdate()) {
2930 		DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2931 		if (drawingEngine->LockParallelAccess()) {
2932 
2933 			fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
2934 			fCurrentDrawingRegionValid = true;
2935 			BRegion dirty(fCurrentDrawingRegion);
2936 
2937 			BRegion content;
2938 			fWindowLayer->GetContentRegion(&content);
2939 
2940 			fCurrentLayer->Draw(drawingEngine, &dirty, &content, false);
2941 
2942 			drawingEngine->UnlockParallelAccess();
2943 		}
2944 	}
2945 #endif
2946 #endif // 0
2947 }
2948 
2949 
2950 void
2951 ServerWindow::_UpdateDrawState(ViewLayer* layer)
2952 {
2953 	// switch the drawing state
2954 	// TODO: is it possible to scroll a view while it
2955 	// is being drawn? probably not... otherwise the
2956 	// "offsets" passed below would need to be updated again
2957 	DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2958 	if (layer && drawingEngine) {
2959 		IntPoint p = layer->ScrollingOffset();
2960 		p += IntPoint(layer->CurrentState()->Origin());
2961 		drawingEngine->SetDrawState(layer->CurrentState(), p.x, p.y);
2962 	}
2963 }
2964 
2965 
2966 status_t
2967 ServerWindow::PictureToRegion(ServerPicture *picture, BRegion &region,
2968 	bool inverse, BPoint where)
2969 {
2970 	fprintf(stderr, "ServerWindow::PictureToRegion() not implemented\n");
2971 	region.MakeEmpty();
2972 	return B_ERROR;
2973 }
2974