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