headers/bsd: Add sys/queue.h.
[haiku.git] / src / servers / app / ServerWindow.cpp
blob6d4a880c670a0209d628f5c29c98d76df7cfc3b7
1 /*
2 * Copyright 2001-2015, Haiku.
3 * Distributed under the terms of the MIT License.
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 * Brecht Machiels <brecht@mos6581.org>
14 * Julian Harnath <julian.harnath@rwth-aachen.de>
15 * Joseph Groover <looncraz@looncraz.net>
19 /*! \class ServerWindow
21 The ServerWindow class handles all BWindow messaging; it forwards all
22 BWindow requests to the corresponding app_server classes, that is Desktop,
23 Window, and View.
24 Furthermore, it also sends app_server requests/notices to its BWindow. There
25 is one ServerWindow per BWindow.
29 #include "ServerWindow.h"
31 #include <syslog.h>
32 #include <new>
34 #include <AppDefs.h>
35 #include <Autolock.h>
36 #include <Debug.h>
37 #include <DirectWindow.h>
38 #include <TokenSpace.h>
39 #include <View.h>
40 #include <GradientLinear.h>
41 #include <GradientRadial.h>
42 #include <GradientRadialFocus.h>
43 #include <GradientDiamond.h>
44 #include <GradientConic.h>
46 #include <MessagePrivate.h>
47 #include <PortLink.h>
48 #include <ShapePrivate.h>
49 #include <ServerProtocolStructs.h>
50 #include <ViewPrivate.h>
51 #include <WindowInfo.h>
52 #include <WindowPrivate.h>
54 #include "clipping.h"
55 #include "utf8_functions.h"
57 #include "AlphaMask.h"
58 #include "AppServer.h"
59 #include "AutoDeleter.h"
60 #include "BBitmapBuffer.h"
61 #include "BitmapManager.h"
62 #include "Desktop.h"
63 #include "DirectWindowInfo.h"
64 #include "DrawingEngine.h"
65 #include "DrawState.h"
66 #include "HWInterface.h"
67 #include "Layer.h"
68 #include "Overlay.h"
69 #include "ProfileMessageSupport.h"
70 #include "RenderingBuffer.h"
71 #include "ServerApp.h"
72 #include "ServerBitmap.h"
73 #include "ServerPicture.h"
74 #include "ServerProtocol.h"
75 #include "Window.h"
76 #include "WorkspacesView.h"
79 using std::nothrow;
82 //#define TRACE_SERVER_WINDOW
83 #ifdef TRACE_SERVER_WINDOW
84 # include <stdio.h>
85 # define STRACE(x) debug_printf x
86 #else
87 # define STRACE(x) ;
88 #endif
90 //#define TRACE_SERVER_WINDOW_MESSAGES
91 #ifdef TRACE_SERVER_WINDOW_MESSAGES
92 # include <stdio.h>
93 static const char* kDrawingModeMap[] = {
94 "B_OP_COPY",
95 "B_OP_OVER",
96 "B_OP_ERASE",
97 "B_OP_INVERT",
98 "B_OP_ADD",
99 "B_OP_SUBTRACT",
100 "B_OP_BLEND",
101 "B_OP_MIN",
102 "B_OP_MAX",
103 "B_OP_SELECT",
104 "B_OP_ALPHA",
106 "fix kDrawingModeMap",
107 "fix kDrawingModeMap",
108 "fix kDrawingModeMap",
109 "fix kDrawingModeMap",
110 "fix kDrawingModeMap",
112 # define DTRACE(x) debug_printf x
113 #else
114 # define DTRACE(x) ;
115 #endif
117 //#define TRACE_SERVER_GRADIENTS
118 #ifdef TRACE_SERVER_GRADIENTS
119 # include <OS.h>
120 # define GTRACE(x) debug_printf x
121 #else
122 # define GTRACE(x) ;
123 #endif
125 //#define PROFILE_MESSAGE_LOOP
126 #ifdef PROFILE_MESSAGE_LOOP
127 struct profile { int32 code; int32 count; bigtime_t time; };
128 static profile sMessageProfile[AS_LAST_CODE];
129 static profile sRedrawProcessingTime;
130 //static profile sNextMessageTime;
131 #endif
134 // #pragma mark -
137 #ifdef PROFILE_MESSAGE_LOOP
138 static int
139 compare_message_profiles(const void* _a, const void* _b)
141 profile* a = (profile*)*(void**)_a;
142 profile* b = (profile*)*(void**)_b;
143 if (a->time < b->time)
144 return 1;
145 if (a->time > b->time)
146 return -1;
147 return 0;
149 #endif
152 // #pragma mark -
155 /*! Sets up the basic BWindow counterpart - you have to call Init() before
156 you can actually use it, though.
158 ServerWindow::ServerWindow(const char* title, ServerApp* app,
159 port_id clientPort, port_id looperPort, int32 clientToken)
161 MessageLooper(title && *title ? title : "Unnamed Window"),
162 fTitle(NULL),
163 fDesktop(app->GetDesktop()),
164 fServerApp(app),
165 fWindow(NULL),
166 fWindowAddedToDesktop(false),
168 fClientTeam(app->ClientTeam()),
170 fMessagePort(-1),
171 fClientReplyPort(clientPort),
172 fClientLooperPort(looperPort),
174 fClientToken(clientToken),
176 fCurrentView(NULL),
177 fCurrentDrawingRegion(),
178 fCurrentDrawingRegionValid(false),
180 fDirectWindowInfo(NULL),
181 fIsDirectlyAccessing(false)
183 STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
185 SetTitle(title);
186 fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
188 BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
189 looperPort, B_PREFERRED_TOKEN);
190 BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
191 looperPort, clientToken);
193 fEventTarget.SetTo(fFocusMessenger);
195 fDeathSemaphore = create_sem(0, "window death");
199 /*! Tears down all connections the main app_server objects, and deletes some
200 internals.
202 ServerWindow::~ServerWindow()
204 STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
206 if (!fWindow->IsOffscreenWindow()) {
207 fWindowAddedToDesktop = false;
208 fDesktop->RemoveWindow(fWindow);
211 if (App() != NULL) {
212 App()->RemoveWindow(this);
213 fServerApp = NULL;
216 delete fWindow;
218 free(fTitle);
219 delete_port(fMessagePort);
221 BPrivate::gDefaultTokens.RemoveToken(fServerToken);
223 delete fDirectWindowInfo;
224 STRACE(("ServerWindow(%p) will exit NOW\n", this));
226 delete_sem(fDeathSemaphore);
228 #ifdef PROFILE_MESSAGE_LOOP
229 BList profiles;
230 for (int32 i = 0; i < AS_LAST_CODE; i++) {
231 if (sMessageProfile[i].count == 0)
232 continue;
233 sMessageProfile[i].code = i;
234 profiles.AddItem(&sMessageProfile[i]);
237 profiles.SortItems(compare_message_profiles);
239 BString codeName;
240 int32 count = profiles.CountItems();
241 for (int32 i = 0; i < count; i++) {
242 profile* p = (profile*)profiles.ItemAtFast(i);
243 string_for_message_code(p->code, codeName);
244 printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
245 "per call)\n", codeName.String(), p->count, p->time / 1000000.0,
246 p->time / p->count);
248 if (sRedrawProcessingTime.count > 0) {
249 printf("average redraw processing time: %g secs, count: %" B_PRId32 " "
250 "(%" B_PRId64 " usecs per call)\n",
251 sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
252 sRedrawProcessingTime.time / sRedrawProcessingTime.count);
254 // if (sNextMessageTime.count > 0) {
255 // printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
256 // sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
257 // sNextMessageTime.time / sNextMessageTime.count);
258 // }
259 #endif
263 status_t
264 ServerWindow::Init(BRect frame, window_look look, window_feel feel,
265 uint32 flags, uint32 workspace)
267 if (!App()->AddWindow(this)) {
268 fServerApp = NULL;
269 return B_NO_MEMORY;
272 if (fTitle == NULL)
273 return B_NO_MEMORY;
275 // fMessagePort is the port to which the app sends messages for the server
276 fMessagePort = create_port(100, fTitle);
277 if (fMessagePort < B_OK)
278 return fMessagePort;
280 fLink.SetSenderPort(fClientReplyPort);
281 fLink.SetReceiverPort(fMessagePort);
283 // We cannot call MakeWindow in the constructor, since it
284 // is a virtual function!
285 fWindow = MakeWindow(frame, fTitle, look, feel, flags, workspace);
286 if (!fWindow || fWindow->InitCheck() != B_OK) {
287 delete fWindow;
288 fWindow = NULL;
289 return B_NO_MEMORY;
292 if (!fWindow->IsOffscreenWindow()) {
293 fDesktop->AddWindow(fWindow);
294 fWindowAddedToDesktop = true;
297 return B_OK;
301 /*! Returns the ServerWindow's Window, if it exists and has been
302 added to the Desktop already.
303 In other words, you cannot assume this method will always give you
304 a valid pointer.
306 Window*
307 ServerWindow::Window() const
309 if (!fWindowAddedToDesktop)
310 return NULL;
312 return fWindow;
316 void
317 ServerWindow::_PrepareQuit()
319 if (fThread == find_thread(NULL)) {
320 // make sure we're hidden
321 fDesktop->LockSingleWindow();
322 _Hide();
323 fDesktop->UnlockSingleWindow();
324 } else if (fThread >= B_OK)
325 PostMessage(AS_INTERNAL_HIDE_WINDOW);
329 void
330 ServerWindow::_GetLooperName(char* name, size_t length)
332 const char *title = Title();
333 if (title == NULL || !title[0])
334 title = "Unnamed Window";
336 snprintf(name, length, "w:%" B_PRId32 ":%s", ClientTeam(), title);
340 /*! Shows the window's Window.
342 void
343 ServerWindow::_Show()
345 // NOTE: if you do something else, other than sending a port message, PLEASE lock
346 STRACE(("ServerWindow %s: _Show\n", Title()));
348 if (fQuitting || fWindow->IsMinimized() || !fWindow->IsHidden()
349 || fWindow->IsOffscreenWindow() || fWindow->TopView() == NULL)
350 return;
352 // TODO: Maybe we need to dispatch a message to the desktop to show/hide us
353 // instead of doing it from this thread.
354 fDesktop->UnlockSingleWindow();
355 fDesktop->ShowWindow(fWindow);
356 if (fDirectWindowInfo && fDirectWindowInfo->IsFullScreen())
357 _ResizeToFullScreen();
359 fDesktop->LockSingleWindow();
363 /*! Hides the window's Window. You need to have all windows locked when
364 calling this function.
366 void
367 ServerWindow::_Hide()
369 STRACE(("ServerWindow %s: _Hide\n", Title()));
371 if (fWindow->IsHidden() || fWindow->IsOffscreenWindow())
372 return;
374 fDesktop->UnlockSingleWindow();
375 fDesktop->HideWindow(fWindow);
376 fDesktop->LockSingleWindow();
380 void
381 ServerWindow::RequestRedraw()
383 PostMessage(AS_REDRAW, 0);
384 // we don't care if this fails - it's only a notification, and if
385 // it fails, there are obviously enough messages in the queue
386 // already
388 atomic_add(&fRedrawRequested, 1);
392 void
393 ServerWindow::SetTitle(const char* newTitle)
395 char* oldTitle = fTitle;
397 if (newTitle == NULL)
398 newTitle = "";
400 fTitle = strdup(newTitle);
401 if (fTitle == NULL) {
402 // out of memory condition
403 fTitle = oldTitle;
404 return;
407 free(oldTitle);
409 if (Thread() >= B_OK) {
410 char name[B_OS_NAME_LENGTH];
411 _GetLooperName(name, sizeof(name));
412 rename_thread(Thread(), name);
415 if (fWindow != NULL)
416 fDesktop->SetWindowTitle(fWindow, newTitle);
420 //! Requests that the ServerWindow's BWindow quit
421 void
422 ServerWindow::NotifyQuitRequested()
424 // NOTE: if you do something else, other than sending a port message,
425 // PLEASE lock
426 STRACE(("ServerWindow %s: Quit\n", fTitle));
428 BMessage msg(B_QUIT_REQUESTED);
429 SendMessageToClient(&msg);
433 void
434 ServerWindow::NotifyMinimize(bool minimize)
436 if (fWindow->Feel() != B_NORMAL_WINDOW_FEEL)
437 return;
439 // The client is responsible for the actual minimization
441 BMessage msg(B_MINIMIZE);
442 msg.AddInt64("when", real_time_clock_usecs());
443 msg.AddBool("minimize", minimize);
445 SendMessageToClient(&msg);
449 //! Sends a message to the client to perform a Zoom
450 void
451 ServerWindow::NotifyZoom()
453 // NOTE: if you do something else, other than sending a port message,
454 // PLEASE lock
455 BMessage msg(B_ZOOM);
456 SendMessageToClient(&msg);
460 void
461 ServerWindow::GetInfo(window_info& info)
463 info.team = ClientTeam();
464 info.server_token = ServerToken();
466 info.thread = Thread();
467 info.client_token = ClientToken();
468 info.client_port = fClientLooperPort;
469 info.workspaces = fWindow->Workspaces();
471 // logic taken from Switcher comments and experiments
472 if (fWindow->IsHidden())
473 info.layer = 0;
474 else if (fWindow->IsVisible()) {
475 if (fWindow->Feel() == kDesktopWindowFeel)
476 info.layer = 2;
477 else if (fWindow->IsFloating() || fWindow->IsModal())
478 info.layer = 4;
479 else
480 info.layer = 3;
481 } else
482 info.layer = 1;
484 info.feel = fWindow->Feel();
485 info.flags = fWindow->Flags();
486 info.window_left = (int)floor(fWindow->Frame().left);
487 info.window_top = (int)floor(fWindow->Frame().top);
488 info.window_right = (int)floor(fWindow->Frame().right);
489 info.window_bottom = (int)floor(fWindow->Frame().bottom);
491 info.show_hide_level = fWindow->ShowLevel();
492 info.is_mini = fWindow->IsMinimized();
496 void
497 ServerWindow::ResyncDrawState()
499 _UpdateDrawState(fCurrentView);
503 View*
504 ServerWindow::_CreateView(BPrivate::LinkReceiver& link, View** _parent)
506 // NOTE: no need to check for a lock. This is a private method.
508 int32 token;
509 BRect frame;
510 uint32 resizeMask;
511 uint32 eventMask;
512 uint32 eventOptions;
513 uint32 flags;
514 bool hidden;
515 int32 parentToken;
516 char* name = NULL;
517 rgb_color viewColor;
518 BPoint scrollingOffset;
520 link.Read<int32>(&token);
521 link.ReadString(&name);
522 link.Read<BRect>(&frame);
523 link.Read<BPoint>(&scrollingOffset);
524 link.Read<uint32>(&resizeMask);
525 link.Read<uint32>(&eventMask);
526 link.Read<uint32>(&eventOptions);
527 link.Read<uint32>(&flags);
528 link.Read<bool>(&hidden);
529 link.Read<rgb_color>(&viewColor);
530 link.Read<int32>(&parentToken);
532 STRACE(("ServerWindow(%s)::_CreateView()-> view %s, token %" B_PRId32 "\n",
533 fTitle, name, token));
535 View* newView;
537 if ((flags & kWorkspacesViewFlag) != 0) {
538 newView = new (nothrow) WorkspacesView(frame, scrollingOffset, name,
539 token, resizeMask, flags);
540 } else {
541 newView = new (nothrow) View(frame, scrollingOffset, name, token,
542 resizeMask, flags);
545 free(name);
547 if (newView == NULL)
548 return NULL;
550 if (newView->InitCheck() != B_OK) {
551 delete newView;
552 return NULL;
555 // there is no way of setting this, other than manually :-)
556 newView->SetViewColor(viewColor);
557 newView->SetHidden(hidden);
558 newView->SetEventMask(eventMask, eventOptions);
560 if (eventMask != 0 || eventOptions != 0) {
561 // fDesktop->UnlockSingleWindow();
562 // fDesktop->LockAllWindows();
563 fDesktop->UnlockAllWindows();
564 // TODO: possible deadlock
565 fDesktop->EventDispatcher().AddListener(EventTarget(),
566 newView->Token(), eventMask, eventOptions);
567 fDesktop->LockAllWindows();
568 // fDesktop->UnlockAllWindows();
569 // fDesktop->LockSingleWindow();
572 // Initialize the view with the current application plain font.
573 // NOTE: This might be out of sync with the global app_server plain
574 // font, but that is so on purpose! The client needs to resync itself
575 // with the app_server fonts upon notification, but if we just use
576 // the current font here, the be_plain_font on the client may still
577 // hold old values. So this needs to be an update initiated by the
578 // client application.
579 newView->CurrentState()->SetFont(App()->PlainFont());
581 if (_parent) {
582 View *parent;
583 if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
584 (void**)&parent) != B_OK
585 || parent->Window()->ServerWindow() != this) {
586 debug_printf("View token not found!\n");
587 parent = NULL;
590 *_parent = parent;
593 return newView;
597 /*! Dispatches all window messages, and those view messages that
598 don't need a valid fCurrentView (ie. view creation).
600 void
601 ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
603 switch (code) {
604 case AS_SHOW_OR_HIDE_WINDOW:
606 int32 showLevel;
607 if (link.Read<int32>(&showLevel) == B_OK) {
608 DTRACE(("ServerWindow %s: Message AS_SHOW_OR_HIDE_WINDOW, "
609 "show level: %" B_PRId32 "\n", Title(), showLevel));
611 fWindow->SetShowLevel(showLevel);
612 if (showLevel <= 0)
613 _Show();
614 else
615 _Hide();
617 break;
619 // Only for internal use within this class
620 case AS_INTERNAL_HIDE_WINDOW:
621 _Hide();
622 break;
623 case AS_MINIMIZE_WINDOW:
625 bool minimize;
626 if (link.Read<bool>(&minimize) == B_OK) {
627 DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW, "
628 "minimize: %d\n", Title(), minimize));
630 fDesktop->UnlockSingleWindow();
631 fDesktop->MinimizeWindow(fWindow, minimize);
632 fDesktop->LockSingleWindow();
634 break;
637 case AS_ACTIVATE_WINDOW:
639 bool activate = true;
640 if (link.Read<bool>(&activate) != B_OK)
641 break;
643 DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: activate: "
644 "%d\n", Title(), activate));
646 fDesktop->UnlockSingleWindow();
648 if (activate)
649 fDesktop->SelectWindow(fWindow);
650 else
651 fDesktop->SendWindowBehind(fWindow, NULL);
653 fDesktop->LockSingleWindow();
654 break;
656 case AS_SEND_BEHIND:
658 // Has the all-window lock
659 int32 token;
660 team_id teamID;
661 status_t status = B_ERROR;
663 link.Read<int32>(&token);
664 if (link.Read<team_id>(&teamID) == B_OK) {
665 ::Window* behindOf = fDesktop->FindWindowByClientToken(token,
666 teamID);
668 DTRACE(("ServerWindow %s: Message AS_SEND_BEHIND %s\n",
669 Title(), behindOf != NULL ? behindOf->Title() : "NULL"));
671 if (behindOf != NULL || token == -1) {
672 fDesktop->SendWindowBehind(fWindow, behindOf);
673 status = B_OK;
674 } else
675 status = B_NAME_NOT_FOUND;
678 fLink.StartMessage(status);
679 fLink.Flush();
680 break;
683 case B_QUIT_REQUESTED:
684 DTRACE(("ServerWindow %s received quit request\n", Title()));
685 NotifyQuitRequested();
686 break;
688 case AS_ENABLE_UPDATES:
689 DTRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES\n", Title()));
690 fWindow->EnableUpdateRequests();
691 break;
693 case AS_DISABLE_UPDATES:
694 DTRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES\n", Title()));
695 fWindow->DisableUpdateRequests();
696 break;
698 case AS_NEEDS_UPDATE:
699 DTRACE(("ServerWindow %s: Message AS_NEEDS_UPDATE: %d\n",
700 Title(), fWindow->NeedsUpdate()));
701 if (fWindow->NeedsUpdate())
702 fLink.StartMessage(B_OK);
703 else
704 fLink.StartMessage(B_ERROR);
705 fLink.Flush();
706 break;
708 case AS_SET_WINDOW_TITLE:
710 char* newTitle;
711 if (link.ReadString(&newTitle) == B_OK) {
712 DTRACE(("ServerWindow %s: Message AS_SET_WINDOW_TITLE: %s\n",
713 Title(), newTitle));
715 SetTitle(newTitle);
716 free(newTitle);
718 break;
721 case AS_ADD_TO_SUBSET:
723 // Has the all-window lock
724 DTRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n", Title()));
725 status_t status = B_ERROR;
727 int32 token;
728 if (link.Read<int32>(&token) == B_OK) {
729 ::Window* window = fDesktop->FindWindowByClientToken(token,
730 App()->ClientTeam());
731 if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL) {
732 status = B_BAD_VALUE;
733 } else {
734 status = fDesktop->AddWindowToSubset(fWindow, window)
735 ? B_OK : B_NO_MEMORY;
739 fLink.StartMessage(status);
740 fLink.Flush();
741 break;
743 case AS_REMOVE_FROM_SUBSET:
745 // Has the all-window lock
746 DTRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n", Title()));
747 status_t status = B_ERROR;
749 int32 token;
750 if (link.Read<int32>(&token) == B_OK) {
751 ::Window* window = fDesktop->FindWindowByClientToken(token,
752 App()->ClientTeam());
753 if (window != NULL) {
754 fDesktop->RemoveWindowFromSubset(fWindow, window);
755 status = B_OK;
756 } else
757 status = B_BAD_VALUE;
760 fLink.StartMessage(status);
761 fLink.Flush();
762 break;
765 case AS_SET_LOOK:
767 // Has the all-window look
768 DTRACE(("ServerWindow %s: Message AS_SET_LOOK\n", Title()));
770 status_t status = B_ERROR;
771 int32 look;
772 if (link.Read<int32>(&look) == B_OK) {
773 // test if look is valid
774 status = Window::IsValidLook((window_look)look)
775 ? B_OK : B_BAD_VALUE;
778 if (status == B_OK && !fWindow->IsOffscreenWindow())
779 fDesktop->SetWindowLook(fWindow, (window_look)look);
781 fLink.StartMessage(status);
782 fLink.Flush();
783 break;
785 case AS_SET_FEEL:
787 // Has the all-window look
788 DTRACE(("ServerWindow %s: Message AS_SET_FEEL\n", Title()));
790 status_t status = B_ERROR;
791 int32 feel;
792 if (link.Read<int32>(&feel) == B_OK) {
793 // test if feel is valid
794 status = Window::IsValidFeel((window_feel)feel)
795 ? B_OK : B_BAD_VALUE;
798 if (status == B_OK && !fWindow->IsOffscreenWindow())
799 fDesktop->SetWindowFeel(fWindow, (window_feel)feel);
801 fLink.StartMessage(status);
802 fLink.Flush();
803 break;
805 case AS_SET_FLAGS:
807 // Has the all-window look
808 DTRACE(("ServerWindow %s: Message AS_SET_FLAGS\n", Title()));
810 status_t status = B_ERROR;
811 uint32 flags;
812 if (link.Read<uint32>(&flags) == B_OK) {
813 // test if flags are valid
814 status = (flags & ~Window::ValidWindowFlags()) == 0
815 ? B_OK : B_BAD_VALUE;
818 if (status == B_OK && !fWindow->IsOffscreenWindow())
819 fDesktop->SetWindowFlags(fWindow, flags);
821 fLink.StartMessage(status);
822 fLink.Flush();
823 break;
825 #if 0
826 case AS_SET_ALIGNMENT:
828 // TODO: Implement AS_SET_ALIGNMENT
829 DTRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n",
830 Title()));
831 break;
833 case AS_GET_ALIGNMENT:
835 // TODO: Implement AS_GET_ALIGNMENT
836 DTRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n",
837 Title()));
838 break;
840 #endif
841 case AS_IS_FRONT_WINDOW:
843 bool isFront = fDesktop->FrontWindow() == fWindow;
844 DTRACE(("ServerWindow %s: Message AS_IS_FRONT_WINDOW: %d\n",
845 Title(), isFront));
846 fLink.StartMessage(isFront ? B_OK : B_ERROR);
847 fLink.Flush();
848 break;
851 case AS_GET_WORKSPACES:
853 DTRACE(("ServerWindow %s: Message AS_GET_WORKSPACES\n", Title()));
854 fLink.StartMessage(B_OK);
855 fLink.Attach<uint32>(fWindow->Workspaces());
856 fLink.Flush();
857 break;
859 case AS_SET_WORKSPACES:
861 // Has the all-window lock (but would actually not need to lock at
862 // all)
863 uint32 newWorkspaces;
864 if (link.Read<uint32>(&newWorkspaces) != B_OK)
865 break;
867 DTRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %" B_PRIx32 "\n",
868 Title(), newWorkspaces));
870 fDesktop->SetWindowWorkspaces(fWindow, newWorkspaces);
871 break;
873 case AS_WINDOW_RESIZE:
875 // Has the all-window look
876 float xResizeTo;
877 float yResizeTo;
878 link.Read<float>(&xResizeTo);
879 if (link.Read<float>(&yResizeTo) != B_OK)
880 break;
882 DTRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
883 Title(), xResizeTo, yResizeTo));
885 // comment this code for the time being, as some apps rely
886 // on the programmatically resize behavior during user resize
887 // if (fWindow->IsResizing()) {
888 // While the user resizes the window, we ignore
889 // pragmatically set window bounds
890 // fLink.StartMessage(B_BUSY);
891 // } else {
892 fDesktop->ResizeWindowBy(fWindow,
893 xResizeTo - fWindow->Frame().Width(),
894 yResizeTo - fWindow->Frame().Height());
895 fLink.StartMessage(B_OK);
896 // }
897 fLink.Flush();
898 break;
900 case AS_WINDOW_MOVE:
902 // Has the all-window look
903 float xMoveTo;
904 float yMoveTo;
905 link.Read<float>(&xMoveTo);
906 if (link.Read<float>(&yMoveTo) != B_OK)
907 break;
909 DTRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
910 Title(), xMoveTo, yMoveTo));
912 if (fWindow->IsDragging()) {
913 // While the user moves the window, we ignore
914 // pragmatically set window positions
915 fLink.StartMessage(B_BUSY);
916 } else {
917 fDesktop->MoveWindowBy(fWindow, xMoveTo - fWindow->Frame().left,
918 yMoveTo - fWindow->Frame().top);
919 fLink.StartMessage(B_OK);
921 fLink.Flush();
922 break;
924 case AS_SET_SIZE_LIMITS:
926 // Has the all-window look
928 // Attached Data:
929 // 1) float minimum width
930 // 2) float maximum width
931 // 3) float minimum height
932 // 4) float maximum height
934 // TODO: for now, move the client to int32 as well!
935 int32 minWidth, maxWidth, minHeight, maxHeight;
936 float value;
937 link.Read<float>(&value); minWidth = (int32)value;
938 link.Read<float>(&value); maxWidth = (int32)value;
939 link.Read<float>(&value); minHeight = (int32)value;
940 link.Read<float>(&value); maxHeight = (int32)value;
942 link.Read<int32>(&minWidth);
943 link.Read<int32>(&maxWidth);
944 link.Read<int32>(&minHeight);
945 link.Read<int32>(&maxHeight);
947 DTRACE(("ServerWindow %s: Message AS_SET_SIZE_LIMITS: "
948 "x: %" B_PRId32 "-%" B_PRId32 ", y: %" B_PRId32 "-%" B_PRId32
949 "\n", Title(), minWidth, maxWidth, minHeight, maxHeight));
951 fWindow->SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
953 // and now, sync the client to the limits that we were able to enforce
954 fWindow->GetSizeLimits(&minWidth, &maxWidth,
955 &minHeight, &maxHeight);
957 fLink.StartMessage(B_OK);
958 fLink.Attach<BRect>(fWindow->Frame());
959 fLink.Attach<float>((float)minWidth);
960 fLink.Attach<float>((float)maxWidth);
961 fLink.Attach<float>((float)minHeight);
962 fLink.Attach<float>((float)maxHeight);
964 fLink.Flush();
966 fDesktop->NotifySizeLimitsChanged(fWindow, minWidth, maxWidth,
967 minHeight, maxHeight);
968 break;
971 case AS_SET_DECORATOR_SETTINGS:
973 // Has the all-window look
974 DTRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n",
975 Title()));
977 int32 size;
978 if (fWindow && link.Read<int32>(&size) == B_OK) {
979 char buffer[size];
980 if (link.Read(buffer, size) == B_OK) {
981 BMessage settings;
982 if (settings.Unflatten(buffer) == B_OK)
983 fDesktop->SetWindowDecoratorSettings(fWindow, settings);
986 break;
989 case AS_GET_DECORATOR_SETTINGS:
991 DTRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n",
992 Title()));
994 bool success = false;
996 BMessage settings;
997 if (fWindow->GetDecoratorSettings(&settings)) {
998 int32 size = settings.FlattenedSize();
999 char buffer[size];
1000 if (settings.Flatten(buffer, size) == B_OK) {
1001 success = true;
1002 fLink.StartMessage(B_OK);
1003 fLink.Attach<int32>(size);
1004 fLink.Attach(buffer, size);
1008 if (!success)
1009 fLink.StartMessage(B_ERROR);
1011 fLink.Flush();
1012 break;
1015 case AS_SYSTEM_FONT_CHANGED:
1017 // Has the all-window look
1018 fDesktop->FontsChanged(fWindow);
1019 break;
1022 // Forward to client
1023 case B_FONTS_UPDATED:
1025 // TODO: would knowing which font was changed be useful?
1026 BMessage message(code);
1027 SendMessageToClient(&message);
1028 break;
1031 case AS_REDRAW:
1032 // Nothing to do here - the redraws are actually handled by looking
1033 // at the fRedrawRequested member variable in _MessageLooper().
1034 break;
1036 case AS_SYNC:
1037 DTRACE(("ServerWindow %s: Message AS_SYNC\n", Title()));
1038 // the synchronisation works by the fact that the client
1039 // window is waiting for this reply, after having received it,
1040 // client and server queues are in sync (earlier, the client
1041 // may have pushed drawing commands at the server and now it
1042 // knows they have all been carried out)
1043 fLink.StartMessage(B_OK);
1044 fLink.Flush();
1045 break;
1047 case AS_BEGIN_UPDATE:
1048 DTRACE(("ServerWindow %s: Message AS_BEGIN_UPDATE\n", Title()));
1049 fWindow->BeginUpdate(fLink);
1050 break;
1052 case AS_END_UPDATE:
1053 DTRACE(("ServerWindow %s: Message AS_END_UPDATE\n", Title()));
1054 fWindow->EndUpdate();
1055 break;
1057 case AS_GET_MOUSE:
1059 // Has the all-window look
1060 DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
1062 // Returns
1063 // 1) BPoint mouse location
1064 // 2) int32 button state
1066 BPoint where;
1067 int32 buttons;
1068 fDesktop->GetLastMouseState(&where, &buttons);
1070 fLink.StartMessage(B_OK);
1071 fLink.Attach<BPoint>(where);
1072 fLink.Attach<int32>(buttons);
1073 fLink.Flush();
1074 break;
1077 // BDirectWindow communication
1079 case AS_DIRECT_WINDOW_GET_SYNC_DATA:
1081 status_t status = _EnableDirectWindowMode();
1083 fLink.StartMessage(status);
1084 if (status == B_OK) {
1085 struct direct_window_sync_data syncData;
1086 fDirectWindowInfo->GetSyncData(syncData);
1088 fLink.Attach(&syncData, sizeof(syncData));
1091 fLink.Flush();
1092 break;
1094 case AS_DIRECT_WINDOW_SET_FULLSCREEN:
1096 // Has the all-window look
1097 bool enable;
1098 link.Read<bool>(&enable);
1100 status_t status = B_OK;
1101 if (fDirectWindowInfo != NULL)
1102 _DirectWindowSetFullScreen(enable);
1103 else
1104 status = B_BAD_TYPE;
1106 fLink.StartMessage(status);
1107 fLink.Flush();
1108 break;
1111 // View creation and destruction (don't need a valid fCurrentView)
1113 case AS_SET_CURRENT_VIEW:
1115 int32 token;
1116 if (link.Read<int32>(&token) != B_OK)
1117 break;
1119 View *current;
1120 if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1121 (void**)&current) != B_OK
1122 || current->Window()->ServerWindow() != this) {
1123 // TODO: if this happens, we probably want to kill the app and
1124 // clean up
1125 debug_printf("ServerWindow %s: Message "
1126 "\n\n\nAS_SET_CURRENT_VIEW: view not found, token %"
1127 B_PRId32 "\n", fTitle, token);
1128 current = NULL;
1129 } else {
1130 DTRACE(("\n\n\nServerWindow %s: Message AS_SET_CURRENT_VIEW: %s, "
1131 "token %" B_PRId32 "\n", fTitle, current->Name(), token));
1132 _SetCurrentView(current);
1134 break;
1137 case AS_VIEW_CREATE_ROOT:
1139 DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE_ROOT\n", fTitle));
1141 // Start receiving top_view data -- pass NULL as the parent view.
1142 // This should be the *only* place where this happens.
1143 if (fCurrentView != NULL) {
1144 debug_printf("ServerWindow %s: Message "
1145 "AS_VIEW_CREATE_ROOT: fCurrentView already set!!\n",
1146 fTitle);
1147 break;
1150 _SetCurrentView(_CreateView(link, NULL));
1151 fWindow->SetTopView(fCurrentView);
1152 break;
1155 case AS_VIEW_CREATE:
1157 DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE: View name: "
1158 "%s\n", fTitle, fCurrentView->Name()));
1160 View* parent = NULL;
1161 View* newView = _CreateView(link, &parent);
1162 if (parent != NULL && newView != NULL)
1163 parent->AddChild(newView);
1164 else {
1165 delete newView;
1166 debug_printf("ServerWindow %s: Message AS_VIEW_CREATE: "
1167 "parent or newView NULL!!\n", fTitle);
1169 break;
1172 case AS_TALK_TO_DESKTOP_LISTENER:
1174 if (fDesktop->MessageForListener(fWindow, fLink.Receiver(),
1175 fLink.Sender()))
1176 break;
1177 // unhandled message at least send an error if needed
1178 if (link.NeedsReply()) {
1179 fLink.StartMessage(B_ERROR);
1180 fLink.Flush();
1182 break;
1185 default:
1186 if (fCurrentView == NULL) {
1187 BString codeName;
1188 string_for_message_code(code, codeName);
1189 debug_printf("ServerWindow %s received unexpected code - "
1190 "message '%s' before top_view attached.\n",
1191 Title(), codeName.String());
1192 if (link.NeedsReply()) {
1193 fLink.StartMessage(B_ERROR);
1194 fLink.Flush();
1196 return;
1199 _DispatchViewMessage(code, link);
1200 break;
1206 Dispatches all view messages that need a valid fCurrentView.
1208 void
1209 ServerWindow::_DispatchViewMessage(int32 code,
1210 BPrivate::LinkReceiver &link)
1212 if (_DispatchPictureMessage(code, link))
1213 return;
1215 switch (code) {
1216 case AS_VIEW_SCROLL:
1218 float dh;
1219 float dv;
1220 link.Read<float>(&dh);
1221 if (link.Read<float>(&dv) != B_OK)
1222 break;
1224 DTRACE(("ServerWindow %s: Message AS_VIEW_SCROLL: View name: "
1225 "%s, %.1f x %.1f\n", fTitle, fCurrentView->Name(), dh, dv));
1226 fWindow->ScrollViewBy(fCurrentView, dh, dv);
1227 break;
1229 case AS_VIEW_COPY_BITS:
1231 BRect src;
1232 BRect dst;
1234 link.Read<BRect>(&src);
1235 if (link.Read<BRect>(&dst) != B_OK)
1236 break;
1238 DTRACE(("ServerWindow %s: Message AS_VIEW_COPY_BITS: View name: "
1239 "%s, BRect(%.1f, %.1f, %.1f, %.1f) -> "
1240 "BRect(%.1f, %.1f, %.1f, %.1f)\n", fTitle,
1241 fCurrentView->Name(), src.left, src.top, src.right, src.bottom,
1242 dst.left, dst.top, dst.right, dst.bottom));
1244 BRegion contentRegion;
1245 // TODO: avoid copy operation maybe?
1246 fWindow->GetContentRegion(&contentRegion);
1247 fCurrentView->CopyBits(src, dst, contentRegion);
1248 break;
1250 case AS_VIEW_DELETE:
1252 // Received when a view is detached from a window
1254 int32 token;
1255 if (link.Read<int32>(&token) != B_OK)
1256 break;
1258 View *view;
1259 if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1260 (void**)&view) == B_OK
1261 && view->Window()->ServerWindow() == this) {
1262 View* parent = view->Parent();
1264 DTRACE(("ServerWindow %s: AS_VIEW_DELETE view: %p, "
1265 "parent: %p\n", fTitle, view, parent));
1267 if (parent != NULL) {
1268 parent->RemoveChild(view);
1270 if (view->EventMask() != 0) {
1271 // TODO: possible deadlock (event dispatcher already
1272 // locked itself, waits for Desktop write lock, but
1273 // we have it, now we are trying to lock the event
1274 // dispatcher -> deadlock)
1275 fDesktop->UnlockSingleWindow();
1276 fDesktop->EventDispatcher().RemoveListener(
1277 EventTarget(), token);
1278 fDesktop->LockSingleWindow();
1281 if (fCurrentView == view || fCurrentView->HasParent(view))
1282 _SetCurrentView(parent);
1284 delete view;
1285 } // else we don't delete the root view
1287 break;
1289 case AS_VIEW_SET_STATE:
1291 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: "
1292 "View name: %s\n", fTitle, fCurrentView->Name()));
1294 fCurrentView->CurrentState()->ReadFromLink(link);
1295 // TODO: When is this used?!?
1296 fCurrentView->RebuildClipping(true);
1297 _UpdateDrawState(fCurrentView);
1299 break;
1301 case AS_VIEW_SET_FONT_STATE:
1303 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: "
1304 "View name: %s\n", fTitle, fCurrentView->Name()));
1306 fCurrentView->CurrentState()->ReadFontFromLink(link);
1307 fWindow->GetDrawingEngine()->SetFont(
1308 fCurrentView->CurrentState());
1309 break;
1311 case AS_VIEW_GET_STATE:
1313 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: "
1314 "View name: %s\n", fTitle, fCurrentView->Name()));
1316 fLink.StartMessage(B_OK);
1318 // attach state data
1319 fCurrentView->CurrentState()->WriteToLink(fLink.Sender());
1320 fLink.Flush();
1321 break;
1323 case AS_VIEW_SET_EVENT_MASK:
1325 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: "
1326 "View name: %s\n", fTitle, fCurrentView->Name()));
1327 uint32 eventMask, options;
1329 link.Read<uint32>(&eventMask);
1330 if (link.Read<uint32>(&options) == B_OK) {
1331 fCurrentView->SetEventMask(eventMask, options);
1333 fDesktop->UnlockSingleWindow();
1334 // TODO: possible deadlock!
1335 if (eventMask != 0 || options != 0) {
1336 fDesktop->EventDispatcher().AddListener(EventTarget(),
1337 fCurrentView->Token(), eventMask, options);
1338 } else {
1339 fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1340 fCurrentView->Token());
1342 fDesktop->LockSingleWindow();
1344 break;
1346 case AS_VIEW_SET_MOUSE_EVENT_MASK:
1348 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: "
1349 "View name: %s\n", fTitle, fCurrentView->Name()));
1350 uint32 eventMask, options;
1352 link.Read<uint32>(&eventMask);
1353 if (link.Read<uint32>(&options) == B_OK) {
1354 fDesktop->UnlockSingleWindow();
1355 // TODO: possible deadlock
1356 if (eventMask != 0 || options != 0) {
1357 if (options & B_LOCK_WINDOW_FOCUS)
1358 fDesktop->SetFocusLocked(fWindow);
1359 fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1360 fCurrentView->Token(), eventMask, options);
1361 } else {
1362 fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1363 fCurrentView->Token());
1365 fDesktop->LockSingleWindow();
1368 // TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1369 break;
1371 case AS_VIEW_MOVE_TO:
1373 float x, y;
1374 link.Read<float>(&x);
1375 if (link.Read<float>(&y) != B_OK)
1376 break;
1378 DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: "
1379 "%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y));
1381 float offsetX = x - fCurrentView->Frame().left;
1382 float offsetY = y - fCurrentView->Frame().top;
1384 BRegion dirty;
1385 fCurrentView->MoveBy(offsetX, offsetY, &dirty);
1387 // TODO: think about how to avoid this hack:
1388 // the parent clipping needs to be updated, it is not
1389 // done in MoveBy() since it would cause
1390 // too much computations when children are resized because
1391 // follow modes
1392 if (View* parent = fCurrentView->Parent())
1393 parent->RebuildClipping(false);
1395 fWindow->MarkContentDirty(dirty);
1396 break;
1398 case AS_VIEW_RESIZE_TO:
1400 float newWidth, newHeight;
1401 link.Read<float>(&newWidth);
1402 if (link.Read<float>(&newHeight) != B_OK)
1403 break;
1405 DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: "
1406 "%s, width: %.1f, height: %.1f\n", fTitle,
1407 fCurrentView->Name(), newWidth, newHeight));
1409 float deltaWidth = newWidth - fCurrentView->Frame().Width();
1410 float deltaHeight = newHeight - fCurrentView->Frame().Height();
1412 BRegion dirty;
1413 fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);
1415 // TODO: see above
1416 if (View* parent = fCurrentView->Parent())
1417 parent->RebuildClipping(false);
1419 fWindow->MarkContentDirty(dirty);
1420 break;
1422 case AS_VIEW_GET_COORD:
1424 // our offset in the parent -> will be originX and originY
1425 // in BView
1426 BPoint parentOffset = fCurrentView->Frame().LeftTop();
1428 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: "
1429 "View: %s -> x: %.1f, y: %.1f\n", Title(),
1430 fCurrentView->Name(), parentOffset.x, parentOffset.y));
1432 fLink.StartMessage(B_OK);
1433 fLink.Attach<BPoint>(parentOffset);
1434 fLink.Attach<BRect>(fCurrentView->Bounds());
1435 fLink.Flush();
1436 break;
1438 case AS_VIEW_SET_ORIGIN:
1440 float x, y;
1441 link.Read<float>(&x);
1442 if (link.Read<float>(&y) != B_OK)
1443 break;
1445 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: "
1446 "View: %s -> x: %.1f, y: %.1f\n", Title(),
1447 fCurrentView->Name(), x, y));
1449 fCurrentView->SetDrawingOrigin(BPoint(x, y));
1450 _UpdateDrawState(fCurrentView);
1451 break;
1453 case AS_VIEW_GET_ORIGIN:
1455 BPoint drawingOrigin = fCurrentView->DrawingOrigin();
1457 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: "
1458 "View: %s -> x: %.1f, y: %.1f\n", Title(),
1459 fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y));
1461 fLink.StartMessage(B_OK);
1462 fLink.Attach<BPoint>(drawingOrigin);
1463 fLink.Flush();
1464 break;
1466 case AS_VIEW_RESIZE_MODE:
1468 uint32 resizeMode;
1469 if (link.Read<uint32>(&resizeMode) != B_OK)
1470 break;
1472 DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: "
1473 "View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(),
1474 resizeMode));
1476 fCurrentView->SetResizeMode(resizeMode);
1477 break;
1479 case AS_VIEW_SET_FLAGS:
1481 uint32 flags;
1482 link.Read<uint32>(&flags);
1484 // The views clipping changes when the B_DRAW_ON_CHILDREN flag is
1485 // toggled.
1486 bool updateClipping = (flags & B_DRAW_ON_CHILDREN)
1487 ^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN);
1489 fCurrentView->SetFlags(flags);
1490 _UpdateDrawState(fCurrentView);
1492 if (updateClipping) {
1493 fCurrentView->RebuildClipping(false);
1494 fCurrentDrawingRegionValid = false;
1497 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: "
1498 "View: %s -> flags: %" B_PRIu32 "\n", Title(),
1499 fCurrentView->Name(), flags));
1500 break;
1502 case AS_VIEW_HIDE:
1503 DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n",
1504 Title(), fCurrentView->Name()));
1505 fCurrentView->SetHidden(true);
1506 break;
1508 case AS_VIEW_SHOW:
1509 DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n",
1510 Title(), fCurrentView->Name()));
1511 fCurrentView->SetHidden(false);
1512 break;
1514 case AS_VIEW_SET_LINE_MODE:
1516 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: "
1517 "View: %s\n", Title(), fCurrentView->Name()));
1518 ViewSetLineModeInfo info;
1519 if (link.Read<ViewSetLineModeInfo>(&info) != B_OK)
1520 break;
1522 fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
1523 fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
1524 fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
1526 fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
1527 info.lineJoin, info.miterLimit);
1529 break;
1531 case AS_VIEW_GET_LINE_MODE:
1533 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: "
1534 "View: %s\n", Title(), fCurrentView->Name()));
1535 ViewSetLineModeInfo info;
1536 info.lineJoin = fCurrentView->CurrentState()->LineJoinMode();
1537 info.lineCap = fCurrentView->CurrentState()->LineCapMode();
1538 info.miterLimit = fCurrentView->CurrentState()->MiterLimit();
1540 fLink.StartMessage(B_OK);
1541 fLink.Attach<ViewSetLineModeInfo>(info);
1542 fLink.Flush();
1544 break;
1546 case AS_VIEW_SET_FILL_RULE:
1548 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: "
1549 "View: %s\n", Title(), fCurrentView->Name()));
1550 int32 fillRule;
1551 if (link.Read<int32>(&fillRule) != B_OK)
1552 break;
1554 fCurrentView->CurrentState()->SetFillRule(fillRule);
1555 fWindow->GetDrawingEngine()->SetFillRule(fillRule);
1557 break;
1559 case AS_VIEW_GET_FILL_RULE:
1561 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: "
1562 "View: %s\n", Title(), fCurrentView->Name()));
1563 int32 fillRule = fCurrentView->CurrentState()->FillRule();
1565 fLink.StartMessage(B_OK);
1566 fLink.Attach<int32>(fillRule);
1567 fLink.Flush();
1569 break;
1571 case AS_VIEW_PUSH_STATE:
1573 DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: "
1574 "%s\n", Title(), fCurrentView->Name()));
1576 fCurrentView->PushState();
1577 // TODO: is this necessary?
1578 // _UpdateDrawState(fCurrentView);
1579 break;
1581 case AS_VIEW_POP_STATE:
1583 DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n",
1584 Title(), fCurrentView->Name()));
1586 fCurrentView->PopState();
1587 _UpdateDrawState(fCurrentView);
1588 break;
1590 case AS_VIEW_SET_SCALE:
1592 float scale;
1593 if (link.Read<float>(&scale) != B_OK)
1594 break;
1596 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: "
1597 "View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(),
1598 scale));
1600 fCurrentView->SetScale(scale);
1601 _UpdateDrawState(fCurrentView);
1602 break;
1604 case AS_VIEW_GET_SCALE:
1606 float scale = fCurrentView->CurrentState()->Scale();
1608 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: "
1609 "View: %s -> scale: %.2f\n",
1610 Title(), fCurrentView->Name(), scale));
1612 fLink.StartMessage(B_OK);
1613 fLink.Attach<float>(scale);
1614 fLink.Flush();
1615 break;
1617 case AS_VIEW_SET_TRANSFORM:
1619 BAffineTransform transform;
1620 if (link.Read<BAffineTransform>(&transform) != B_OK)
1621 break;
1623 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: "
1624 "View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1625 Title(), fCurrentView->Name(), transform.sx, transform.shy,
1626 transform.shx, transform.sy, transform.tx, transform.ty));
1628 fCurrentView->CurrentState()->SetTransform(transform);
1629 _UpdateDrawState(fCurrentView);
1630 break;
1632 case AS_VIEW_GET_TRANSFORM:
1634 BAffineTransform transform
1635 = fCurrentView->CurrentState()->Transform();
1637 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: "
1638 "View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1639 Title(), fCurrentView->Name(), transform.sx, transform.shy,
1640 transform.shx, transform.sy, transform.tx, transform.ty));
1642 fLink.StartMessage(B_OK);
1643 fLink.Attach<BAffineTransform>(transform);
1644 fLink.Flush();
1645 break;
1647 case AS_VIEW_AFFINE_TRANSLATE:
1649 double x, y;
1650 link.Read<double>(&x);
1651 link.Read<double>(&y);
1652 BAffineTransform current =
1653 fCurrentView->CurrentState()->Transform();
1654 current.PreTranslateBy(x, y);
1655 fCurrentView->CurrentState()->SetTransform(current);
1656 _UpdateDrawState(fCurrentView);
1657 break;
1660 case AS_VIEW_AFFINE_SCALE:
1662 double x, y;
1663 link.Read<double>(&x);
1664 link.Read<double>(&y);
1665 BAffineTransform current =
1666 fCurrentView->CurrentState()->Transform();
1667 current.PreScaleBy(x, y);
1668 fCurrentView->CurrentState()->SetTransform(current);
1669 _UpdateDrawState(fCurrentView);
1670 break;
1673 case AS_VIEW_AFFINE_ROTATE:
1675 double angleRadians;
1676 link.Read<double>(&angleRadians);
1677 BAffineTransform current =
1678 fCurrentView->CurrentState()->Transform();
1679 current.PreRotateBy(angleRadians);
1680 fCurrentView->CurrentState()->SetTransform(current);
1681 _UpdateDrawState(fCurrentView);
1682 break;
1685 case AS_VIEW_SET_PEN_LOC:
1687 BPoint location;
1688 if (link.Read<BPoint>(&location) != B_OK)
1689 break;
1691 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: "
1692 "View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1693 fCurrentView->Name(), location.x, location.y));
1695 fCurrentView->CurrentState()->SetPenLocation(location);
1696 break;
1698 case AS_VIEW_GET_PEN_LOC:
1700 BPoint location = fCurrentView->CurrentState()->PenLocation();
1702 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: "
1703 "View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1704 fCurrentView->Name(), location.x, location.y));
1706 fLink.StartMessage(B_OK);
1707 fLink.Attach<BPoint>(location);
1708 fLink.Flush();
1710 break;
1712 case AS_VIEW_SET_PEN_SIZE:
1714 float penSize;
1715 if (link.Read<float>(&penSize) != B_OK)
1716 break;
1718 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: "
1719 "View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1721 fCurrentView->CurrentState()->SetPenSize(penSize);
1722 fWindow->GetDrawingEngine()->SetPenSize(
1723 fCurrentView->CurrentState()->PenSize());
1724 break;
1726 case AS_VIEW_GET_PEN_SIZE:
1728 float penSize = fCurrentView->CurrentState()->UnscaledPenSize();
1730 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: "
1731 "View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1733 fLink.StartMessage(B_OK);
1734 fLink.Attach<float>(penSize);
1735 fLink.Flush();
1737 break;
1739 case AS_VIEW_SET_VIEW_COLOR:
1741 rgb_color color;
1742 if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1743 break;
1745 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: "
1746 "View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(),
1747 fCurrentView->Name(), color.red, color.green, color.blue,
1748 color.alpha));
1750 fCurrentView->SetViewColor(color);
1751 break;
1753 case AS_VIEW_GET_VIEW_COLOR:
1755 rgb_color color = fCurrentView->ViewColor();
1757 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: "
1758 "View: %s -> rgb_color(%d, %d, %d, %d)\n",
1759 Title(), fCurrentView->Name(), color.red, color.green,
1760 color.blue, color.alpha));
1762 fLink.StartMessage(B_OK);
1763 fLink.Attach<rgb_color>(color);
1764 fLink.Flush();
1765 break;
1767 case AS_VIEW_SET_HIGH_COLOR:
1769 rgb_color color;
1770 if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1771 break;
1773 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: "
1774 "View: %s -> rgb_color(%d, %d, %d, %d)\n",
1775 Title(), fCurrentView->Name(), color.red, color.green,
1776 color.blue, color.alpha));
1778 fCurrentView->CurrentState()->SetHighColor(color);
1779 fWindow->GetDrawingEngine()->SetHighColor(color);
1780 break;
1783 case AS_VIEW_SET_HIGH_UI_COLOR:
1785 color_which which = B_NO_COLOR;
1786 float tint = B_NO_TINT;
1788 if (link.Read<color_which>(&which) != B_OK
1789 || link.Read<float>(&tint) != B_OK )
1790 break;
1792 fCurrentView->CurrentState()->SetHighUIColor(which, tint);
1794 // TODO: should we do more color_which validity checking?
1795 if (which != B_NO_COLOR) {
1796 DesktopSettings settings(fDesktop);
1797 rgb_color color = tint_color(settings.UIColor(which), tint);
1799 fCurrentView->CurrentState()->SetHighColor(color);
1800 fWindow->GetDrawingEngine()->SetHighColor(color);
1802 break;
1804 case AS_VIEW_SET_LOW_UI_COLOR:
1806 color_which which = B_NO_COLOR;
1807 float tint = B_NO_TINT;
1809 if (link.Read<color_which>(&which) != B_OK
1810 || link.Read<float>(&tint) != B_OK )
1811 break;
1813 fCurrentView->CurrentState()->SetLowUIColor(which, tint);
1815 // TODO: should we do more color_which validity checking?
1816 if (which != B_NO_COLOR) {
1817 DesktopSettings settings(fDesktop);
1818 rgb_color color = tint_color(settings.UIColor(which), tint);
1820 fCurrentView->CurrentState()->SetLowColor(color);
1821 fWindow->GetDrawingEngine()->SetLowColor(color);
1823 break;
1825 case AS_VIEW_SET_VIEW_UI_COLOR:
1827 color_which which = B_NO_COLOR;
1828 float tint = B_NO_TINT;
1830 if (link.Read<color_which>(&which) != B_OK
1831 || link.Read<float>(&tint) != B_OK )
1832 break;
1834 // TODO: should we do more color_which validity checking?
1835 fCurrentView->SetViewUIColor(which, tint);
1836 break;
1838 case AS_VIEW_GET_HIGH_UI_COLOR:
1840 float tint;
1841 color_which which = fCurrentView->CurrentState()->HighUIColor(&tint);
1842 rgb_color color = fCurrentView->CurrentState()->HighColor();
1844 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_UI_COLOR: "
1845 "View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1846 " %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1847 color.red, color.green, color.blue, color.alpha));
1849 fLink.StartMessage(B_OK);
1850 fLink.Attach<color_which>(which);
1851 fLink.Attach<float>(tint);
1852 fLink.Attach<rgb_color>(color);
1853 fLink.Flush();
1854 break;
1856 case AS_VIEW_GET_LOW_UI_COLOR:
1858 float tint;
1859 color_which which = fCurrentView->CurrentState()->LowUIColor(&tint);
1860 rgb_color color = fCurrentView->CurrentState()->LowColor();
1862 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_UI_COLOR: "
1863 "View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1864 " %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1865 color.red, color.green, color.blue, color.alpha));
1867 fLink.StartMessage(B_OK);
1868 fLink.Attach<color_which>(which);
1869 fLink.Attach<float>(tint);
1870 fLink.Attach<rgb_color>(color);
1871 fLink.Flush();
1872 break;
1874 case AS_VIEW_GET_VIEW_UI_COLOR:
1876 float tint;
1877 color_which which = fCurrentView->ViewUIColor(&tint);
1878 rgb_color color = fCurrentView->ViewColor();
1880 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_UI_COLOR: "
1881 "View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1882 " %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1883 color.red, color.green, color.blue, color.alpha));
1885 fLink.StartMessage(B_OK);
1886 fLink.Attach<color_which>(which);
1887 fLink.Attach<float>(tint);
1888 fLink.Attach<rgb_color>(color);
1889 fLink.Flush();
1890 break;
1892 case AS_VIEW_GET_HIGH_COLOR:
1894 rgb_color color = fCurrentView->CurrentState()->HighColor();
1896 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: "
1897 "View: %s -> rgb_color(%d, %d, %d, %d)\n",
1898 Title(), fCurrentView->Name(), color.red, color.green,
1899 color.blue, color.alpha));
1901 fLink.StartMessage(B_OK);
1902 fLink.Attach<rgb_color>(color);
1903 fLink.Flush();
1904 break;
1906 case AS_VIEW_SET_LOW_COLOR:
1908 rgb_color color;
1909 if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1910 break;
1912 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: "
1913 "View: %s -> rgb_color(%d, %d, %d, %d)\n",
1914 Title(), fCurrentView->Name(), color.red, color.green,
1915 color.blue, color.alpha));
1917 fCurrentView->CurrentState()->SetLowColor(color);
1918 fWindow->GetDrawingEngine()->SetLowColor(color);
1919 break;
1921 case AS_VIEW_GET_LOW_COLOR:
1923 rgb_color color = fCurrentView->CurrentState()->LowColor();
1925 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: "
1926 "View: %s -> rgb_color(%d, %d, %d, %d)\n",
1927 Title(), fCurrentView->Name(), color.red, color.green,
1928 color.blue, color.alpha));
1930 fLink.StartMessage(B_OK);
1931 fLink.Attach<rgb_color>(color);
1932 fLink.Flush();
1933 break;
1935 case AS_VIEW_SET_PATTERN:
1937 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: "
1938 "View: %s\n", fTitle, fCurrentView->Name()));
1940 pattern pat;
1941 if (link.Read(&pat, sizeof(pattern)) != B_OK)
1942 break;
1944 fCurrentView->CurrentState()->SetPattern(Pattern(pat));
1945 fWindow->GetDrawingEngine()->SetPattern(pat);
1946 break;
1949 case AS_VIEW_SET_BLENDING_MODE:
1951 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: "
1952 "View: %s\n", Title(), fCurrentView->Name()));
1954 ViewBlendingModeInfo info;
1955 if (link.Read<ViewBlendingModeInfo>(&info) != B_OK)
1956 break;
1958 fCurrentView->CurrentState()->SetBlendingMode(
1959 info.sourceAlpha, info.alphaFunction);
1960 fWindow->GetDrawingEngine()->SetBlendingMode(
1961 info.sourceAlpha, info.alphaFunction);
1962 break;
1964 case AS_VIEW_GET_BLENDING_MODE:
1966 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: "
1967 "View: %s\n", Title(), fCurrentView->Name()));
1969 ViewBlendingModeInfo info;
1970 info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode();
1971 info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode();
1973 fLink.StartMessage(B_OK);
1974 fLink.Attach<ViewBlendingModeInfo>(info);
1975 fLink.Flush();
1977 break;
1979 case AS_VIEW_SET_DRAWING_MODE:
1981 int8 drawingMode;
1982 if (link.Read<int8>(&drawingMode) != B_OK)
1983 break;
1985 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: "
1986 "View: %s -> %s\n", Title(), fCurrentView->Name(),
1987 kDrawingModeMap[drawingMode]));
1989 fCurrentView->CurrentState()->SetDrawingMode(
1990 (drawing_mode)drawingMode);
1991 fWindow->GetDrawingEngine()->SetDrawingMode(
1992 (drawing_mode)drawingMode);
1993 break;
1995 case AS_VIEW_GET_DRAWING_MODE:
1997 int8 drawingMode
1998 = (int8)(fCurrentView->CurrentState()->GetDrawingMode());
2000 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: "
2001 "View: %s -> %s\n", Title(), fCurrentView->Name(),
2002 kDrawingModeMap[drawingMode]));
2004 fLink.StartMessage(B_OK);
2005 fLink.Attach<int8>(drawingMode);
2006 fLink.Flush();
2008 break;
2010 case AS_VIEW_SET_VIEW_BITMAP:
2012 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: "
2013 "View: %s\n", Title(), fCurrentView->Name()));
2015 int32 bitmapToken, resizingMode, options;
2016 BRect srcRect, dstRect;
2018 link.Read<int32>(&bitmapToken);
2019 link.Read<BRect>(&srcRect);
2020 link.Read<BRect>(&dstRect);
2021 link.Read<int32>(&resizingMode);
2022 status_t status = link.Read<int32>(&options);
2024 rgb_color colorKey = {0};
2026 if (status == B_OK) {
2027 ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken);
2028 if (bitmapToken == -1 || bitmap != NULL) {
2029 bool wasOverlay = fCurrentView->ViewBitmap() != NULL
2030 && fCurrentView->ViewBitmap()->Overlay() != NULL;
2032 fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
2033 resizingMode, options);
2035 // TODO: if we revert the view color overlay handling
2036 // in View::Draw() to the BeOS version, we never
2037 // need to invalidate the view for overlays.
2039 // Invalidate view - but only if this is a non-overlay
2040 // switch
2041 if (bitmap == NULL || bitmap->Overlay() == NULL
2042 || !wasOverlay) {
2043 BRegion dirty((BRect)fCurrentView->Bounds());
2044 fWindow->InvalidateView(fCurrentView, dirty);
2047 if (bitmap != NULL && bitmap->Overlay() != NULL) {
2048 bitmap->Overlay()->SetFlags(options);
2049 colorKey = bitmap->Overlay()->Color();
2052 if (bitmap != NULL)
2053 bitmap->ReleaseReference();
2054 } else
2055 status = B_BAD_VALUE;
2058 fLink.StartMessage(status);
2059 if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
2060 // Attach color key for the overlay bitmap
2061 fLink.Attach<rgb_color>(colorKey);
2064 fLink.Flush();
2065 break;
2067 case AS_VIEW_PRINT_ALIASING:
2069 DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: "
2070 "View: %s\n", Title(), fCurrentView->Name()));
2072 bool fontAliasing;
2073 if (link.Read<bool>(&fontAliasing) == B_OK) {
2074 fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing);
2075 _UpdateDrawState(fCurrentView);
2077 break;
2079 case AS_VIEW_CLIP_TO_PICTURE:
2081 DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: "
2082 "View: %s\n", Title(), fCurrentView->Name()));
2084 int32 pictureToken;
2085 BPoint where;
2086 bool inverse = false;
2088 link.Read<int32>(&pictureToken);
2089 if (pictureToken < 0) {
2090 fCurrentView->SetAlphaMask(NULL);
2091 _UpdateDrawState(fCurrentView);
2092 break;
2095 link.Read<BPoint>(&where);
2096 if (link.Read<bool>(&inverse) != B_OK)
2097 break;
2099 ServerPicture* picture = fServerApp->GetPicture(pictureToken);
2100 if (picture == NULL)
2101 break;
2103 AlphaMask* const mask = new(std::nothrow) PictureAlphaMask(
2104 fCurrentView->GetAlphaMask(), picture,
2105 *fCurrentView->CurrentState(), where, inverse);
2106 fCurrentView->SetAlphaMask(mask);
2107 if (mask != NULL)
2108 mask->ReleaseReference();
2110 _UpdateDrawState(fCurrentView);
2112 picture->ReleaseReference();
2113 break;
2116 case AS_VIEW_GET_CLIP_REGION:
2118 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: "
2119 "View: %s\n", Title(), fCurrentView->Name()));
2121 // if this view is hidden, it has no visible region
2122 fLink.StartMessage(B_OK);
2123 if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) {
2124 BRegion empty;
2125 fLink.AttachRegion(empty);
2126 } else {
2127 _UpdateCurrentDrawingRegion();
2128 BRegion region(fCurrentDrawingRegion);
2129 fCurrentView->ScreenToLocalTransform().Apply(&region);
2130 fLink.AttachRegion(region);
2132 fLink.Flush();
2134 break;
2136 case AS_VIEW_SET_CLIP_REGION:
2138 int32 rectCount;
2139 status_t status = link.Read<int32>(&rectCount);
2140 // a negative count means no
2141 // region for the current draw state,
2142 // but an *empty* region is actually valid!
2143 // even if it means no drawing is allowed
2145 if (status < B_OK)
2146 break;
2148 if (rectCount >= 0) {
2149 // we are supposed to set the clipping region
2150 BRegion region;
2151 if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
2152 break;
2154 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2155 "View: %s -> rect count: %" B_PRId32 ", frame = "
2156 "BRect(%.1f, %.1f, %.1f, %.1f)\n",
2157 Title(), fCurrentView->Name(), rectCount,
2158 region.Frame().left, region.Frame().top,
2159 region.Frame().right, region.Frame().bottom));
2161 fCurrentView->SetUserClipping(&region);
2162 } else {
2163 // we are supposed to unset the clipping region
2164 // passing NULL sets this states region to that
2165 // of the previous state
2167 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2168 "View: %s -> unset\n", Title(), fCurrentView->Name()));
2170 fCurrentView->SetUserClipping(NULL);
2172 fCurrentDrawingRegionValid = false;
2174 break;
2177 case AS_VIEW_CLIP_TO_RECT:
2179 bool inverse;
2180 BRect rect;
2182 link.Read<bool>(&inverse);
2183 link.Read<BRect>(&rect);
2185 bool needDrawStateUpdate = fCurrentView->ClipToRect(
2186 rect, inverse);
2187 fCurrentDrawingRegionValid = false;
2189 if (needDrawStateUpdate)
2190 _UpdateDrawState(fCurrentView);
2192 _UpdateCurrentDrawingRegion();
2194 BRegion region(fCurrentDrawingRegion);
2195 fCurrentView->ScreenToLocalTransform().Apply(&region);
2197 break;
2200 case AS_VIEW_CLIP_TO_SHAPE:
2202 bool inverse;
2203 link.Read<bool>(&inverse);
2205 shape_data shape;
2206 link.Read<int32>(&shape.opCount);
2207 link.Read<int32>(&shape.ptCount);
2208 shape.opSize = shape.opCount * sizeof(uint32);
2209 shape.ptSize = shape.ptCount * sizeof(BPoint);
2210 shape.opList = new(nothrow) uint32[shape.opCount];
2211 shape.ptList = new(nothrow) BPoint[shape.ptCount];
2212 if (link.Read(shape.opList, shape.opSize) >= B_OK
2213 && link.Read(shape.ptList, shape.ptSize) >= B_OK) {
2214 fCurrentView->ClipToShape(&shape, inverse);
2215 _UpdateDrawState(fCurrentView);
2218 delete[] shape.opList;
2219 delete[] shape.ptList;
2220 break;
2223 case AS_VIEW_INVALIDATE_RECT:
2225 // NOTE: looks like this call is NOT affected by origin and scale
2226 // on R5 so this implementation is "correct"
2227 BRect invalidRect;
2228 if (link.Read<BRect>(&invalidRect) == B_OK) {
2229 DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: "
2230 "View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2231 fCurrentView->Name(), invalidRect.left, invalidRect.top,
2232 invalidRect.right, invalidRect.bottom));
2234 View* view = NULL;
2235 if (link.Read<View*>(&view) != B_OK)
2236 view = fCurrentView;
2238 // make sure the view is still available!
2239 if (view != fCurrentView
2240 && !fWindow->TopView()->HasView(view))
2241 break;
2243 BRegion dirty(invalidRect);
2244 fWindow->InvalidateView(view, dirty);
2246 break;
2249 case AS_VIEW_DELAYED_INVALIDATE_RECT:
2251 bigtime_t time = 0;
2252 BRect invalidRect;
2253 if (link.Read<bigtime_t>(&time) == B_OK
2254 && link.Read<BRect>(&invalidRect) == B_OK) {
2255 DTRACE(("ServerWindow %s: Message "
2256 "AS_VIEW_DELAYED_INVALIDATE_RECT: "
2257 "View: %s -> BRect(%.1f, %.1f, %.1f, %.1f) at time %llu\n",
2258 Title(), fCurrentView->Name(), invalidRect.left,
2259 invalidRect.top, invalidRect.right, invalidRect.bottom,
2260 time));
2262 DelayedMessage delayed(AS_VIEW_INVALIDATE_RECT, time, true);
2263 delayed.AddTarget(MessagePort());
2264 delayed.SetMerge(DM_MERGE_DUPLICATES);
2266 if (delayed.Attach<BRect>(invalidRect) == B_OK
2267 && delayed.Attach<View*>(fCurrentView) == B_OK)
2268 delayed.Flush();
2270 break;
2273 case AS_VIEW_INVALIDATE_REGION:
2275 // NOTE: looks like this call is NOT affected by origin and scale
2276 // on R5 so this implementation is "correct"
2277 BRegion region;
2278 if (link.ReadRegion(&region) < B_OK)
2279 break;
2281 DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: "
2282 "View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, "
2283 "%.1f, %.1f, %.1f)\n", Title(),
2284 fCurrentView->Name(), region.CountRects(),
2285 region.Frame().left, region.Frame().top,
2286 region.Frame().right, region.Frame().bottom));
2288 fWindow->InvalidateView(fCurrentView, region);
2289 break;
2292 case AS_VIEW_DRAG_IMAGE:
2294 // TODO: flesh out AS_VIEW_DRAG_IMAGE
2295 DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
2297 int32 bitmapToken;
2298 drawing_mode dragMode;
2299 BPoint offset;
2300 int32 bufferSize;
2302 link.Read<int32>(&bitmapToken);
2303 link.Read<int32>((int32*)&dragMode);
2304 link.Read<BPoint>(&offset);
2305 link.Read<int32>(&bufferSize);
2307 if (bufferSize > 0) {
2308 char* buffer = new (nothrow) char[bufferSize];
2309 BMessage dragMessage;
2310 if (link.Read(buffer, bufferSize) == B_OK
2311 && dragMessage.Unflatten(buffer) == B_OK) {
2312 ServerBitmap* bitmap
2313 = fServerApp->GetBitmap(bitmapToken);
2314 // TODO: possible deadlock
2315 fDesktop->UnlockSingleWindow();
2316 fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2317 bitmap, offset);
2318 fDesktop->LockSingleWindow();
2319 if (bitmap != NULL)
2320 bitmap->ReleaseReference();
2322 delete[] buffer;
2324 // sync the client (it can now delete the bitmap)
2325 fLink.StartMessage(B_OK);
2326 fLink.Flush();
2328 break;
2330 case AS_VIEW_DRAG_RECT:
2332 // TODO: flesh out AS_VIEW_DRAG_RECT
2333 DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
2335 BRect dragRect;
2336 BPoint offset;
2337 int32 bufferSize;
2339 link.Read<BRect>(&dragRect);
2340 link.Read<BPoint>(&offset);
2341 link.Read<int32>(&bufferSize);
2343 if (bufferSize > 0) {
2344 char* buffer = new (nothrow) char[bufferSize];
2345 BMessage dragMessage;
2346 if (link.Read(buffer, bufferSize) == B_OK
2347 && dragMessage.Unflatten(buffer) == B_OK) {
2348 // TODO: possible deadlock
2349 fDesktop->UnlockSingleWindow();
2350 fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2351 NULL /* should be dragRect */, offset);
2352 fDesktop->LockSingleWindow();
2354 delete[] buffer;
2356 break;
2359 case AS_VIEW_BEGIN_RECT_TRACK:
2361 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n",
2362 Title()));
2363 BRect dragRect;
2364 uint32 style;
2366 link.Read<BRect>(&dragRect);
2367 link.Read<uint32>(&style);
2369 // TODO: implement rect tracking (used sometimes for selecting
2370 // a group of things, also sometimes used to appear to drag
2371 // something, but without real drag message)
2372 break;
2374 case AS_VIEW_END_RECT_TRACK:
2376 DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n",
2377 Title()));
2378 // TODO: implement rect tracking
2379 break;
2382 case AS_VIEW_BEGIN_PICTURE:
2384 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
2385 Title()));
2386 ServerPicture* picture = App()->CreatePicture();
2387 if (picture != NULL) {
2388 picture->SyncState(fCurrentView);
2389 fCurrentView->SetPicture(picture);
2391 break;
2394 case AS_VIEW_APPEND_TO_PICTURE:
2396 DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
2397 Title()));
2399 int32 token;
2400 link.Read<int32>(&token);
2402 ServerPicture* picture = App()->GetPicture(token);
2403 if (picture != NULL)
2404 picture->SyncState(fCurrentView);
2406 fCurrentView->SetPicture(picture);
2408 if (picture != NULL)
2409 picture->ReleaseReference();
2410 break;
2413 case AS_VIEW_END_PICTURE:
2415 DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
2416 Title()));
2418 ServerPicture* picture = fCurrentView->Picture();
2419 if (picture != NULL) {
2420 fCurrentView->SetPicture(NULL);
2421 fLink.StartMessage(B_OK);
2422 fLink.Attach<int32>(picture->Token());
2423 } else
2424 fLink.StartMessage(B_ERROR);
2426 fLink.Flush();
2427 break;
2430 case AS_VIEW_BEGIN_LAYER:
2432 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n",
2433 Title()));
2435 uint8 opacity;
2436 link.Read<uint8>(&opacity);
2438 Layer* layer = new(std::nothrow) Layer(opacity);
2439 if (layer == NULL)
2440 break;
2442 if (opacity != 255) {
2443 fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
2444 fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
2445 B_ALPHA_COMPOSITE);
2446 fCurrentView->CurrentState()->SetDrawingModeLocked(true);
2449 fCurrentView->SetPicture(layer);
2450 break;
2453 default:
2454 _DispatchViewDrawingMessage(code, link);
2455 break;
2460 /*! Dispatches all view drawing messages.
2461 The desktop clipping must be read locked when entering this method.
2462 Requires a valid fCurrentView.
2464 void
2465 ServerWindow::_DispatchViewDrawingMessage(int32 code,
2466 BPrivate::LinkReceiver &link)
2468 if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) {
2469 if (link.NeedsReply()) {
2470 debug_printf("ServerWindow::DispatchViewDrawingMessage() got "
2471 "message %" B_PRId32 " that needs a reply!\n", code);
2472 // the client is now blocking and waiting for a reply!
2473 fLink.StartMessage(B_ERROR);
2474 fLink.Flush();
2476 return;
2479 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
2480 if (!drawingEngine) {
2481 // ?!?
2482 debug_printf("ServerWindow %s: no drawing engine!!\n", Title());
2483 if (link.NeedsReply()) {
2484 // the client is now blocking and waiting for a reply!
2485 fLink.StartMessage(B_ERROR);
2486 fLink.Flush();
2488 return;
2491 _UpdateCurrentDrawingRegion();
2492 if (fCurrentDrawingRegion.CountRects() <= 0 && code != AS_VIEW_END_LAYER) {
2493 // If the command is AS_VIEW_END_LAYER, then we continue even if
2494 // the clipping region is empty. The layer itself might set a valid
2495 // clipping while its contents are drawn, and even if it doesn't,
2496 // we must still play back its picture so that we don't leak
2497 // nested layer instances.
2499 DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, "
2500 "INVALID CLIPPING!\n", Title(), fCurrentView->Name()));
2501 if (link.NeedsReply()) {
2502 // the client is now blocking and waiting for a reply!
2503 fLink.StartMessage(B_ERROR);
2504 fLink.Flush();
2506 return;
2509 drawingEngine->LockParallelAccess();
2510 // NOTE: the region is not copied, Painter keeps a pointer,
2511 // that's why you need to use the clipping only for as long
2512 // as you have it locked
2513 drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
2515 switch (code) {
2516 case AS_STROKE_LINE:
2518 ViewStrokeLineInfo info;
2519 if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
2520 break;
2522 DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> "
2523 "BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(),
2524 fCurrentView->Name(),
2525 info.startPoint.x, info.startPoint.y,
2526 info.endPoint.x, info.endPoint.y));
2528 BPoint penPos = info.endPoint;
2529 const SimpleTransform transform =
2530 fCurrentView->PenToScreenTransform();
2531 transform.Apply(&info.startPoint);
2532 transform.Apply(&info.endPoint);
2533 drawingEngine->StrokeLine(info.startPoint, info.endPoint);
2535 // We update the pen here because many DrawingEngine calls which
2536 // do not update the pen position actually call StrokeLine
2538 // TODO: Decide where to put this, for example, it cannot be done
2539 // for DrawString(), also there needs to be a decision, if the pen
2540 // location is in View coordinates (I think it should be) or in
2541 // screen coordinates.
2542 fCurrentView->CurrentState()->SetPenLocation(penPos);
2543 break;
2545 case AS_VIEW_INVERT_RECT:
2547 BRect rect;
2548 if (link.Read<BRect>(&rect) != B_OK)
2549 break;
2551 DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> "
2552 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2553 fCurrentView->Name(), rect.left, rect.top, rect.right,
2554 rect.bottom));
2556 fCurrentView->PenToScreenTransform().Apply(&rect);
2557 drawingEngine->InvertRect(rect);
2558 break;
2560 case AS_STROKE_RECT:
2562 BRect rect;
2563 if (link.Read<BRect>(&rect) != B_OK)
2564 break;
2566 DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> "
2567 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2568 fCurrentView->Name(), rect.left, rect.top, rect.right,
2569 rect.bottom));
2571 fCurrentView->PenToScreenTransform().Apply(&rect);
2572 drawingEngine->StrokeRect(rect);
2573 break;
2575 case AS_FILL_RECT:
2577 BRect rect;
2578 if (link.Read<BRect>(&rect) != B_OK)
2579 break;
2581 DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> "
2582 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2583 fCurrentView->Name(), rect.left, rect.top, rect.right,
2584 rect.bottom));
2586 fCurrentView->PenToScreenTransform().Apply(&rect);
2587 drawingEngine->FillRect(rect);
2588 break;
2590 case AS_FILL_RECT_GRADIENT:
2592 BRect rect;
2593 link.Read<BRect>(&rect);
2594 BGradient* gradient;
2595 if (link.ReadGradient(&gradient) != B_OK)
2596 break;
2598 GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s "
2599 "-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2600 fCurrentView->Name(), rect.left, rect.top, rect.right,
2601 rect.bottom));
2603 const SimpleTransform transform =
2604 fCurrentView->PenToScreenTransform();
2605 transform.Apply(&rect);
2606 transform.Apply(gradient);
2607 drawingEngine->FillRect(rect, *gradient);
2608 delete gradient;
2609 break;
2611 case AS_VIEW_DRAW_BITMAP:
2613 ViewDrawBitmapInfo info;
2614 if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK)
2615 break;
2617 #if 0
2618 if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0)
2619 info.options |= B_FILTER_BITMAP_BILINEAR;
2620 #endif
2622 ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken);
2623 if (bitmap != NULL) {
2624 DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
2625 "View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x "
2626 "%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> "
2627 "BRect(%.1f, %.1f, %.1f, %.1f)\n",
2628 fTitle, fCurrentView->Name(), info.bitmapToken,
2629 bitmap->Width(), bitmap->Height(),
2630 info.bitmapRect.left, info.bitmapRect.top,
2631 info.bitmapRect.right, info.bitmapRect.bottom,
2632 info.viewRect.left, info.viewRect.top,
2633 info.viewRect.right, info.viewRect.bottom));
2635 fCurrentView->PenToScreenTransform().Apply(&info.viewRect);
2637 // TODO: Unbreak...
2638 // if ((info.options & B_WAIT_FOR_RETRACE) != 0)
2639 // fDesktop->HWInterface()->WaitForRetrace(20000);
2641 drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
2642 info.viewRect, info.options);
2644 bitmap->ReleaseReference();
2646 break;
2648 case AS_STROKE_ARC:
2649 case AS_FILL_ARC:
2651 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2653 float angle, span;
2654 BRect r;
2656 link.Read<BRect>(&r);
2657 link.Read<float>(&angle);
2658 if (link.Read<float>(&span) != B_OK)
2659 break;
2661 fCurrentView->PenToScreenTransform().Apply(&r);
2662 drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
2663 break;
2665 case AS_FILL_ARC_GRADIENT:
2667 GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n",
2668 Title()));
2670 float angle, span;
2671 BRect r;
2672 link.Read<BRect>(&r);
2673 link.Read<float>(&angle);
2674 link.Read<float>(&span);
2675 BGradient* gradient;
2676 if (link.ReadGradient(&gradient) != B_OK)
2677 break;
2678 const SimpleTransform transform =
2679 fCurrentView->PenToScreenTransform();
2680 transform.Apply(&r);
2681 transform.Apply(gradient);
2682 drawingEngine->FillArc(r, angle, span, *gradient);
2683 delete gradient;
2684 break;
2686 case AS_STROKE_BEZIER:
2687 case AS_FILL_BEZIER:
2689 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n",
2690 Title()));
2692 const SimpleTransform transform =
2693 fCurrentView->PenToScreenTransform();
2694 BPoint pts[4];
2695 status_t status;
2696 for (int32 i = 0; i < 4; i++) {
2697 status = link.Read<BPoint>(&(pts[i]));
2698 transform.Apply(&pts[i]);
2700 if (status != B_OK)
2701 break;
2703 drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
2704 break;
2706 case AS_FILL_BEZIER_GRADIENT:
2708 GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n",
2709 Title()));
2711 const SimpleTransform transform =
2712 fCurrentView->PenToScreenTransform();
2713 BPoint pts[4];
2714 for (int32 i = 0; i < 4; i++) {
2715 link.Read<BPoint>(&(pts[i]));
2716 transform.Apply(&pts[i]);
2718 BGradient* gradient;
2719 if (link.ReadGradient(&gradient) != B_OK)
2720 break;
2721 transform.Apply(gradient);
2722 drawingEngine->FillBezier(pts, *gradient);
2723 delete gradient;
2724 break;
2726 case AS_STROKE_ELLIPSE:
2727 case AS_FILL_ELLIPSE:
2729 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n",
2730 Title()));
2732 BRect rect;
2733 if (link.Read<BRect>(&rect) != B_OK)
2734 break;
2736 fCurrentView->PenToScreenTransform().Apply(&rect);
2737 drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
2738 break;
2740 case AS_FILL_ELLIPSE_GRADIENT:
2742 GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n",
2743 Title()));
2745 BRect rect;
2746 link.Read<BRect>(&rect);
2747 BGradient* gradient;
2748 if (link.ReadGradient(&gradient) != B_OK)
2749 break;
2750 const SimpleTransform transform =
2751 fCurrentView->PenToScreenTransform();
2752 transform.Apply(&rect);
2753 transform.Apply(gradient);
2754 drawingEngine->FillEllipse(rect, *gradient);
2755 delete gradient;
2756 break;
2758 case AS_STROKE_ROUNDRECT:
2759 case AS_FILL_ROUNDRECT:
2761 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n",
2762 Title()));
2764 BRect rect;
2765 float xRadius;
2766 float yRadius;
2767 link.Read<BRect>(&rect);
2768 link.Read<float>(&xRadius);
2769 if (link.Read<float>(&yRadius) != B_OK)
2770 break;
2772 fCurrentView->PenToScreenTransform().Apply(&rect);
2773 float scale = fCurrentView->CurrentState()->CombinedScale();
2774 drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale,
2775 code == AS_FILL_ROUNDRECT);
2776 break;
2778 case AS_FILL_ROUNDRECT_GRADIENT:
2780 GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n",
2781 Title()));
2783 BRect rect;
2784 float xrad,yrad;
2785 link.Read<BRect>(&rect);
2786 link.Read<float>(&xrad);
2787 link.Read<float>(&yrad);
2788 BGradient* gradient;
2789 if (link.ReadGradient(&gradient) != B_OK)
2790 break;
2791 const SimpleTransform transform =
2792 fCurrentView->PenToScreenTransform();
2793 transform.Apply(&rect);
2794 transform.Apply(gradient);
2795 drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient);
2796 delete gradient;
2797 break;
2799 case AS_STROKE_TRIANGLE:
2800 case AS_FILL_TRIANGLE:
2802 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n",
2803 Title()));
2805 const SimpleTransform transform =
2806 fCurrentView->PenToScreenTransform();
2807 BPoint pts[3];
2808 BRect rect;
2810 for (int32 i = 0; i < 3; i++) {
2811 link.Read<BPoint>(&(pts[i]));
2812 transform.Apply(&pts[i]);
2815 if (link.Read<BRect>(&rect) != B_OK)
2816 break;
2818 transform.Apply(&rect);
2819 drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
2820 break;
2822 case AS_FILL_TRIANGLE_GRADIENT:
2824 DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n",
2825 Title()));
2827 const SimpleTransform transform =
2828 fCurrentView->PenToScreenTransform();
2829 BPoint pts[3];
2830 BRect rect;
2831 for (int32 i = 0; i < 3; i++) {
2832 link.Read<BPoint>(&(pts[i]));
2833 transform.Apply(&pts[i]);
2835 link.Read<BRect>(&rect);
2836 BGradient* gradient;
2837 if (link.ReadGradient(&gradient) != B_OK)
2838 break;
2839 transform.Apply(&rect);
2840 transform.Apply(gradient);
2841 drawingEngine->FillTriangle(pts, rect, *gradient);
2842 delete gradient;
2843 break;
2845 case AS_STROKE_POLYGON:
2846 case AS_FILL_POLYGON:
2848 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n",
2849 Title()));
2851 BRect polyFrame;
2852 bool isClosed = true;
2853 int32 pointCount;
2855 link.Read<BRect>(&polyFrame);
2856 if (code == AS_STROKE_POLYGON)
2857 link.Read<bool>(&isClosed);
2858 link.Read<int32>(&pointCount);
2860 const SimpleTransform transform =
2861 fCurrentView->PenToScreenTransform();
2862 BPoint* pointList = new(nothrow) BPoint[pointCount];
2863 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2864 for (int32 i = 0; i < pointCount; i++)
2865 transform.Apply(&pointList[i]);
2866 transform.Apply(&polyFrame);
2868 drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2869 code == AS_FILL_POLYGON, isClosed && pointCount > 2);
2871 delete[] pointList;
2872 break;
2874 case AS_FILL_POLYGON_GRADIENT:
2876 DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n",
2877 Title()));
2879 BRect polyFrame;
2880 bool isClosed = true;
2881 int32 pointCount;
2882 link.Read<BRect>(&polyFrame);
2883 link.Read<int32>(&pointCount);
2885 const SimpleTransform transform =
2886 fCurrentView->PenToScreenTransform();
2887 BPoint* pointList = new(nothrow) BPoint[pointCount];
2888 BGradient* gradient;
2889 if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK
2890 && link.ReadGradient(&gradient) == B_OK) {
2891 for (int32 i = 0; i < pointCount; i++)
2892 transform.Apply(&pointList[i]);
2893 transform.Apply(&polyFrame);
2894 transform.Apply(gradient);
2896 drawingEngine->FillPolygon(pointList, pointCount,
2897 polyFrame, *gradient, isClosed && pointCount > 2);
2898 delete gradient;
2900 delete[] pointList;
2901 break;
2903 case AS_STROKE_SHAPE:
2904 case AS_FILL_SHAPE:
2906 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n",
2907 Title()));
2909 BRect shapeFrame;
2910 int32 opCount;
2911 int32 ptCount;
2913 link.Read<BRect>(&shapeFrame);
2914 link.Read<int32>(&opCount);
2915 link.Read<int32>(&ptCount);
2917 uint32* opList = new(nothrow) uint32[opCount];
2918 BPoint* ptList = new(nothrow) BPoint[ptCount];
2919 if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2920 link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2922 // this might seem a bit weird, but under R5, the shapes
2923 // are always offset by the current pen location
2924 BPoint screenOffset
2925 = fCurrentView->CurrentState()->PenLocation();
2926 shapeFrame.OffsetBy(screenOffset);
2928 const SimpleTransform transform =
2929 fCurrentView->PenToScreenTransform();
2930 transform.Apply(&screenOffset);
2931 transform.Apply(&shapeFrame);
2933 drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
2934 ptList, code == AS_FILL_SHAPE, screenOffset,
2935 fCurrentView->Scale());
2938 delete[] opList;
2939 delete[] ptList;
2940 break;
2942 case AS_FILL_SHAPE_GRADIENT:
2944 DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n",
2945 Title()));
2947 BRect shapeFrame;
2948 int32 opCount;
2949 int32 ptCount;
2951 link.Read<BRect>(&shapeFrame);
2952 link.Read<int32>(&opCount);
2953 link.Read<int32>(&ptCount);
2955 uint32* opList = new(nothrow) uint32[opCount];
2956 BPoint* ptList = new(nothrow) BPoint[ptCount];
2957 BGradient* gradient;
2958 if (link.Read(opList, opCount * sizeof(uint32)) == B_OK
2959 && link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK
2960 && link.ReadGradient(&gradient) == B_OK) {
2962 // this might seem a bit weird, but under R5, the shapes
2963 // are always offset by the current pen location
2964 BPoint screenOffset
2965 = fCurrentView->CurrentState()->PenLocation();
2966 shapeFrame.OffsetBy(screenOffset);
2968 const SimpleTransform transform =
2969 fCurrentView->PenToScreenTransform();
2970 transform.Apply(&screenOffset);
2971 transform.Apply(&shapeFrame);
2972 transform.Apply(gradient);
2973 drawingEngine->FillShape(shapeFrame, opCount, opList,
2974 ptCount, ptList, *gradient, screenOffset,
2975 fCurrentView->Scale());
2976 delete gradient;
2979 delete[] opList;
2980 delete[] ptList;
2981 break;
2983 case AS_FILL_REGION:
2985 DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2987 BRegion region;
2988 if (link.ReadRegion(&region) < B_OK)
2989 break;
2991 fCurrentView->PenToScreenTransform().Apply(&region);
2992 drawingEngine->FillRegion(region);
2994 break;
2996 case AS_FILL_REGION_GRADIENT:
2998 DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n",
2999 Title()));
3001 BRegion region;
3002 link.ReadRegion(&region);
3004 BGradient* gradient;
3005 if (link.ReadGradient(&gradient) != B_OK)
3006 break;
3008 const SimpleTransform transform =
3009 fCurrentView->PenToScreenTransform();
3010 transform.Apply(&region);
3011 transform.Apply(gradient);
3012 drawingEngine->FillRegion(region, *gradient);
3013 delete gradient;
3014 break;
3016 case AS_STROKE_LINEARRAY:
3018 DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",
3019 Title()));
3021 // Attached Data:
3022 // 1) int32 Number of lines in the array
3023 // 2) LineArrayData
3025 int32 lineCount;
3026 if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3027 break;
3029 // To speed things up, try to use a stack allocation and only
3030 // fall back to the heap if there are enough lines...
3031 ViewLineArrayInfo* lineData;
3032 const int32 kStackBufferLineDataCount = 64;
3033 ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3034 if (lineCount > kStackBufferLineDataCount) {
3035 lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3036 if (lineData == NULL)
3037 break;
3038 } else
3039 lineData = lineDataStackBuffer;
3041 // Read them all in one go
3042 size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3043 if (link.Read(lineData, dataSize) != B_OK) {
3044 if (lineData != lineDataStackBuffer)
3045 delete[] lineData;
3046 break;
3049 // Convert to screen coords and draw
3050 const SimpleTransform transform =
3051 fCurrentView->PenToScreenTransform();
3052 for (int32 i = 0; i < lineCount; i++) {
3053 transform.Apply(&lineData[i].startPoint);
3054 transform.Apply(&lineData[i].endPoint);
3056 drawingEngine->StrokeLineArray(lineCount, lineData);
3058 if (lineData != lineDataStackBuffer)
3059 delete[] lineData;
3060 break;
3062 case AS_DRAW_STRING:
3063 case AS_DRAW_STRING_WITH_DELTA:
3065 ViewDrawStringInfo info;
3066 if (link.Read<ViewDrawStringInfo>(&info) != B_OK
3067 || info.stringLength <= 0) {
3068 break;
3071 const ssize_t kMaxStackStringSize = 4096;
3072 char stackString[kMaxStackStringSize];
3073 char* string = stackString;
3074 if (info.stringLength >= kMaxStackStringSize) {
3075 // NOTE: Careful, the + 1 is for termination!
3076 string = (char*)malloc((info.stringLength + 1 + 63) / 64 * 64);
3077 if (string == NULL)
3078 break;
3081 escapement_delta* delta = NULL;
3082 if (code == AS_DRAW_STRING_WITH_DELTA) {
3083 // In this case, info.delta will contain valid values.
3084 delta = &info.delta;
3087 if (link.Read(string, info.stringLength) != B_OK) {
3088 if (string != stackString)
3089 free(string);
3090 break;
3092 // Terminate the string, if nothing else, it's important
3093 // for the DTRACE call below...
3094 string[info.stringLength] = '\0';
3096 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s "
3097 "-> %s\n", Title(), fCurrentView->Name(), string));
3099 fCurrentView->PenToScreenTransform().Apply(&info.location);
3100 BPoint penLocation = drawingEngine->DrawString(string,
3101 info.stringLength, info.location, delta);
3103 fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3104 fCurrentView->CurrentState()->SetPenLocation(penLocation);
3106 if (string != stackString)
3107 free(string);
3108 break;
3110 case AS_DRAW_STRING_WITH_OFFSETS:
3112 int32 stringLength;
3113 if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
3114 break;
3116 int32 glyphCount;
3117 if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
3118 break;
3120 const ssize_t kMaxStackStringSize = 512;
3121 char stackString[kMaxStackStringSize];
3122 char* string = stackString;
3123 BPoint stackLocations[kMaxStackStringSize];
3124 BPoint* locations = stackLocations;
3125 MemoryDeleter stringDeleter;
3126 MemoryDeleter locationsDeleter;
3127 if (stringLength >= kMaxStackStringSize) {
3128 // NOTE: Careful, the + 1 is for termination!
3129 string = (char*)malloc((stringLength + 1 + 63) / 64 * 64);
3130 if (string == NULL)
3131 break;
3132 stringDeleter.SetTo(string);
3134 if (glyphCount > kMaxStackStringSize) {
3135 locations = (BPoint*)malloc(
3136 ((glyphCount * sizeof(BPoint)) + 63) / 64 * 64);
3137 if (locations == NULL)
3138 break;
3139 locationsDeleter.SetTo(locations);
3142 if (link.Read(string, stringLength) != B_OK)
3143 break;
3144 // Count UTF8 glyphs and make sure we have enough locations
3145 if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
3146 break;
3147 if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
3148 break;
3149 // Terminate the string, if nothing else, it's important
3150 // for the DTRACE call below...
3151 string[stringLength] = '\0';
3153 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s "
3154 "-> %s\n", Title(), fCurrentView->Name(), string));
3156 const SimpleTransform transform =
3157 fCurrentView->PenToScreenTransform();
3158 for (int32 i = 0; i < glyphCount; i++)
3159 transform.Apply(&locations[i]);
3161 BPoint penLocation = drawingEngine->DrawString(string,
3162 stringLength, locations);
3164 fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3165 fCurrentView->CurrentState()->SetPenLocation(penLocation);
3167 break;
3170 case AS_VIEW_DRAW_PICTURE:
3172 int32 token;
3173 link.Read<int32>(&token);
3175 BPoint where;
3176 if (link.Read<BPoint>(&where) == B_OK) {
3177 ServerPicture* picture = App()->GetPicture(token);
3178 if (picture != NULL) {
3179 // Setting the drawing origin outside of the
3180 // state makes sure that everything the picture
3181 // does is relative to the global picture offset.
3182 fCurrentView->PushState();
3183 fCurrentView->SetDrawingOrigin(where);
3185 fCurrentView->PushState();
3186 picture->Play(fCurrentView);
3187 fCurrentView->PopState();
3189 fCurrentView->PopState();
3191 picture->ReleaseReference();
3194 break;
3197 case AS_VIEW_END_LAYER:
3199 DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n",
3200 Title()));
3202 fCurrentView->BlendAllLayers();
3203 fCurrentView->SetPicture(NULL);
3204 fCurrentView->CurrentState()->SetDrawingModeLocked(false);
3205 break;
3208 default:
3209 BString codeString;
3210 string_for_message_code(code, codeString);
3211 debug_printf("ServerWindow %s received unexpected code: %s\n",
3212 Title(), codeString.String());
3214 if (link.NeedsReply()) {
3215 // the client is now blocking and waiting for a reply!
3216 fLink.StartMessage(B_ERROR);
3217 fLink.Flush();
3219 break;
3222 drawingEngine->UnlockParallelAccess();
3226 bool
3227 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link)
3229 ServerPicture* picture = fCurrentView->Picture();
3230 if (picture == NULL)
3231 return false;
3233 switch (code) {
3234 case AS_VIEW_SET_ORIGIN:
3236 float x, y;
3237 link.Read<float>(&x);
3238 link.Read<float>(&y);
3240 picture->WriteSetOrigin(BPoint(x, y));
3241 break;
3244 case AS_VIEW_INVERT_RECT:
3246 BRect rect;
3247 link.Read<BRect>(&rect);
3248 picture->WriteInvertRect(rect);
3249 break;
3252 case AS_VIEW_PUSH_STATE:
3254 picture->WritePushState();
3255 break;
3258 case AS_VIEW_POP_STATE:
3260 picture->WritePopState();
3261 break;
3264 case AS_VIEW_SET_DRAWING_MODE:
3266 int8 drawingMode;
3267 link.Read<int8>(&drawingMode);
3269 picture->WriteSetDrawingMode((drawing_mode)drawingMode);
3271 fCurrentView->CurrentState()->SetDrawingMode(
3272 (drawing_mode)drawingMode);
3273 fWindow->GetDrawingEngine()->SetDrawingMode(
3274 (drawing_mode)drawingMode);
3275 break;
3278 case AS_VIEW_SET_PEN_LOC:
3280 BPoint location;
3281 link.Read<BPoint>(&location);
3282 picture->WriteSetPenLocation(location);
3284 fCurrentView->CurrentState()->SetPenLocation(location);
3285 break;
3287 case AS_VIEW_SET_PEN_SIZE:
3289 float penSize;
3290 link.Read<float>(&penSize);
3291 picture->WriteSetPenSize(penSize);
3293 fCurrentView->CurrentState()->SetPenSize(penSize);
3294 fWindow->GetDrawingEngine()->SetPenSize(
3295 fCurrentView->CurrentState()->PenSize());
3296 break;
3299 case AS_VIEW_SET_LINE_MODE:
3302 ViewSetLineModeInfo info;
3303 link.Read<ViewSetLineModeInfo>(&info);
3305 picture->WriteSetLineMode(info.lineCap, info.lineJoin,
3306 info.miterLimit);
3308 fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
3309 fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
3310 fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
3312 fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
3313 info.lineJoin, info.miterLimit);
3314 break;
3316 case AS_VIEW_SET_SCALE:
3318 float scale;
3319 if (link.Read<float>(&scale) != B_OK)
3320 break;
3322 picture->WriteSetScale(scale);
3324 fCurrentView->SetScale(scale);
3325 _UpdateDrawState(fCurrentView);
3326 break;
3328 case AS_VIEW_SET_TRANSFORM:
3330 BAffineTransform transform;
3331 if (link.Read<BAffineTransform>(&transform) != B_OK)
3332 break;
3334 picture->WriteSetTransform(transform);
3335 break;
3338 case AS_VIEW_AFFINE_TRANSLATE:
3340 double x, y;
3341 link.Read<double>(&x);
3342 link.Read<double>(&y);
3344 picture->WriteTranslateBy(x, y);
3345 break;
3348 case AS_VIEW_AFFINE_SCALE:
3350 double x, y;
3351 link.Read<double>(&x);
3352 link.Read<double>(&y);
3354 picture->WriteScaleBy(x, y);
3355 break;
3358 case AS_VIEW_AFFINE_ROTATE:
3360 double angleRadians;
3361 link.Read<double>(&angleRadians);
3363 picture->WriteRotateBy(angleRadians);
3364 break;
3368 case AS_VIEW_SET_PATTERN:
3370 pattern pat;
3371 link.Read(&pat, sizeof(pattern));
3372 picture->WriteSetPattern(pat);
3373 break;
3376 case AS_VIEW_SET_FONT_STATE:
3378 picture->SetFontFromLink(link);
3379 break;
3382 case AS_FILL_RECT:
3383 case AS_STROKE_RECT:
3385 BRect rect;
3386 link.Read<BRect>(&rect);
3388 picture->WriteDrawRect(rect, code == AS_FILL_RECT);
3389 break;
3392 case AS_FILL_REGION:
3394 // There is no B_PIC_FILL_REGION op, we have to
3395 // implement it using B_PIC_FILL_RECT
3396 BRegion region;
3397 if (link.ReadRegion(&region) < B_OK)
3398 break;
3399 for (int32 i = 0; i < region.CountRects(); i++)
3400 picture->WriteDrawRect(region.RectAt(i), true);
3401 break;
3404 case AS_STROKE_ROUNDRECT:
3405 case AS_FILL_ROUNDRECT:
3407 BRect rect;
3408 link.Read<BRect>(&rect);
3410 BPoint radii;
3411 link.Read<float>(&radii.x);
3412 link.Read<float>(&radii.y);
3414 picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
3415 break;
3418 case AS_STROKE_ELLIPSE:
3419 case AS_FILL_ELLIPSE:
3421 BRect rect;
3422 link.Read<BRect>(&rect);
3423 picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
3424 break;
3427 case AS_STROKE_ARC:
3428 case AS_FILL_ARC:
3430 BRect rect;
3431 link.Read<BRect>(&rect);
3432 float startTheta, arcTheta;
3433 link.Read<float>(&startTheta);
3434 link.Read<float>(&arcTheta);
3436 BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
3437 BPoint center = rect.LeftTop() + radii;
3439 picture->WriteDrawArc(center, radii, startTheta, arcTheta,
3440 code == AS_FILL_ARC);
3441 break;
3444 case AS_STROKE_TRIANGLE:
3445 case AS_FILL_TRIANGLE:
3447 // There is no B_PIC_FILL/STROKE_TRIANGLE op,
3448 // we implement it using B_PIC_FILL/STROKE_POLYGON
3449 BPoint points[3];
3451 for (int32 i = 0; i < 3; i++) {
3452 link.Read<BPoint>(&(points[i]));
3455 BRect rect;
3456 link.Read<BRect>(&rect);
3458 picture->WriteDrawPolygon(3, points,
3459 true, code == AS_FILL_TRIANGLE);
3460 break;
3462 case AS_STROKE_POLYGON:
3463 case AS_FILL_POLYGON:
3465 BRect polyFrame;
3466 bool isClosed = true;
3467 int32 pointCount;
3468 const bool fill = (code == AS_FILL_POLYGON);
3470 link.Read<BRect>(&polyFrame);
3471 if (code == AS_STROKE_POLYGON)
3472 link.Read<bool>(&isClosed);
3473 link.Read<int32>(&pointCount);
3475 BPoint* pointList = new(nothrow) BPoint[pointCount];
3476 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
3477 picture->WriteDrawPolygon(pointCount, pointList,
3478 isClosed && pointCount > 2, fill);
3480 delete[] pointList;
3481 break;
3484 case AS_STROKE_BEZIER:
3485 case AS_FILL_BEZIER:
3487 BPoint points[4];
3488 for (int32 i = 0; i < 4; i++) {
3489 link.Read<BPoint>(&(points[i]));
3491 picture->WriteDrawBezier(points, code == AS_FILL_BEZIER);
3492 break;
3495 case AS_STROKE_LINE:
3497 ViewStrokeLineInfo info;
3498 link.Read<ViewStrokeLineInfo>(&info);
3500 picture->WriteStrokeLine(info.startPoint, info.endPoint);
3501 break;
3504 case AS_STROKE_LINEARRAY:
3506 int32 lineCount;
3507 if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3508 break;
3510 // To speed things up, try to use a stack allocation and only
3511 // fall back to the heap if there are enough lines...
3512 ViewLineArrayInfo* lineData;
3513 const int32 kStackBufferLineDataCount = 64;
3514 ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3515 if (lineCount > kStackBufferLineDataCount) {
3516 lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3517 if (lineData == NULL)
3518 break;
3519 } else
3520 lineData = lineDataStackBuffer;
3522 // Read them all in one go
3523 size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3524 if (link.Read(lineData, dataSize) != B_OK) {
3525 if (lineData != lineDataStackBuffer)
3526 delete[] lineData;
3527 break;
3530 picture->WritePushState();
3532 for (int32 i = 0; i < lineCount; i++) {
3533 picture->WriteSetHighColor(lineData[i].color);
3534 picture->WriteStrokeLine(lineData[i].startPoint,
3535 lineData[i].endPoint);
3538 picture->WritePopState();
3540 if (lineData != lineDataStackBuffer)
3541 delete[] lineData;
3542 break;
3545 case AS_VIEW_SET_LOW_COLOR:
3546 case AS_VIEW_SET_HIGH_COLOR:
3548 rgb_color color;
3549 link.Read(&color, sizeof(rgb_color));
3551 if (code == AS_VIEW_SET_HIGH_COLOR) {
3552 picture->WriteSetHighColor(color);
3553 fCurrentView->CurrentState()->SetHighColor(color);
3554 fWindow->GetDrawingEngine()->SetHighColor(color);
3555 } else {
3556 picture->WriteSetLowColor(color);
3557 fCurrentView->CurrentState()->SetLowColor(color);
3558 fWindow->GetDrawingEngine()->SetLowColor(color);
3560 } break;
3562 case AS_DRAW_STRING:
3563 case AS_DRAW_STRING_WITH_DELTA:
3565 ViewDrawStringInfo info;
3566 if (link.Read<ViewDrawStringInfo>(&info) != B_OK)
3567 break;
3569 char* string = (char*)malloc(info.stringLength + 1);
3570 if (string == NULL)
3571 break;
3573 if (code != AS_DRAW_STRING_WITH_DELTA) {
3574 // In this case, info.delta will NOT contain valid values.
3575 info.delta = (escapement_delta){ 0, 0 };
3578 if (link.Read(string, info.stringLength) != B_OK) {
3579 free(string);
3580 break;
3582 // Terminate the string
3583 string[info.stringLength] = '\0';
3585 picture->WriteDrawString(info.location, string, info.stringLength,
3586 info.delta);
3588 free(string);
3589 break;
3592 case AS_STROKE_SHAPE:
3593 case AS_FILL_SHAPE:
3595 BRect shapeFrame;
3596 int32 opCount;
3597 int32 ptCount;
3599 link.Read<BRect>(&shapeFrame);
3600 link.Read<int32>(&opCount);
3601 link.Read<int32>(&ptCount);
3603 uint32* opList = new(std::nothrow) uint32[opCount];
3604 BPoint* ptList = new(std::nothrow) BPoint[ptCount];
3605 if (opList != NULL && ptList != NULL
3606 && link.Read(opList, opCount * sizeof(uint32)) >= B_OK
3607 && link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
3608 // This might seem a bit weird, but under BeOS, the shapes
3609 // are always offset by the current pen location
3610 BPoint penLocation
3611 = fCurrentView->CurrentState()->PenLocation();
3612 for (int32 i = 0; i < ptCount; i++) {
3613 ptList[i] += penLocation;
3615 const bool fill = (code == AS_FILL_SHAPE);
3616 picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill);
3619 delete[] opList;
3620 delete[] ptList;
3621 break;
3624 case AS_VIEW_DRAW_BITMAP:
3626 ViewDrawBitmapInfo info;
3627 link.Read<ViewDrawBitmapInfo>(&info);
3629 ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken);
3630 if (bitmap == NULL)
3631 break;
3633 picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
3634 bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
3635 bitmap->ColorSpace(), info.options, bitmap->Bits(),
3636 bitmap->BitsLength());
3638 bitmap->ReleaseReference();
3639 break;
3642 case AS_VIEW_DRAW_PICTURE:
3644 int32 token;
3645 link.Read<int32>(&token);
3647 BPoint where;
3648 if (link.Read<BPoint>(&where) == B_OK) {
3649 ServerPicture* pictureToDraw = App()->GetPicture(token);
3650 if (pictureToDraw != NULL) {
3651 // We need to make a copy of the picture, since it can
3652 // change after it has been drawn
3653 ServerPicture* copy = App()->CreatePicture(pictureToDraw);
3654 picture->NestPicture(copy);
3655 picture->WriteDrawPicture(where, copy->Token());
3657 pictureToDraw->ReleaseReference();
3660 break;
3663 case AS_VIEW_SET_CLIP_REGION:
3665 int32 rectCount;
3666 status_t status = link.Read<int32>(&rectCount);
3667 // a negative count means no
3668 // region for the current draw state,
3669 // but an *empty* region is actually valid!
3670 // even if it means no drawing is allowed
3672 if (status < B_OK)
3673 break;
3675 if (rectCount >= 0) {
3676 // we are supposed to set the clipping region
3677 BRegion region;
3678 if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
3679 break;
3680 picture->WriteSetClipping(region);
3681 } else {
3682 // we are supposed to clear the clipping region
3683 picture->WriteClearClipping();
3685 break;
3688 case AS_VIEW_CLIP_TO_PICTURE:
3690 int32 pictureToken;
3691 BPoint where;
3692 bool inverse = false;
3694 link.Read<int32>(&pictureToken);
3695 if (pictureToken < 0)
3696 break;
3698 link.Read<BPoint>(&where);
3699 if (link.Read<bool>(&inverse) != B_OK)
3700 break;
3702 ServerPicture* picture = fServerApp->GetPicture(pictureToken);
3703 if (picture == NULL)
3704 break;
3706 picture->WriteClipToPicture(picture->Token(), where, inverse);
3708 picture->ReleaseReference();
3709 break;
3712 case AS_VIEW_CLIP_TO_RECT:
3714 bool inverse;
3715 BRect rect;
3716 link.Read<bool>(&inverse);
3717 link.Read<BRect>(&rect);
3718 picture->WriteClipToRect(rect, inverse);
3720 break;
3723 case AS_VIEW_CLIP_TO_SHAPE:
3725 bool inverse;
3726 link.Read<bool>(&inverse);
3728 shape_data shape;
3729 link.Read<int32>(&shape.opCount);
3730 link.Read<int32>(&shape.ptCount);
3731 shape.opSize = shape.opCount * sizeof(uint32);
3732 shape.ptSize = shape.ptCount * sizeof(BPoint);
3733 shape.opList = new(nothrow) uint32[shape.opCount];
3734 shape.ptList = new(nothrow) BPoint[shape.ptCount];
3735 if (link.Read(shape.opList, shape.opSize) >= B_OK
3736 && link.Read(shape.ptList, shape.ptSize) >= B_OK) {
3737 picture->WriteClipToShape(shape.opCount, shape.opList,
3738 shape.ptCount, shape.ptList, inverse);
3741 delete[] shape.opList;
3742 delete[] shape.ptList;
3743 break;
3746 case AS_VIEW_BEGIN_PICTURE:
3748 ServerPicture* newPicture = App()->CreatePicture();
3749 if (newPicture != NULL) {
3750 newPicture->PushPicture(picture);
3751 newPicture->SyncState(fCurrentView);
3752 fCurrentView->SetPicture(newPicture);
3754 break;
3757 case AS_VIEW_APPEND_TO_PICTURE:
3759 int32 token;
3760 link.Read<int32>(&token);
3762 ServerPicture* appendPicture = App()->GetPicture(token);
3763 if (appendPicture != NULL) {
3764 //picture->SyncState(fCurrentView);
3765 appendPicture->AppendPicture(picture);
3768 fCurrentView->SetPicture(appendPicture);
3770 if (appendPicture != NULL)
3771 appendPicture->ReleaseReference();
3772 break;
3775 case AS_VIEW_END_PICTURE:
3777 ServerPicture* poppedPicture = picture->PopPicture();
3778 fCurrentView->SetPicture(poppedPicture);
3779 if (poppedPicture != NULL)
3780 poppedPicture->ReleaseReference();
3782 fLink.StartMessage(B_OK);
3783 fLink.Attach<int32>(picture->Token());
3784 fLink.Flush();
3785 return true;
3788 case AS_VIEW_BEGIN_LAYER:
3790 uint8 opacity;
3791 link.Read<uint8>(&opacity);
3793 Layer* layer = dynamic_cast<Layer*>(picture);
3794 if (layer == NULL)
3795 break;
3797 Layer* nextLayer = new(std::nothrow) Layer(opacity);
3798 if (nextLayer == NULL)
3799 break;
3801 if (opacity != 255) {
3802 fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
3803 fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
3804 B_ALPHA_COMPOSITE);
3805 fCurrentView->CurrentState()->SetDrawingModeLocked(true);
3808 nextLayer->PushLayer(layer);
3809 fCurrentView->SetPicture(nextLayer);
3810 break;
3813 case AS_VIEW_END_LAYER:
3815 Layer* layer = dynamic_cast<Layer*>(picture);
3816 if (layer == NULL)
3817 break;
3819 Layer* previousLayer = layer->PopLayer();
3820 if (previousLayer == NULL) {
3821 // End last layer
3822 return false;
3824 fCurrentView->SetPicture(previousLayer);
3826 previousLayer->WriteBlendLayer(layer);
3827 break;
3831 case AS_VIEW_SET_BLENDING_MODE:
3833 ViewBlendingModeInfo info;
3834 link.Read<ViewBlendingModeInfo>(&info);
3836 picture->BeginOp(B_PIC_SET_BLENDING_MODE);
3837 picture->AddInt16((int16)info.sourceAlpha);
3838 picture->AddInt16((int16)info.alphaFunction);
3839 picture->EndOp();
3841 fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
3842 info.alphaFunction);
3843 fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
3844 info.alphaFunction);
3845 break;
3847 default:
3848 return false;
3851 if (link.NeedsReply()) {
3852 fLink.StartMessage(B_ERROR);
3853 fLink.Flush();
3855 return true;
3859 /*! \brief Message-dispatching loop for the ServerWindow
3861 Watches the ServerWindow's message port and dispatches as necessary
3863 void
3864 ServerWindow::_MessageLooper()
3866 // Send a reply to our window - it is expecting fMessagePort
3867 // port and some other info.
3869 fLink.StartMessage(B_OK);
3870 fLink.Attach<port_id>(fMessagePort);
3872 int32 minWidth, maxWidth, minHeight, maxHeight;
3873 fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
3875 fLink.Attach<BRect>(fWindow->Frame());
3876 fLink.Attach<float>((float)minWidth);
3877 fLink.Attach<float>((float)maxWidth);
3878 fLink.Attach<float>((float)minHeight);
3879 fLink.Attach<float>((float)maxHeight);
3880 fLink.Flush();
3882 BPrivate::LinkReceiver& receiver = fLink.Receiver();
3883 bool quitLoop = false;
3885 while (!quitLoop) {
3886 //STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
3887 // fMessagePort));
3889 int32 code;
3890 status_t status = receiver.GetNextMessage(code);
3891 if (status != B_OK) {
3892 // that shouldn't happen, it's our port
3893 printf("Someone deleted our message port!\n");
3895 // try to let our client die happily
3896 NotifyQuitRequested();
3897 break;
3900 #ifdef PROFILE_MESSAGE_LOOP
3901 bigtime_t start = system_time();
3902 #endif
3904 Lock();
3906 #ifdef PROFILE_MESSAGE_LOOP
3907 bigtime_t diff = system_time() - start;
3908 if (diff > 10000) {
3909 printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n",
3910 Title(), diff);
3912 #endif
3914 int32 messagesProcessed = 0;
3915 bigtime_t processingStart = system_time();
3916 bool lockedDesktopSingleWindow = false;
3918 while (true) {
3919 if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
3920 // this means the client has been killed
3921 DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message "
3922 "code\n", Title()));
3924 if (code == AS_DELETE_WINDOW) {
3925 fLink.StartMessage(B_OK);
3926 fLink.Flush();
3929 if (lockedDesktopSingleWindow)
3930 fDesktop->UnlockSingleWindow();
3932 quitLoop = true;
3934 // ServerWindow's destructor takes care of pulling this object
3935 // off the desktop.
3936 ASSERT(fWindow->IsHidden());
3937 break;
3940 // Acquire the appropriate lock
3941 bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code);
3942 if (needsAllWindowsLocked) {
3943 // We may already still hold the read-lock from the previous
3944 // inner-loop iteration.
3945 if (lockedDesktopSingleWindow) {
3946 fDesktop->UnlockSingleWindow();
3947 lockedDesktopSingleWindow = false;
3949 fDesktop->LockAllWindows();
3950 } else {
3951 // We never keep the write-lock across inner-loop iterations,
3952 // so there is nothing else to do besides read-locking unless
3953 // we already have the read-lock from the previous iteration.
3954 if (!lockedDesktopSingleWindow) {
3955 fDesktop->LockSingleWindow();
3956 lockedDesktopSingleWindow = true;
3960 if (atomic_and(&fRedrawRequested, 0) != 0) {
3961 #ifdef PROFILE_MESSAGE_LOOP
3962 bigtime_t redrawStart = system_time();
3963 #endif
3964 fWindow->RedrawDirtyRegion();
3965 #ifdef PROFILE_MESSAGE_LOOP
3966 diff = system_time() - redrawStart;
3967 atomic_add(&sRedrawProcessingTime.count, 1);
3968 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
3969 atomic_add64(&sRedrawProcessingTime.time, diff);
3970 # else
3971 sRedrawProcessingTime.time += diff;
3972 # endif
3973 #endif
3976 #ifdef PROFILE_MESSAGE_LOOP
3977 bigtime_t dispatchStart = system_time();
3978 #endif
3979 _DispatchMessage(code, receiver);
3981 #ifdef PROFILE_MESSAGE_LOOP
3982 if (code >= 0 && code < AS_LAST_CODE) {
3983 diff = system_time() - dispatchStart;
3984 atomic_add(&sMessageProfile[code].count, 1);
3985 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
3986 atomic_add64(&sMessageProfile[code].time, diff);
3987 #else
3988 sMessageProfile[code].time += diff;
3989 #endif
3990 if (diff > 10000) {
3991 printf("ServerWindow %s: message %" B_PRId32 " took %"
3992 B_PRId64 " usecs\n", Title(), code, diff);
3995 #endif
3997 if (needsAllWindowsLocked)
3998 fDesktop->UnlockAllWindows();
4000 // Only process up to 70 waiting messages at once (we have the
4001 // Desktop locked), but don't hold the lock longer than 10 ms
4002 if (!receiver.HasMessages() || ++messagesProcessed > 70
4003 || system_time() - processingStart > 10000) {
4004 if (lockedDesktopSingleWindow)
4005 fDesktop->UnlockSingleWindow();
4006 break;
4009 // next message
4010 status_t status = receiver.GetNextMessage(code);
4011 if (status != B_OK) {
4012 // that shouldn't happen, it's our port
4013 printf("Someone deleted our message port!\n");
4014 if (lockedDesktopSingleWindow)
4015 fDesktop->UnlockSingleWindow();
4017 // try to let our client die happily
4018 NotifyQuitRequested();
4019 break;
4023 Unlock();
4026 // We were asked to quit the message loop - either on request or because of
4027 // an error.
4028 Quit();
4029 // does not return
4033 void
4034 ServerWindow::ScreenChanged(const BMessage* message)
4036 SendMessageToClient(message);
4038 if (fDirectWindowInfo != NULL && fDirectWindowInfo->IsFullScreen())
4039 _ResizeToFullScreen();
4043 status_t
4044 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
4046 if (target == B_NULL_TOKEN)
4047 target = fClientToken;
4049 BMessenger reply;
4050 BMessage::Private messagePrivate((BMessage*)msg);
4051 return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
4052 0, false, reply);
4056 Window*
4057 ServerWindow::MakeWindow(BRect frame, const char* name,
4058 window_look look, window_feel feel, uint32 flags, uint32 workspace)
4060 // The non-offscreen ServerWindow uses the DrawingEngine instance from
4061 // the desktop.
4062 return new(std::nothrow) ::Window(frame, name, look, feel, flags,
4063 workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
4067 void
4068 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
4070 ASSERT_MULTI_LOCKED(fDesktop->WindowLocker());
4072 if (fDirectWindowInfo == NULL)
4073 return;
4075 STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = "
4076 "%" B_PRId32 ")\n", bufferState, driverState));
4078 status_t status = fDirectWindowInfo->SetState(
4079 (direct_buffer_state)bufferState, (direct_driver_state)driverState,
4080 fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(),
4081 fWindow->VisibleContentRegion());
4083 if (status != B_OK) {
4084 char errorString[256];
4085 snprintf(errorString, sizeof(errorString),
4086 "%s killed for a problem in DirectConnected(): %s",
4087 App()->Signature(), strerror(status));
4088 syslog(LOG_ERR, errorString);
4090 // The client application didn't release the semaphore
4091 // within the given timeout. Or something else went wrong.
4092 // Deleting this member should make it crash.
4093 delete fDirectWindowInfo;
4094 fDirectWindowInfo = NULL;
4095 } else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START)
4096 fIsDirectlyAccessing = true;
4097 else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
4098 fIsDirectlyAccessing = false;
4102 void
4103 ServerWindow::_SetCurrentView(View* view)
4105 if (fCurrentView == view)
4106 return;
4108 fCurrentView = view;
4109 fCurrentDrawingRegionValid = false;
4110 _UpdateDrawState(fCurrentView);
4112 #if 0
4113 #if DELAYED_BACKGROUND_CLEARING
4114 if (fCurrentView && fCurrentView->IsBackgroundDirty()
4115 && fWindow->InUpdate()) {
4116 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
4117 if (drawingEngine->LockParallelAccess()) {
4118 fWindow->GetEffectiveDrawingRegion(fCurrentView,
4119 fCurrentDrawingRegion);
4120 fCurrentDrawingRegionValid = true;
4121 BRegion dirty(fCurrentDrawingRegion);
4123 BRegion content;
4124 fWindow->GetContentRegion(&content);
4126 fCurrentView->Draw(drawingEngine, &dirty, &content, false);
4128 drawingEngine->UnlockParallelAccess();
4131 #endif
4132 #endif // 0
4136 void
4137 ServerWindow::_UpdateDrawState(View* view)
4139 // switch the drawing state
4140 // TODO: is it possible to scroll a view while it
4141 // is being drawn? probably not... otherwise the
4142 // "offsets" passed below would need to be updated again
4143 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
4144 if (view != NULL && drawingEngine != NULL) {
4145 BPoint leftTop(0, 0);
4146 if (view->GetAlphaMask() != NULL) {
4147 view->LocalToScreenTransform().Apply(&leftTop);
4148 view->GetAlphaMask()->SetCanvasGeometry(leftTop, view->Bounds());
4149 leftTop = BPoint(0, 0);
4151 view->PenToScreenTransform().Apply(&leftTop);
4152 drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y);
4157 void
4158 ServerWindow::_UpdateCurrentDrawingRegion()
4160 if (!fCurrentDrawingRegionValid
4161 || fWindow->DrawingRegionChanged(fCurrentView)) {
4162 fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion);
4163 fCurrentDrawingRegionValid = true;
4168 bool
4169 ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const
4171 switch (code) {
4172 case AS_SET_WINDOW_TITLE:
4173 case AS_ADD_TO_SUBSET:
4174 case AS_REMOVE_FROM_SUBSET:
4175 case AS_VIEW_CREATE_ROOT:
4176 case AS_VIEW_CREATE:
4177 case AS_SEND_BEHIND:
4178 case AS_SET_LOOK:
4179 case AS_SET_FEEL:
4180 case AS_SET_FLAGS:
4181 case AS_SET_WORKSPACES:
4182 case AS_WINDOW_MOVE:
4183 case AS_WINDOW_RESIZE:
4184 case AS_SET_SIZE_LIMITS:
4185 case AS_SYSTEM_FONT_CHANGED:
4186 case AS_SET_DECORATOR_SETTINGS:
4187 case AS_GET_MOUSE:
4188 case AS_DIRECT_WINDOW_SET_FULLSCREEN:
4189 // case AS_VIEW_SET_EVENT_MASK:
4190 // case AS_VIEW_SET_MOUSE_EVENT_MASK:
4191 case AS_TALK_TO_DESKTOP_LISTENER:
4192 return true;
4193 default:
4194 return false;
4199 void
4200 ServerWindow::_ResizeToFullScreen()
4202 BRect screenFrame;
4205 AutoReadLocker _(fDesktop->ScreenLocker());
4206 const Screen* screen = fWindow->Screen();
4207 if (screen == NULL)
4208 return;
4210 screenFrame = fWindow->Screen()->Frame();
4213 fDesktop->MoveWindowBy(fWindow,
4214 screenFrame.left - fWindow->Frame().left,
4215 screenFrame.top - fWindow->Frame().top);
4216 fDesktop->ResizeWindowBy(fWindow,
4217 screenFrame.Width() - fWindow->Frame().Width(),
4218 screenFrame.Height() - fWindow->Frame().Height());
4222 status_t
4223 ServerWindow::_EnableDirectWindowMode()
4225 if (fDirectWindowInfo != NULL) {
4226 // already in direct window mode
4227 return B_ERROR;
4230 if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
4231 // direct window mode not supported
4232 return B_UNSUPPORTED;
4235 fDirectWindowInfo = new(std::nothrow) DirectWindowInfo;
4236 if (fDirectWindowInfo == NULL)
4237 return B_NO_MEMORY;
4239 status_t status = fDirectWindowInfo->InitCheck();
4240 if (status != B_OK) {
4241 delete fDirectWindowInfo;
4242 fDirectWindowInfo = NULL;
4244 return status;
4247 return B_OK;
4251 void
4252 ServerWindow::_DirectWindowSetFullScreen(bool enable)
4254 window_feel feel = kWindowScreenFeel;
4256 if (enable) {
4257 fDesktop->HWInterface()->SetCursorVisible(false);
4259 fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel());
4260 _ResizeToFullScreen();
4261 } else {
4262 const BRect& originalFrame = fDirectWindowInfo->OriginalFrame();
4264 fDirectWindowInfo->DisableFullScreen();
4266 // Resize window back to its original size
4267 fDesktop->MoveWindowBy(fWindow,
4268 originalFrame.left - fWindow->Frame().left,
4269 originalFrame.top - fWindow->Frame().top);
4270 fDesktop->ResizeWindowBy(fWindow,
4271 originalFrame.Width() - fWindow->Frame().Width(),
4272 originalFrame.Height() - fWindow->Frame().Height());
4274 fDesktop->HWInterface()->SetCursorVisible(true);
4277 fDesktop->SetWindowFeel(fWindow, feel);