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