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