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