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