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