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 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 */ 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 */ 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 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* 303 ServerWindow::Window() const 304 { 305 if (!fWindowAddedToDesktop) 306 return NULL; 307 308 return fWindow.Get(); 309 } 310 311 312 void 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 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 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 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 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 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 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 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 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 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 493 ServerWindow::ResyncDrawState() 494 { 495 _UpdateDrawState(fCurrentView); 496 } 497 498 499 View* 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 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 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 fWindow->GetDrawingEngine()->SetFont( 1304 fCurrentView->CurrentState()); 1305 break; 1306 } 1307 case AS_VIEW_GET_STATE: 1308 { 1309 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: " 1310 "View name: %s\n", fTitle, fCurrentView->Name())); 1311 1312 fLink.StartMessage(B_OK); 1313 1314 // attach state data 1315 fCurrentView->CurrentState()->WriteToLink(fLink.Sender()); 1316 fLink.Flush(); 1317 break; 1318 } 1319 case AS_VIEW_SET_EVENT_MASK: 1320 { 1321 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: " 1322 "View name: %s\n", fTitle, fCurrentView->Name())); 1323 uint32 eventMask, options; 1324 1325 link.Read<uint32>(&eventMask); 1326 if (link.Read<uint32>(&options) == B_OK) { 1327 fCurrentView->SetEventMask(eventMask, options); 1328 1329 fDesktop->UnlockSingleWindow(); 1330 // TODO: possible deadlock! 1331 if (eventMask != 0 || options != 0) { 1332 fDesktop->EventDispatcher().AddListener(EventTarget(), 1333 fCurrentView->Token(), eventMask, options); 1334 } else { 1335 fDesktop->EventDispatcher().RemoveListener(EventTarget(), 1336 fCurrentView->Token()); 1337 } 1338 fDesktop->LockSingleWindow(); 1339 } 1340 break; 1341 } 1342 case AS_VIEW_SET_MOUSE_EVENT_MASK: 1343 { 1344 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: " 1345 "View name: %s\n", fTitle, fCurrentView->Name())); 1346 uint32 eventMask, options; 1347 1348 link.Read<uint32>(&eventMask); 1349 if (link.Read<uint32>(&options) == B_OK) { 1350 fDesktop->UnlockSingleWindow(); 1351 // TODO: possible deadlock 1352 if (eventMask != 0 || options != 0) { 1353 if (options & B_LOCK_WINDOW_FOCUS) 1354 fDesktop->SetFocusLocked(fWindow.Get()); 1355 fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(), 1356 fCurrentView->Token(), eventMask, options); 1357 } else { 1358 fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(), 1359 fCurrentView->Token()); 1360 } 1361 fDesktop->LockSingleWindow(); 1362 } 1363 1364 // TODO: support B_LOCK_WINDOW_FOCUS option in Desktop 1365 break; 1366 } 1367 case AS_VIEW_MOVE_TO: 1368 { 1369 float x, y; 1370 link.Read<float>(&x); 1371 if (link.Read<float>(&y) != B_OK) 1372 break; 1373 1374 DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: " 1375 "%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y)); 1376 1377 float offsetX = x - fCurrentView->Frame().left; 1378 float offsetY = y - fCurrentView->Frame().top; 1379 1380 BRegion dirty; 1381 fCurrentView->MoveBy(offsetX, offsetY, &dirty); 1382 1383 // TODO: think about how to avoid this hack: 1384 // the parent clipping needs to be updated, it is not 1385 // done in MoveBy() since it would cause 1386 // too much computations when children are resized because 1387 // follow modes 1388 if (View* parent = fCurrentView->Parent()) 1389 parent->RebuildClipping(false); 1390 1391 fWindow->MarkContentDirty(dirty); 1392 break; 1393 } 1394 case AS_VIEW_RESIZE_TO: 1395 { 1396 float newWidth, newHeight; 1397 link.Read<float>(&newWidth); 1398 if (link.Read<float>(&newHeight) != B_OK) 1399 break; 1400 1401 DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: " 1402 "%s, width: %.1f, height: %.1f\n", fTitle, 1403 fCurrentView->Name(), newWidth, newHeight)); 1404 1405 float deltaWidth = newWidth - fCurrentView->Frame().Width(); 1406 float deltaHeight = newHeight - fCurrentView->Frame().Height(); 1407 1408 BRegion dirty; 1409 fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty); 1410 1411 // TODO: see above 1412 if (View* parent = fCurrentView->Parent()) 1413 parent->RebuildClipping(false); 1414 1415 fWindow->MarkContentDirty(dirty); 1416 break; 1417 } 1418 case AS_VIEW_GET_COORD: 1419 { 1420 // our offset in the parent -> will be originX and originY 1421 // in BView 1422 BPoint parentOffset = fCurrentView->Frame().LeftTop(); 1423 1424 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: " 1425 "View: %s -> x: %.1f, y: %.1f\n", Title(), 1426 fCurrentView->Name(), parentOffset.x, parentOffset.y)); 1427 1428 fLink.StartMessage(B_OK); 1429 fLink.Attach<BPoint>(parentOffset); 1430 fLink.Attach<BRect>(fCurrentView->Bounds()); 1431 fLink.Flush(); 1432 break; 1433 } 1434 case AS_VIEW_SET_ORIGIN: 1435 { 1436 float x, y; 1437 link.Read<float>(&x); 1438 if (link.Read<float>(&y) != B_OK) 1439 break; 1440 1441 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: " 1442 "View: %s -> x: %.1f, y: %.1f\n", Title(), 1443 fCurrentView->Name(), x, y)); 1444 1445 fCurrentView->SetDrawingOrigin(BPoint(x, y)); 1446 _UpdateDrawState(fCurrentView); 1447 break; 1448 } 1449 case AS_VIEW_GET_ORIGIN: 1450 { 1451 BPoint drawingOrigin = fCurrentView->DrawingOrigin(); 1452 1453 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: " 1454 "View: %s -> x: %.1f, y: %.1f\n", Title(), 1455 fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y)); 1456 1457 fLink.StartMessage(B_OK); 1458 fLink.Attach<BPoint>(drawingOrigin); 1459 fLink.Flush(); 1460 break; 1461 } 1462 case AS_VIEW_RESIZE_MODE: 1463 { 1464 uint32 resizeMode; 1465 if (link.Read<uint32>(&resizeMode) != B_OK) 1466 break; 1467 1468 DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: " 1469 "View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(), 1470 resizeMode)); 1471 1472 fCurrentView->SetResizeMode(resizeMode); 1473 break; 1474 } 1475 case AS_VIEW_SET_FLAGS: 1476 { 1477 uint32 flags; 1478 link.Read<uint32>(&flags); 1479 1480 // The views clipping changes when the B_DRAW_ON_CHILDREN flag is 1481 // toggled. 1482 bool updateClipping = (flags & B_DRAW_ON_CHILDREN) 1483 ^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN); 1484 1485 fCurrentView->SetFlags(flags); 1486 _UpdateDrawState(fCurrentView); 1487 1488 if (updateClipping) { 1489 fCurrentView->RebuildClipping(false); 1490 fCurrentDrawingRegionValid = false; 1491 } 1492 1493 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: " 1494 "View: %s -> flags: %" B_PRIu32 "\n", Title(), 1495 fCurrentView->Name(), flags)); 1496 break; 1497 } 1498 case AS_VIEW_HIDE: 1499 DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n", 1500 Title(), fCurrentView->Name())); 1501 fCurrentView->SetHidden(true); 1502 break; 1503 1504 case AS_VIEW_SHOW: 1505 DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n", 1506 Title(), fCurrentView->Name())); 1507 fCurrentView->SetHidden(false); 1508 break; 1509 1510 case AS_VIEW_SET_LINE_MODE: 1511 { 1512 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: " 1513 "View: %s\n", Title(), fCurrentView->Name())); 1514 ViewSetLineModeInfo info; 1515 if (link.Read<ViewSetLineModeInfo>(&info) != B_OK) 1516 break; 1517 1518 fCurrentView->CurrentState()->SetLineCapMode(info.lineCap); 1519 fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin); 1520 fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit); 1521 1522 fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap, 1523 info.lineJoin, info.miterLimit); 1524 1525 break; 1526 } 1527 case AS_VIEW_GET_LINE_MODE: 1528 { 1529 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: " 1530 "View: %s\n", Title(), fCurrentView->Name())); 1531 ViewSetLineModeInfo info; 1532 info.lineJoin = fCurrentView->CurrentState()->LineJoinMode(); 1533 info.lineCap = fCurrentView->CurrentState()->LineCapMode(); 1534 info.miterLimit = fCurrentView->CurrentState()->MiterLimit(); 1535 1536 fLink.StartMessage(B_OK); 1537 fLink.Attach<ViewSetLineModeInfo>(info); 1538 fLink.Flush(); 1539 1540 break; 1541 } 1542 case AS_VIEW_SET_FILL_RULE: 1543 { 1544 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: " 1545 "View: %s\n", Title(), fCurrentView->Name())); 1546 int32 fillRule; 1547 if (link.Read<int32>(&fillRule) != B_OK) 1548 break; 1549 1550 fCurrentView->CurrentState()->SetFillRule(fillRule); 1551 fWindow->GetDrawingEngine()->SetFillRule(fillRule); 1552 1553 break; 1554 } 1555 case AS_VIEW_GET_FILL_RULE: 1556 { 1557 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: " 1558 "View: %s\n", Title(), fCurrentView->Name())); 1559 int32 fillRule = fCurrentView->CurrentState()->FillRule(); 1560 1561 fLink.StartMessage(B_OK); 1562 fLink.Attach<int32>(fillRule); 1563 fLink.Flush(); 1564 1565 break; 1566 } 1567 case AS_VIEW_PUSH_STATE: 1568 { 1569 DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: " 1570 "%s\n", Title(), fCurrentView->Name())); 1571 1572 fCurrentView->PushState(); 1573 // TODO: is this necessary? 1574 // _UpdateDrawState(fCurrentView); 1575 break; 1576 } 1577 case AS_VIEW_POP_STATE: 1578 { 1579 DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n", 1580 Title(), fCurrentView->Name())); 1581 1582 fCurrentView->PopState(); 1583 _UpdateDrawState(fCurrentView); 1584 break; 1585 } 1586 case AS_VIEW_SET_SCALE: 1587 { 1588 float scale; 1589 if (link.Read<float>(&scale) != B_OK) 1590 break; 1591 1592 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: " 1593 "View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(), 1594 scale)); 1595 1596 fCurrentView->SetScale(scale); 1597 _UpdateDrawState(fCurrentView); 1598 break; 1599 } 1600 case AS_VIEW_GET_SCALE: 1601 { 1602 float scale = fCurrentView->CurrentState()->Scale(); 1603 1604 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: " 1605 "View: %s -> scale: %.2f\n", 1606 Title(), fCurrentView->Name(), scale)); 1607 1608 fLink.StartMessage(B_OK); 1609 fLink.Attach<float>(scale); 1610 fLink.Flush(); 1611 break; 1612 } 1613 case AS_VIEW_SET_TRANSFORM: 1614 { 1615 BAffineTransform transform; 1616 if (link.Read<BAffineTransform>(&transform) != B_OK) 1617 break; 1618 1619 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: " 1620 "View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n", 1621 Title(), fCurrentView->Name(), transform.sx, transform.shy, 1622 transform.shx, transform.sy, transform.tx, transform.ty)); 1623 1624 fCurrentView->CurrentState()->SetTransform(transform); 1625 _UpdateDrawState(fCurrentView); 1626 break; 1627 } 1628 case AS_VIEW_GET_TRANSFORM: 1629 { 1630 BAffineTransform transform 1631 = fCurrentView->CurrentState()->Transform(); 1632 1633 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: " 1634 "View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n", 1635 Title(), fCurrentView->Name(), transform.sx, transform.shy, 1636 transform.shx, transform.sy, transform.tx, transform.ty)); 1637 1638 fLink.StartMessage(B_OK); 1639 fLink.Attach<BAffineTransform>(transform); 1640 fLink.Flush(); 1641 break; 1642 } 1643 case AS_VIEW_AFFINE_TRANSLATE: 1644 { 1645 double x, y; 1646 link.Read<double>(&x); 1647 link.Read<double>(&y); 1648 BAffineTransform current = 1649 fCurrentView->CurrentState()->Transform(); 1650 current.PreTranslateBy(x, y); 1651 fCurrentView->CurrentState()->SetTransform(current); 1652 _UpdateDrawState(fCurrentView); 1653 break; 1654 } 1655 1656 case AS_VIEW_AFFINE_SCALE: 1657 { 1658 double x, y; 1659 link.Read<double>(&x); 1660 link.Read<double>(&y); 1661 BAffineTransform current = 1662 fCurrentView->CurrentState()->Transform(); 1663 current.PreScaleBy(x, y); 1664 fCurrentView->CurrentState()->SetTransform(current); 1665 _UpdateDrawState(fCurrentView); 1666 break; 1667 } 1668 1669 case AS_VIEW_AFFINE_ROTATE: 1670 { 1671 double angleRadians; 1672 link.Read<double>(&angleRadians); 1673 BAffineTransform current = 1674 fCurrentView->CurrentState()->Transform(); 1675 current.PreRotateBy(angleRadians); 1676 fCurrentView->CurrentState()->SetTransform(current); 1677 _UpdateDrawState(fCurrentView); 1678 break; 1679 } 1680 1681 case AS_VIEW_SET_PEN_LOC: 1682 { 1683 BPoint location; 1684 if (link.Read<BPoint>(&location) != B_OK) 1685 break; 1686 1687 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: " 1688 "View: %s -> BPoint(%.1f, %.1f)\n", Title(), 1689 fCurrentView->Name(), location.x, location.y)); 1690 1691 fCurrentView->CurrentState()->SetPenLocation(location); 1692 break; 1693 } 1694 case AS_VIEW_GET_PEN_LOC: 1695 { 1696 BPoint location = fCurrentView->CurrentState()->PenLocation(); 1697 1698 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: " 1699 "View: %s -> BPoint(%.1f, %.1f)\n", Title(), 1700 fCurrentView->Name(), location.x, location.y)); 1701 1702 fLink.StartMessage(B_OK); 1703 fLink.Attach<BPoint>(location); 1704 fLink.Flush(); 1705 1706 break; 1707 } 1708 case AS_VIEW_SET_PEN_SIZE: 1709 { 1710 float penSize; 1711 if (link.Read<float>(&penSize) != B_OK) 1712 break; 1713 1714 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: " 1715 "View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize)); 1716 1717 fCurrentView->CurrentState()->SetPenSize(penSize); 1718 fWindow->GetDrawingEngine()->SetPenSize( 1719 fCurrentView->CurrentState()->PenSize()); 1720 break; 1721 } 1722 case AS_VIEW_GET_PEN_SIZE: 1723 { 1724 float penSize = fCurrentView->CurrentState()->UnscaledPenSize(); 1725 1726 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: " 1727 "View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize)); 1728 1729 fLink.StartMessage(B_OK); 1730 fLink.Attach<float>(penSize); 1731 fLink.Flush(); 1732 1733 break; 1734 } 1735 case AS_VIEW_SET_VIEW_COLOR: 1736 { 1737 rgb_color color; 1738 if (link.Read(&color, sizeof(rgb_color)) != B_OK) 1739 break; 1740 1741 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: " 1742 "View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(), 1743 fCurrentView->Name(), color.red, color.green, color.blue, 1744 color.alpha)); 1745 1746 fCurrentView->SetViewColor(color); 1747 break; 1748 } 1749 case AS_VIEW_GET_VIEW_COLOR: 1750 { 1751 rgb_color color = fCurrentView->ViewColor(); 1752 1753 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: " 1754 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1755 Title(), fCurrentView->Name(), color.red, color.green, 1756 color.blue, color.alpha)); 1757 1758 fLink.StartMessage(B_OK); 1759 fLink.Attach<rgb_color>(color); 1760 fLink.Flush(); 1761 break; 1762 } 1763 case AS_VIEW_SET_HIGH_COLOR: 1764 { 1765 rgb_color color; 1766 if (link.Read(&color, sizeof(rgb_color)) != B_OK) 1767 break; 1768 1769 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: " 1770 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1771 Title(), fCurrentView->Name(), color.red, color.green, 1772 color.blue, color.alpha)); 1773 1774 fCurrentView->CurrentState()->SetHighColor(color); 1775 fWindow->GetDrawingEngine()->SetHighColor(color); 1776 break; 1777 } 1778 1779 case AS_VIEW_SET_HIGH_UI_COLOR: 1780 { 1781 color_which which = B_NO_COLOR; 1782 float tint = B_NO_TINT; 1783 1784 if (link.Read<color_which>(&which) != B_OK 1785 || link.Read<float>(&tint) != B_OK ) 1786 break; 1787 1788 fCurrentView->CurrentState()->SetHighUIColor(which, tint); 1789 1790 // TODO: should we do more color_which validity checking? 1791 if (which != B_NO_COLOR) { 1792 DesktopSettings settings(fDesktop); 1793 rgb_color color = tint_color(settings.UIColor(which), tint); 1794 1795 fCurrentView->CurrentState()->SetHighColor(color); 1796 fWindow->GetDrawingEngine()->SetHighColor(color); 1797 } 1798 break; 1799 } 1800 case AS_VIEW_SET_LOW_UI_COLOR: 1801 { 1802 color_which which = B_NO_COLOR; 1803 float tint = B_NO_TINT; 1804 1805 if (link.Read<color_which>(&which) != B_OK 1806 || link.Read<float>(&tint) != B_OK ) 1807 break; 1808 1809 fCurrentView->CurrentState()->SetLowUIColor(which, tint); 1810 1811 // TODO: should we do more color_which validity checking? 1812 if (which != B_NO_COLOR) { 1813 DesktopSettings settings(fDesktop); 1814 rgb_color color = tint_color(settings.UIColor(which), tint); 1815 1816 fCurrentView->CurrentState()->SetLowColor(color); 1817 fWindow->GetDrawingEngine()->SetLowColor(color); 1818 } 1819 break; 1820 } 1821 case AS_VIEW_SET_VIEW_UI_COLOR: 1822 { 1823 color_which which = B_NO_COLOR; 1824 float tint = B_NO_TINT; 1825 1826 if (link.Read<color_which>(&which) != B_OK 1827 || link.Read<float>(&tint) != B_OK ) 1828 break; 1829 1830 // TODO: should we do more color_which validity checking? 1831 fCurrentView->SetViewUIColor(which, tint); 1832 break; 1833 } 1834 case AS_VIEW_GET_HIGH_UI_COLOR: 1835 { 1836 float tint; 1837 color_which which = fCurrentView->CurrentState()->HighUIColor(&tint); 1838 rgb_color color = fCurrentView->CurrentState()->HighColor(); 1839 1840 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_UI_COLOR: " 1841 "View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i," 1842 " %i, %i)\n", Title(), fCurrentView->Name(), which, tint, 1843 color.red, color.green, color.blue, color.alpha)); 1844 1845 fLink.StartMessage(B_OK); 1846 fLink.Attach<color_which>(which); 1847 fLink.Attach<float>(tint); 1848 fLink.Attach<rgb_color>(color); 1849 fLink.Flush(); 1850 break; 1851 } 1852 case AS_VIEW_GET_LOW_UI_COLOR: 1853 { 1854 float tint; 1855 color_which which = fCurrentView->CurrentState()->LowUIColor(&tint); 1856 rgb_color color = fCurrentView->CurrentState()->LowColor(); 1857 1858 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_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_VIEW_UI_COLOR: 1871 { 1872 float tint; 1873 color_which which = fCurrentView->ViewUIColor(&tint); 1874 rgb_color color = fCurrentView->ViewColor(); 1875 1876 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_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_HIGH_COLOR: 1889 { 1890 rgb_color color = fCurrentView->CurrentState()->HighColor(); 1891 1892 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: " 1893 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1894 Title(), fCurrentView->Name(), color.red, color.green, 1895 color.blue, color.alpha)); 1896 1897 fLink.StartMessage(B_OK); 1898 fLink.Attach<rgb_color>(color); 1899 fLink.Flush(); 1900 break; 1901 } 1902 case AS_VIEW_SET_LOW_COLOR: 1903 { 1904 rgb_color color; 1905 if (link.Read(&color, sizeof(rgb_color)) != B_OK) 1906 break; 1907 1908 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: " 1909 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1910 Title(), fCurrentView->Name(), color.red, color.green, 1911 color.blue, color.alpha)); 1912 1913 fCurrentView->CurrentState()->SetLowColor(color); 1914 fWindow->GetDrawingEngine()->SetLowColor(color); 1915 break; 1916 } 1917 case AS_VIEW_GET_LOW_COLOR: 1918 { 1919 rgb_color color = fCurrentView->CurrentState()->LowColor(); 1920 1921 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: " 1922 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1923 Title(), fCurrentView->Name(), color.red, color.green, 1924 color.blue, color.alpha)); 1925 1926 fLink.StartMessage(B_OK); 1927 fLink.Attach<rgb_color>(color); 1928 fLink.Flush(); 1929 break; 1930 } 1931 case AS_VIEW_SET_PATTERN: 1932 { 1933 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: " 1934 "View: %s\n", fTitle, fCurrentView->Name())); 1935 1936 pattern pat; 1937 if (link.Read(&pat, sizeof(pattern)) != B_OK) 1938 break; 1939 1940 fCurrentView->CurrentState()->SetPattern(Pattern(pat)); 1941 fWindow->GetDrawingEngine()->SetPattern(pat); 1942 break; 1943 } 1944 1945 case AS_VIEW_SET_BLENDING_MODE: 1946 { 1947 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: " 1948 "View: %s\n", Title(), fCurrentView->Name())); 1949 1950 ViewBlendingModeInfo info; 1951 if (link.Read<ViewBlendingModeInfo>(&info) != B_OK) 1952 break; 1953 1954 fCurrentView->CurrentState()->SetBlendingMode( 1955 info.sourceAlpha, info.alphaFunction); 1956 fWindow->GetDrawingEngine()->SetBlendingMode( 1957 info.sourceAlpha, info.alphaFunction); 1958 break; 1959 } 1960 case AS_VIEW_GET_BLENDING_MODE: 1961 { 1962 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: " 1963 "View: %s\n", Title(), fCurrentView->Name())); 1964 1965 ViewBlendingModeInfo info; 1966 info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode(); 1967 info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode(); 1968 1969 fLink.StartMessage(B_OK); 1970 fLink.Attach<ViewBlendingModeInfo>(info); 1971 fLink.Flush(); 1972 1973 break; 1974 } 1975 case AS_VIEW_SET_DRAWING_MODE: 1976 { 1977 int8 drawingMode; 1978 if (link.Read<int8>(&drawingMode) != B_OK) 1979 break; 1980 1981 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: " 1982 "View: %s -> %s\n", Title(), fCurrentView->Name(), 1983 kDrawingModeMap[drawingMode])); 1984 1985 fCurrentView->CurrentState()->SetDrawingMode( 1986 (drawing_mode)drawingMode); 1987 fWindow->GetDrawingEngine()->SetDrawingMode( 1988 (drawing_mode)drawingMode); 1989 break; 1990 } 1991 case AS_VIEW_GET_DRAWING_MODE: 1992 { 1993 int8 drawingMode 1994 = (int8)(fCurrentView->CurrentState()->GetDrawingMode()); 1995 1996 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: " 1997 "View: %s -> %s\n", Title(), fCurrentView->Name(), 1998 kDrawingModeMap[drawingMode])); 1999 2000 fLink.StartMessage(B_OK); 2001 fLink.Attach<int8>(drawingMode); 2002 fLink.Flush(); 2003 2004 break; 2005 } 2006 case AS_VIEW_SET_VIEW_BITMAP: 2007 { 2008 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: " 2009 "View: %s\n", Title(), fCurrentView->Name())); 2010 2011 int32 bitmapToken, resizingMode, options; 2012 BRect srcRect, dstRect; 2013 2014 link.Read<int32>(&bitmapToken); 2015 link.Read<BRect>(&srcRect); 2016 link.Read<BRect>(&dstRect); 2017 link.Read<int32>(&resizingMode); 2018 status_t status = link.Read<int32>(&options); 2019 2020 rgb_color colorKey = {0}; 2021 2022 if (status == B_OK) { 2023 BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(bitmapToken), true); 2024 if (bitmapToken == -1 || bitmap != NULL) { 2025 bool wasOverlay = fCurrentView->ViewBitmap() != NULL 2026 && fCurrentView->ViewBitmap()->Overlay() != NULL; 2027 2028 fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect, 2029 resizingMode, options); 2030 2031 // TODO: if we revert the view color overlay handling 2032 // in View::Draw() to the BeOS version, we never 2033 // need to invalidate the view for overlays. 2034 2035 // Invalidate view - but only if this is a non-overlay 2036 // switch 2037 if (bitmap == NULL || bitmap->Overlay() == NULL 2038 || !wasOverlay) { 2039 BRegion dirty((BRect)fCurrentView->Bounds()); 2040 fWindow->InvalidateView(fCurrentView, dirty); 2041 } 2042 2043 if (bitmap != NULL && bitmap->Overlay() != NULL) { 2044 bitmap->Overlay()->SetFlags(options); 2045 colorKey = bitmap->Overlay()->Color(); 2046 } 2047 } else 2048 status = B_BAD_VALUE; 2049 } 2050 2051 fLink.StartMessage(status); 2052 if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) { 2053 // Attach color key for the overlay bitmap 2054 fLink.Attach<rgb_color>(colorKey); 2055 } 2056 2057 fLink.Flush(); 2058 break; 2059 } 2060 case AS_VIEW_PRINT_ALIASING: 2061 { 2062 DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: " 2063 "View: %s\n", Title(), fCurrentView->Name())); 2064 2065 bool fontAliasing; 2066 if (link.Read<bool>(&fontAliasing) == B_OK) { 2067 fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing); 2068 _UpdateDrawState(fCurrentView); 2069 } 2070 break; 2071 } 2072 case AS_VIEW_CLIP_TO_PICTURE: 2073 { 2074 DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: " 2075 "View: %s\n", Title(), fCurrentView->Name())); 2076 2077 int32 pictureToken; 2078 BPoint where; 2079 bool inverse = false; 2080 2081 link.Read<int32>(&pictureToken); 2082 if (pictureToken < 0) { 2083 fCurrentView->SetAlphaMask(NULL); 2084 _UpdateDrawState(fCurrentView); 2085 break; 2086 } 2087 2088 link.Read<BPoint>(&where); 2089 if (link.Read<bool>(&inverse) != B_OK) 2090 break; 2091 2092 BReference<ServerPicture> picture(fServerApp->GetPicture(pictureToken), true); 2093 if (picture == NULL) 2094 break; 2095 2096 BReference<AlphaMask> const mask(new(std::nothrow) PictureAlphaMask( 2097 fCurrentView->GetAlphaMask(), picture, 2098 *fCurrentView->CurrentState(), where, inverse), true); 2099 fCurrentView->SetAlphaMask(mask); 2100 2101 _UpdateDrawState(fCurrentView); 2102 break; 2103 } 2104 2105 case AS_VIEW_GET_CLIP_REGION: 2106 { 2107 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: " 2108 "View: %s\n", Title(), fCurrentView->Name())); 2109 2110 // if this view is hidden, it has no visible region 2111 fLink.StartMessage(B_OK); 2112 if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) { 2113 BRegion empty; 2114 fLink.AttachRegion(empty); 2115 } else { 2116 _UpdateCurrentDrawingRegion(); 2117 BRegion region(fCurrentDrawingRegion); 2118 fCurrentView->ScreenToLocalTransform().Apply(®ion); 2119 fLink.AttachRegion(region); 2120 } 2121 fLink.Flush(); 2122 2123 break; 2124 } 2125 case AS_VIEW_SET_CLIP_REGION: 2126 { 2127 int32 rectCount; 2128 status_t status = link.Read<int32>(&rectCount); 2129 // a negative count means no 2130 // region for the current draw state, 2131 // but an *empty* region is actually valid! 2132 // even if it means no drawing is allowed 2133 2134 if (status < B_OK) 2135 break; 2136 2137 if (rectCount >= 0) { 2138 // we are supposed to set the clipping region 2139 BRegion region; 2140 if (rectCount > 0 && link.ReadRegion(®ion) < B_OK) 2141 break; 2142 2143 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: " 2144 "View: %s -> rect count: %" B_PRId32 ", frame = " 2145 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 2146 Title(), fCurrentView->Name(), rectCount, 2147 region.Frame().left, region.Frame().top, 2148 region.Frame().right, region.Frame().bottom)); 2149 2150 fCurrentView->SetUserClipping(®ion); 2151 } else { 2152 // we are supposed to unset the clipping region 2153 // passing NULL sets this states region to that 2154 // of the previous state 2155 2156 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: " 2157 "View: %s -> unset\n", Title(), fCurrentView->Name())); 2158 2159 fCurrentView->SetUserClipping(NULL); 2160 } 2161 fCurrentDrawingRegionValid = false; 2162 2163 break; 2164 } 2165 2166 case AS_VIEW_CLIP_TO_RECT: 2167 { 2168 bool inverse; 2169 BRect rect; 2170 2171 link.Read<bool>(&inverse); 2172 link.Read<BRect>(&rect); 2173 2174 bool needDrawStateUpdate = fCurrentView->ClipToRect( 2175 rect, inverse); 2176 fCurrentDrawingRegionValid = false; 2177 2178 if (needDrawStateUpdate) 2179 _UpdateDrawState(fCurrentView); 2180 2181 _UpdateCurrentDrawingRegion(); 2182 2183 BRegion region(fCurrentDrawingRegion); 2184 fCurrentView->ScreenToLocalTransform().Apply(®ion); 2185 2186 break; 2187 } 2188 2189 case AS_VIEW_CLIP_TO_SHAPE: 2190 { 2191 bool inverse; 2192 link.Read<bool>(&inverse); 2193 2194 shape_data shape; 2195 link.Read<int32>(&shape.opCount); 2196 link.Read<int32>(&shape.ptCount); 2197 shape.opSize = shape.opCount * sizeof(uint32); 2198 shape.ptSize = shape.ptCount * sizeof(BPoint); 2199 shape.opList = new(nothrow) uint32[shape.opCount]; 2200 shape.ptList = new(nothrow) BPoint[shape.ptCount]; 2201 if (link.Read(shape.opList, shape.opSize) >= B_OK 2202 && link.Read(shape.ptList, shape.ptSize) >= B_OK) { 2203 fCurrentView->ClipToShape(&shape, inverse); 2204 _UpdateDrawState(fCurrentView); 2205 } 2206 2207 delete[] shape.opList; 2208 delete[] shape.ptList; 2209 break; 2210 } 2211 2212 case AS_VIEW_INVALIDATE_RECT: 2213 { 2214 // NOTE: looks like this call is NOT affected by origin and scale 2215 // on R5 so this implementation is "correct" 2216 BRect invalidRect; 2217 if (link.Read<BRect>(&invalidRect) == B_OK) { 2218 DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: " 2219 "View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2220 fCurrentView->Name(), invalidRect.left, invalidRect.top, 2221 invalidRect.right, invalidRect.bottom)); 2222 2223 View* view = NULL; 2224 if (link.Read<View*>(&view) != B_OK) 2225 view = fCurrentView; 2226 2227 // make sure the view is still available! 2228 if (view != fCurrentView 2229 && !fWindow->TopView()->HasView(view)) 2230 break; 2231 2232 BRegion dirty(invalidRect); 2233 fWindow->InvalidateView(view, dirty); 2234 } 2235 break; 2236 } 2237 2238 case AS_VIEW_DELAYED_INVALIDATE_RECT: 2239 { 2240 bigtime_t time = 0; 2241 BRect invalidRect; 2242 if (link.Read<bigtime_t>(&time) == B_OK 2243 && link.Read<BRect>(&invalidRect) == B_OK) { 2244 DTRACE(("ServerWindow %s: Message " 2245 "AS_VIEW_DELAYED_INVALIDATE_RECT: " 2246 "View: %s -> BRect(%.1f, %.1f, %.1f, %.1f) at time %llu\n", 2247 Title(), fCurrentView->Name(), invalidRect.left, 2248 invalidRect.top, invalidRect.right, invalidRect.bottom, 2249 time)); 2250 2251 DelayedMessage delayed(AS_VIEW_INVALIDATE_RECT, time, true); 2252 delayed.AddTarget(MessagePort()); 2253 delayed.SetMerge(DM_MERGE_DUPLICATES); 2254 2255 if (delayed.Attach<BRect>(invalidRect) == B_OK 2256 && delayed.Attach<View*>(fCurrentView) == B_OK) 2257 delayed.Flush(); 2258 } 2259 break; 2260 } 2261 2262 case AS_VIEW_INVALIDATE_REGION: 2263 { 2264 // NOTE: looks like this call is NOT affected by origin and scale 2265 // on R5 so this implementation is "correct" 2266 BRegion region; 2267 if (link.ReadRegion(®ion) < B_OK) 2268 break; 2269 2270 DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: " 2271 "View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, " 2272 "%.1f, %.1f, %.1f)\n", Title(), 2273 fCurrentView->Name(), region.CountRects(), 2274 region.Frame().left, region.Frame().top, 2275 region.Frame().right, region.Frame().bottom)); 2276 2277 fWindow->InvalidateView(fCurrentView, region); 2278 break; 2279 } 2280 2281 case AS_VIEW_DRAG_IMAGE: 2282 { 2283 // TODO: flesh out AS_VIEW_DRAG_IMAGE 2284 DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title())); 2285 2286 int32 bitmapToken; 2287 drawing_mode dragMode; 2288 BPoint offset; 2289 int32 bufferSize; 2290 2291 link.Read<int32>(&bitmapToken); 2292 link.Read<int32>((int32*)&dragMode); 2293 link.Read<BPoint>(&offset); 2294 link.Read<int32>(&bufferSize); 2295 2296 if (bufferSize > 0) { 2297 char* buffer = new (nothrow) char[bufferSize]; 2298 BMessage dragMessage; 2299 if (link.Read(buffer, bufferSize) == B_OK 2300 && dragMessage.Unflatten(buffer) == B_OK) { 2301 BReference<ServerBitmap> bitmap( 2302 fServerApp->GetBitmap(bitmapToken), true); 2303 // TODO: possible deadlock 2304 fDesktop->UnlockSingleWindow(); 2305 fDesktop->EventDispatcher().SetDragMessage(dragMessage, 2306 bitmap, offset); 2307 fDesktop->LockSingleWindow(); 2308 } 2309 delete[] buffer; 2310 } 2311 // sync the client (it can now delete the bitmap) 2312 fLink.StartMessage(B_OK); 2313 fLink.Flush(); 2314 2315 break; 2316 } 2317 case AS_VIEW_DRAG_RECT: 2318 { 2319 // TODO: flesh out AS_VIEW_DRAG_RECT 2320 DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title())); 2321 2322 BRect dragRect; 2323 BPoint offset; 2324 int32 bufferSize; 2325 2326 link.Read<BRect>(&dragRect); 2327 link.Read<BPoint>(&offset); 2328 link.Read<int32>(&bufferSize); 2329 2330 if (bufferSize > 0) { 2331 char* buffer = new (nothrow) char[bufferSize]; 2332 BMessage dragMessage; 2333 if (link.Read(buffer, bufferSize) == B_OK 2334 && dragMessage.Unflatten(buffer) == B_OK) { 2335 // TODO: possible deadlock 2336 fDesktop->UnlockSingleWindow(); 2337 fDesktop->EventDispatcher().SetDragMessage(dragMessage, 2338 NULL /* should be dragRect */, offset); 2339 fDesktop->LockSingleWindow(); 2340 } 2341 delete[] buffer; 2342 } 2343 break; 2344 } 2345 2346 case AS_VIEW_BEGIN_RECT_TRACK: 2347 { 2348 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n", 2349 Title())); 2350 BRect dragRect; 2351 uint32 style; 2352 2353 link.Read<BRect>(&dragRect); 2354 link.Read<uint32>(&style); 2355 2356 // TODO: implement rect tracking (used sometimes for selecting 2357 // a group of things, also sometimes used to appear to drag 2358 // something, but without real drag message) 2359 break; 2360 } 2361 case AS_VIEW_END_RECT_TRACK: 2362 { 2363 DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n", 2364 Title())); 2365 // TODO: implement rect tracking 2366 break; 2367 } 2368 2369 case AS_VIEW_BEGIN_PICTURE: 2370 { 2371 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n", 2372 Title())); 2373 BReference<ServerPicture> picture(App()->CreatePicture(), true); 2374 if (picture != NULL) { 2375 picture->SyncState(fCurrentView); 2376 fCurrentView->SetPicture(picture); 2377 } 2378 break; 2379 } 2380 2381 case AS_VIEW_APPEND_TO_PICTURE: 2382 { 2383 DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n", 2384 Title())); 2385 2386 int32 token; 2387 link.Read<int32>(&token); 2388 2389 BReference<ServerPicture> picture(App()->GetPicture(token), true); 2390 if (picture != NULL) 2391 picture->SyncState(fCurrentView); 2392 2393 fCurrentView->SetPicture(picture); 2394 2395 break; 2396 } 2397 2398 case AS_VIEW_END_PICTURE: 2399 { 2400 DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n", 2401 Title())); 2402 2403 ServerPicture* picture = fCurrentView->Picture(); 2404 if (picture != NULL) { 2405 fCurrentView->SetPicture(NULL); 2406 fLink.StartMessage(B_OK); 2407 fLink.Attach<int32>(picture->Token()); 2408 } else 2409 fLink.StartMessage(B_ERROR); 2410 2411 fLink.Flush(); 2412 break; 2413 } 2414 2415 case AS_VIEW_BEGIN_LAYER: 2416 { 2417 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n", 2418 Title())); 2419 2420 uint8 opacity; 2421 link.Read<uint8>(&opacity); 2422 2423 Layer* layer = new(std::nothrow) Layer(opacity); 2424 if (layer == NULL) 2425 break; 2426 2427 if (opacity != 255) { 2428 fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA); 2429 fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA, 2430 B_ALPHA_COMPOSITE); 2431 fCurrentView->CurrentState()->SetDrawingModeLocked(true); 2432 } 2433 2434 fCurrentView->SetPicture(layer); 2435 break; 2436 } 2437 2438 default: 2439 // The drawing code handles allocation failures using exceptions; 2440 // so we need to account for that here. 2441 try { 2442 _DispatchViewDrawingMessage(code, link); 2443 } catch (std::bad_alloc&) { 2444 // Cancel any message we were in the middle of sending. 2445 fLink.CancelMessage(); 2446 2447 if (link.NeedsReply()) { 2448 // As done in _DispatchViewDrawingMessage, send just a 2449 // single status_t as the reply. 2450 fLink.StartMessage(B_NO_MEMORY); 2451 fLink.Flush(); 2452 } 2453 } 2454 break; 2455 } 2456 } 2457 2458 2459 /*! Dispatches all view drawing messages. 2460 The desktop clipping must be read locked when entering this method. 2461 Requires a valid fCurrentView. 2462 */ 2463 void 2464 ServerWindow::_DispatchViewDrawingMessage(int32 code, 2465 BPrivate::LinkReceiver &link) 2466 { 2467 if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) { 2468 if (link.NeedsReply()) { 2469 debug_printf("ServerWindow::DispatchViewDrawingMessage() got " 2470 "message %" B_PRId32 " that needs a reply!\n", code); 2471 // the client is now blocking and waiting for a reply! 2472 fLink.StartMessage(B_ERROR); 2473 fLink.Flush(); 2474 } 2475 return; 2476 } 2477 2478 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 2479 if (!drawingEngine) { 2480 // ?!? 2481 debug_printf("ServerWindow %s: no drawing engine!!\n", Title()); 2482 if (link.NeedsReply()) { 2483 // the client is now blocking and waiting for a reply! 2484 fLink.StartMessage(B_ERROR); 2485 fLink.Flush(); 2486 } 2487 return; 2488 } 2489 2490 _UpdateCurrentDrawingRegion(); 2491 if (fCurrentDrawingRegion.CountRects() <= 0 && code != AS_VIEW_END_LAYER) { 2492 // If the command is AS_VIEW_END_LAYER, then we continue even if 2493 // the clipping region is empty. The layer itself might set a valid 2494 // clipping while its contents are drawn, and even if it doesn't, 2495 // we must still play back its picture so that we don't leak 2496 // nested layer instances. 2497 2498 DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, " 2499 "INVALID CLIPPING!\n", Title(), fCurrentView->Name())); 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 drawingEngine->LockParallelAccess(); 2509 // NOTE: the region is not copied, Painter keeps a pointer, 2510 // that's why you need to use the clipping only for as long 2511 // as you have it locked 2512 drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion); 2513 2514 switch (code) { 2515 case AS_STROKE_LINE: 2516 { 2517 ViewStrokeLineInfo info; 2518 if (link.Read<ViewStrokeLineInfo>(&info) != B_OK) 2519 break; 2520 2521 DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> " 2522 "BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(), 2523 fCurrentView->Name(), 2524 info.startPoint.x, info.startPoint.y, 2525 info.endPoint.x, info.endPoint.y)); 2526 2527 BPoint penPos = info.endPoint; 2528 const SimpleTransform transform = 2529 fCurrentView->PenToScreenTransform(); 2530 transform.Apply(&info.startPoint); 2531 transform.Apply(&info.endPoint); 2532 drawingEngine->StrokeLine(info.startPoint, info.endPoint); 2533 2534 // We update the pen here because many DrawingEngine calls which 2535 // do not update the pen position actually call StrokeLine 2536 2537 // TODO: Decide where to put this, for example, it cannot be done 2538 // for DrawString(), also there needs to be a decision, if the pen 2539 // location is in View coordinates (I think it should be) or in 2540 // screen coordinates. 2541 fCurrentView->CurrentState()->SetPenLocation(penPos); 2542 break; 2543 } 2544 case AS_VIEW_INVERT_RECT: 2545 { 2546 BRect rect; 2547 if (link.Read<BRect>(&rect) != B_OK) 2548 break; 2549 2550 DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> " 2551 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2552 fCurrentView->Name(), rect.left, rect.top, rect.right, 2553 rect.bottom)); 2554 2555 fCurrentView->PenToScreenTransform().Apply(&rect); 2556 drawingEngine->InvertRect(rect); 2557 break; 2558 } 2559 case AS_STROKE_RECT: 2560 { 2561 BRect rect; 2562 if (link.Read<BRect>(&rect) != B_OK) 2563 break; 2564 2565 DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> " 2566 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2567 fCurrentView->Name(), rect.left, rect.top, rect.right, 2568 rect.bottom)); 2569 2570 fCurrentView->PenToScreenTransform().Apply(&rect); 2571 drawingEngine->StrokeRect(rect); 2572 break; 2573 } 2574 case AS_FILL_RECT: 2575 { 2576 BRect rect; 2577 if (link.Read<BRect>(&rect) != B_OK) 2578 break; 2579 2580 DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> " 2581 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2582 fCurrentView->Name(), rect.left, rect.top, rect.right, 2583 rect.bottom)); 2584 2585 fCurrentView->PenToScreenTransform().Apply(&rect); 2586 drawingEngine->FillRect(rect); 2587 break; 2588 } 2589 case AS_FILL_RECT_GRADIENT: 2590 { 2591 BRect rect; 2592 link.Read<BRect>(&rect); 2593 BGradient* gradient; 2594 if (link.ReadGradient(&gradient) != B_OK) 2595 break; 2596 2597 GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s " 2598 "-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2599 fCurrentView->Name(), rect.left, rect.top, rect.right, 2600 rect.bottom)); 2601 2602 const SimpleTransform transform = 2603 fCurrentView->PenToScreenTransform(); 2604 transform.Apply(&rect); 2605 transform.Apply(gradient); 2606 drawingEngine->FillRect(rect, *gradient); 2607 delete gradient; 2608 break; 2609 } 2610 case AS_VIEW_DRAW_BITMAP: 2611 { 2612 ViewDrawBitmapInfo info; 2613 if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK) 2614 break; 2615 2616 #if 0 2617 if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0) 2618 info.options |= B_FILTER_BITMAP_BILINEAR; 2619 #endif 2620 2621 BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(info.bitmapToken), true); 2622 if (bitmap != NULL) { 2623 DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: " 2624 "View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x " 2625 "%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> " 2626 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 2627 fTitle, fCurrentView->Name(), info.bitmapToken, 2628 bitmap->Width(), bitmap->Height(), 2629 info.bitmapRect.left, info.bitmapRect.top, 2630 info.bitmapRect.right, info.bitmapRect.bottom, 2631 info.viewRect.left, info.viewRect.top, 2632 info.viewRect.right, info.viewRect.bottom)); 2633 2634 fCurrentView->PenToScreenTransform().Apply(&info.viewRect); 2635 2636 // TODO: Unbreak... 2637 // if ((info.options & B_WAIT_FOR_RETRACE) != 0) 2638 // fDesktop->HWInterface()->WaitForRetrace(20000); 2639 2640 drawingEngine->DrawBitmap(bitmap, info.bitmapRect, 2641 info.viewRect, info.options); 2642 } 2643 break; 2644 } 2645 case AS_STROKE_ARC: 2646 case AS_FILL_ARC: 2647 { 2648 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title())); 2649 2650 float angle, span; 2651 BRect r; 2652 2653 link.Read<BRect>(&r); 2654 link.Read<float>(&angle); 2655 if (link.Read<float>(&span) != B_OK) 2656 break; 2657 2658 fCurrentView->PenToScreenTransform().Apply(&r); 2659 drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC); 2660 break; 2661 } 2662 case AS_FILL_ARC_GRADIENT: 2663 { 2664 GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n", 2665 Title())); 2666 2667 float angle, span; 2668 BRect r; 2669 link.Read<BRect>(&r); 2670 link.Read<float>(&angle); 2671 link.Read<float>(&span); 2672 BGradient* gradient; 2673 if (link.ReadGradient(&gradient) != B_OK) 2674 break; 2675 const SimpleTransform transform = 2676 fCurrentView->PenToScreenTransform(); 2677 transform.Apply(&r); 2678 transform.Apply(gradient); 2679 drawingEngine->FillArc(r, angle, span, *gradient); 2680 delete gradient; 2681 break; 2682 } 2683 case AS_STROKE_BEZIER: 2684 case AS_FILL_BEZIER: 2685 { 2686 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", 2687 Title())); 2688 2689 const SimpleTransform transform = 2690 fCurrentView->PenToScreenTransform(); 2691 BPoint pts[4]; 2692 status_t status; 2693 for (int32 i = 0; i < 4; i++) { 2694 status = link.Read<BPoint>(&(pts[i])); 2695 transform.Apply(&pts[i]); 2696 } 2697 if (status != B_OK) 2698 break; 2699 2700 drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER); 2701 break; 2702 } 2703 case AS_FILL_BEZIER_GRADIENT: 2704 { 2705 GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n", 2706 Title())); 2707 2708 const SimpleTransform transform = 2709 fCurrentView->PenToScreenTransform(); 2710 BPoint pts[4]; 2711 for (int32 i = 0; i < 4; i++) { 2712 link.Read<BPoint>(&(pts[i])); 2713 transform.Apply(&pts[i]); 2714 } 2715 BGradient* gradient; 2716 if (link.ReadGradient(&gradient) != B_OK) 2717 break; 2718 transform.Apply(gradient); 2719 drawingEngine->FillBezier(pts, *gradient); 2720 delete gradient; 2721 break; 2722 } 2723 case AS_STROKE_ELLIPSE: 2724 case AS_FILL_ELLIPSE: 2725 { 2726 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", 2727 Title())); 2728 2729 BRect rect; 2730 if (link.Read<BRect>(&rect) != B_OK) 2731 break; 2732 2733 fCurrentView->PenToScreenTransform().Apply(&rect); 2734 drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE); 2735 break; 2736 } 2737 case AS_FILL_ELLIPSE_GRADIENT: 2738 { 2739 GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n", 2740 Title())); 2741 2742 BRect rect; 2743 link.Read<BRect>(&rect); 2744 BGradient* gradient; 2745 if (link.ReadGradient(&gradient) != B_OK) 2746 break; 2747 const SimpleTransform transform = 2748 fCurrentView->PenToScreenTransform(); 2749 transform.Apply(&rect); 2750 transform.Apply(gradient); 2751 drawingEngine->FillEllipse(rect, *gradient); 2752 delete gradient; 2753 break; 2754 } 2755 case AS_STROKE_ROUNDRECT: 2756 case AS_FILL_ROUNDRECT: 2757 { 2758 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", 2759 Title())); 2760 2761 BRect rect; 2762 float xRadius; 2763 float yRadius; 2764 link.Read<BRect>(&rect); 2765 link.Read<float>(&xRadius); 2766 if (link.Read<float>(&yRadius) != B_OK) 2767 break; 2768 2769 fCurrentView->PenToScreenTransform().Apply(&rect); 2770 float scale = fCurrentView->CurrentState()->CombinedScale(); 2771 drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale, 2772 code == AS_FILL_ROUNDRECT); 2773 break; 2774 } 2775 case AS_FILL_ROUNDRECT_GRADIENT: 2776 { 2777 GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n", 2778 Title())); 2779 2780 BRect rect; 2781 float xrad,yrad; 2782 link.Read<BRect>(&rect); 2783 link.Read<float>(&xrad); 2784 link.Read<float>(&yrad); 2785 BGradient* gradient; 2786 if (link.ReadGradient(&gradient) != B_OK) 2787 break; 2788 const SimpleTransform transform = 2789 fCurrentView->PenToScreenTransform(); 2790 transform.Apply(&rect); 2791 transform.Apply(gradient); 2792 drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient); 2793 delete gradient; 2794 break; 2795 } 2796 case AS_STROKE_TRIANGLE: 2797 case AS_FILL_TRIANGLE: 2798 { 2799 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", 2800 Title())); 2801 2802 const SimpleTransform transform = 2803 fCurrentView->PenToScreenTransform(); 2804 BPoint pts[3]; 2805 BRect rect; 2806 2807 for (int32 i = 0; i < 3; i++) { 2808 link.Read<BPoint>(&(pts[i])); 2809 transform.Apply(&pts[i]); 2810 } 2811 2812 if (link.Read<BRect>(&rect) != B_OK) 2813 break; 2814 2815 transform.Apply(&rect); 2816 drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE); 2817 break; 2818 } 2819 case AS_FILL_TRIANGLE_GRADIENT: 2820 { 2821 DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n", 2822 Title())); 2823 2824 const SimpleTransform transform = 2825 fCurrentView->PenToScreenTransform(); 2826 BPoint pts[3]; 2827 BRect rect; 2828 for (int32 i = 0; i < 3; i++) { 2829 link.Read<BPoint>(&(pts[i])); 2830 transform.Apply(&pts[i]); 2831 } 2832 link.Read<BRect>(&rect); 2833 BGradient* gradient; 2834 if (link.ReadGradient(&gradient) != B_OK) 2835 break; 2836 transform.Apply(&rect); 2837 transform.Apply(gradient); 2838 drawingEngine->FillTriangle(pts, rect, *gradient); 2839 delete gradient; 2840 break; 2841 } 2842 case AS_STROKE_POLYGON: 2843 case AS_FILL_POLYGON: 2844 { 2845 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", 2846 Title())); 2847 2848 BRect polyFrame; 2849 bool isClosed = true; 2850 int32 pointCount; 2851 2852 link.Read<BRect>(&polyFrame); 2853 if (code == AS_STROKE_POLYGON) 2854 link.Read<bool>(&isClosed); 2855 link.Read<int32>(&pointCount); 2856 2857 const SimpleTransform transform = 2858 fCurrentView->PenToScreenTransform(); 2859 BPoint* pointList = new(nothrow) BPoint[pointCount]; 2860 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { 2861 for (int32 i = 0; i < pointCount; i++) 2862 transform.Apply(&pointList[i]); 2863 transform.Apply(&polyFrame); 2864 2865 drawingEngine->DrawPolygon(pointList, pointCount, polyFrame, 2866 code == AS_FILL_POLYGON, isClosed && pointCount > 2); 2867 } 2868 delete[] pointList; 2869 break; 2870 } 2871 case AS_FILL_POLYGON_GRADIENT: 2872 { 2873 DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n", 2874 Title())); 2875 2876 BRect polyFrame; 2877 bool isClosed = true; 2878 int32 pointCount; 2879 link.Read<BRect>(&polyFrame); 2880 link.Read<int32>(&pointCount); 2881 2882 const SimpleTransform transform = 2883 fCurrentView->PenToScreenTransform(); 2884 BPoint* pointList = new(nothrow) BPoint[pointCount]; 2885 BGradient* gradient; 2886 if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK 2887 && link.ReadGradient(&gradient) == B_OK) { 2888 for (int32 i = 0; i < pointCount; i++) 2889 transform.Apply(&pointList[i]); 2890 transform.Apply(&polyFrame); 2891 transform.Apply(gradient); 2892 2893 drawingEngine->FillPolygon(pointList, pointCount, 2894 polyFrame, *gradient, isClosed && pointCount > 2); 2895 delete gradient; 2896 } 2897 delete[] pointList; 2898 break; 2899 } 2900 case AS_STROKE_SHAPE: 2901 case AS_FILL_SHAPE: 2902 { 2903 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", 2904 Title())); 2905 2906 BRect shapeFrame; 2907 int32 opCount; 2908 int32 ptCount; 2909 2910 link.Read<BRect>(&shapeFrame); 2911 link.Read<int32>(&opCount); 2912 link.Read<int32>(&ptCount); 2913 2914 uint32* opList = new(nothrow) uint32[opCount]; 2915 BPoint* ptList = new(nothrow) BPoint[ptCount]; 2916 if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK && 2917 link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) { 2918 2919 // this might seem a bit weird, but under R5, the shapes 2920 // are always offset by the current pen location 2921 BPoint screenOffset 2922 = fCurrentView->CurrentState()->PenLocation(); 2923 shapeFrame.OffsetBy(screenOffset); 2924 2925 const SimpleTransform transform = 2926 fCurrentView->PenToScreenTransform(); 2927 transform.Apply(&screenOffset); 2928 transform.Apply(&shapeFrame); 2929 2930 drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, 2931 ptList, code == AS_FILL_SHAPE, screenOffset, 2932 fCurrentView->Scale()); 2933 } 2934 2935 delete[] opList; 2936 delete[] ptList; 2937 break; 2938 } 2939 case AS_FILL_SHAPE_GRADIENT: 2940 { 2941 DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n", 2942 Title())); 2943 2944 BRect shapeFrame; 2945 int32 opCount; 2946 int32 ptCount; 2947 2948 link.Read<BRect>(&shapeFrame); 2949 link.Read<int32>(&opCount); 2950 link.Read<int32>(&ptCount); 2951 2952 uint32* opList = new(nothrow) uint32[opCount]; 2953 BPoint* ptList = new(nothrow) BPoint[ptCount]; 2954 BGradient* gradient; 2955 if (link.Read(opList, opCount * sizeof(uint32)) == B_OK 2956 && link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK 2957 && link.ReadGradient(&gradient) == B_OK) { 2958 2959 // this might seem a bit weird, but under R5, the shapes 2960 // are always offset by the current pen location 2961 BPoint screenOffset 2962 = fCurrentView->CurrentState()->PenLocation(); 2963 shapeFrame.OffsetBy(screenOffset); 2964 2965 const SimpleTransform transform = 2966 fCurrentView->PenToScreenTransform(); 2967 transform.Apply(&screenOffset); 2968 transform.Apply(&shapeFrame); 2969 transform.Apply(gradient); 2970 drawingEngine->FillShape(shapeFrame, opCount, opList, 2971 ptCount, ptList, *gradient, screenOffset, 2972 fCurrentView->Scale()); 2973 delete gradient; 2974 } 2975 2976 delete[] opList; 2977 delete[] ptList; 2978 break; 2979 } 2980 case AS_FILL_REGION: 2981 { 2982 DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title())); 2983 2984 BRegion region; 2985 if (link.ReadRegion(®ion) < B_OK) 2986 break; 2987 2988 fCurrentView->PenToScreenTransform().Apply(®ion); 2989 drawingEngine->FillRegion(region); 2990 2991 break; 2992 } 2993 case AS_FILL_REGION_GRADIENT: 2994 { 2995 DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n", 2996 Title())); 2997 2998 BRegion region; 2999 link.ReadRegion(®ion); 3000 3001 BGradient* gradient; 3002 if (link.ReadGradient(&gradient) != B_OK) 3003 break; 3004 3005 const SimpleTransform transform = 3006 fCurrentView->PenToScreenTransform(); 3007 transform.Apply(®ion); 3008 transform.Apply(gradient); 3009 drawingEngine->FillRegion(region, *gradient); 3010 delete gradient; 3011 break; 3012 } 3013 case AS_STROKE_LINEARRAY: 3014 { 3015 DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", 3016 Title())); 3017 3018 // Attached Data: 3019 // 1) int32 Number of lines in the array 3020 // 2) LineArrayData 3021 3022 int32 lineCount; 3023 if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0) 3024 break; 3025 3026 // To speed things up, try to use a stack allocation and only 3027 // fall back to the heap if there are enough lines... 3028 ViewLineArrayInfo* lineData; 3029 const int32 kStackBufferLineDataCount = 64; 3030 ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount]; 3031 if (lineCount > kStackBufferLineDataCount) { 3032 lineData = new(std::nothrow) ViewLineArrayInfo[lineCount]; 3033 if (lineData == NULL) 3034 break; 3035 } else 3036 lineData = lineDataStackBuffer; 3037 3038 // Read them all in one go 3039 size_t dataSize = lineCount * sizeof(ViewLineArrayInfo); 3040 if (link.Read(lineData, dataSize) != B_OK) { 3041 if (lineData != lineDataStackBuffer) 3042 delete[] lineData; 3043 break; 3044 } 3045 3046 // Convert to screen coords and draw 3047 const SimpleTransform transform = 3048 fCurrentView->PenToScreenTransform(); 3049 for (int32 i = 0; i < lineCount; i++) { 3050 transform.Apply(&lineData[i].startPoint); 3051 transform.Apply(&lineData[i].endPoint); 3052 } 3053 drawingEngine->StrokeLineArray(lineCount, lineData); 3054 3055 if (lineData != lineDataStackBuffer) 3056 delete[] lineData; 3057 break; 3058 } 3059 case AS_DRAW_STRING: 3060 case AS_DRAW_STRING_WITH_DELTA: 3061 { 3062 ViewDrawStringInfo info; 3063 if (link.Read<ViewDrawStringInfo>(&info) != B_OK 3064 || info.stringLength <= 0) { 3065 break; 3066 } 3067 3068 // NOTE: Careful, the + 1 is for termination! 3069 BStackOrHeapArray<char, 4096> string( 3070 (info.stringLength + 1 + 63) / 64 * 64); 3071 if (!string.IsValid()) 3072 break; 3073 3074 escapement_delta* delta = NULL; 3075 if (code == AS_DRAW_STRING_WITH_DELTA) { 3076 // In this case, info.delta will contain valid values. 3077 delta = &info.delta; 3078 } 3079 3080 if (link.Read(string, info.stringLength) != B_OK) 3081 break; 3082 3083 // Terminate the string, if nothing else, it's important 3084 // for the DTRACE call below... 3085 string[info.stringLength] = '\0'; 3086 3087 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s " 3088 "-> %s\n", Title(), fCurrentView->Name(), string)); 3089 3090 fCurrentView->PenToScreenTransform().Apply(&info.location); 3091 BPoint penLocation = drawingEngine->DrawString(string, 3092 info.stringLength, info.location, delta); 3093 3094 fCurrentView->ScreenToPenTransform().Apply(&penLocation); 3095 fCurrentView->CurrentState()->SetPenLocation(penLocation); 3096 3097 break; 3098 } 3099 case AS_DRAW_STRING_WITH_OFFSETS: 3100 { 3101 int32 stringLength; 3102 if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0) 3103 break; 3104 3105 int32 glyphCount; 3106 if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0) 3107 break; 3108 3109 // NOTE: Careful, the + 1 is for termination! 3110 BStackOrHeapArray<char, 512> string( 3111 (stringLength + 1 + 63) / 64 * 64); 3112 BStackOrHeapArray<BPoint, 512> locations(glyphCount); 3113 if (!string.IsValid() || !locations.IsValid()) 3114 break; 3115 3116 if (link.Read(string, stringLength) != B_OK) 3117 break; 3118 // Count UTF8 glyphs and make sure we have enough locations 3119 if ((int32)UTF8CountChars(string, stringLength) > glyphCount) 3120 break; 3121 if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK) 3122 break; 3123 // Terminate the string, if nothing else, it's important 3124 // for the DTRACE call below... 3125 string[stringLength] = '\0'; 3126 3127 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s " 3128 "-> %s\n", Title(), fCurrentView->Name(), string)); 3129 3130 const SimpleTransform transform = 3131 fCurrentView->PenToScreenTransform(); 3132 for (int32 i = 0; i < glyphCount; i++) 3133 transform.Apply(&locations[i]); 3134 3135 BPoint penLocation = drawingEngine->DrawString(string, 3136 stringLength, locations); 3137 3138 fCurrentView->ScreenToPenTransform().Apply(&penLocation); 3139 fCurrentView->CurrentState()->SetPenLocation(penLocation); 3140 3141 break; 3142 } 3143 3144 case AS_VIEW_DRAW_PICTURE: 3145 { 3146 int32 token; 3147 link.Read<int32>(&token); 3148 3149 BPoint where; 3150 if (link.Read<BPoint>(&where) == B_OK) { 3151 BReference<ServerPicture> picture(App()->GetPicture(token), true); 3152 if (picture != NULL) { 3153 // Setting the drawing origin outside of the 3154 // state makes sure that everything the picture 3155 // does is relative to the global picture offset. 3156 fCurrentView->PushState(); 3157 fCurrentView->SetDrawingOrigin(where); 3158 3159 fCurrentView->PushState(); 3160 picture->Play(fCurrentView); 3161 fCurrentView->PopState(); 3162 3163 fCurrentView->PopState(); 3164 } 3165 } 3166 break; 3167 } 3168 3169 case AS_VIEW_END_LAYER: 3170 { 3171 DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n", 3172 Title())); 3173 3174 fCurrentView->BlendAllLayers(); 3175 fCurrentView->SetPicture(NULL); 3176 fCurrentView->CurrentState()->SetDrawingModeLocked(false); 3177 break; 3178 } 3179 3180 default: 3181 debug_printf("ServerWindow %s received unexpected code: %s\n", 3182 Title(), string_for_message_code(code)); 3183 3184 if (link.NeedsReply()) { 3185 // the client is now blocking and waiting for a reply! 3186 fLink.StartMessage(B_ERROR); 3187 fLink.Flush(); 3188 } 3189 break; 3190 } 3191 3192 drawingEngine->UnlockParallelAccess(); 3193 } 3194 3195 3196 bool 3197 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) 3198 { 3199 ServerPicture* picture = fCurrentView->Picture(); 3200 if (picture == NULL) 3201 return false; 3202 3203 switch (code) { 3204 case AS_VIEW_SET_ORIGIN: 3205 { 3206 float x, y; 3207 link.Read<float>(&x); 3208 link.Read<float>(&y); 3209 3210 fCurrentView->SetDrawingOrigin(BPoint(x, y)); 3211 picture->WriteSetOrigin(BPoint(x, y)); 3212 break; 3213 } 3214 3215 case AS_VIEW_INVERT_RECT: 3216 { 3217 BRect rect; 3218 link.Read<BRect>(&rect); 3219 picture->WriteInvertRect(rect); 3220 break; 3221 } 3222 3223 case AS_VIEW_PUSH_STATE: 3224 { 3225 fCurrentView->PushState(); 3226 picture->WritePushState(); 3227 break; 3228 } 3229 3230 case AS_VIEW_POP_STATE: 3231 { 3232 fCurrentView->PopState(); 3233 picture->WritePopState(); 3234 break; 3235 } 3236 3237 case AS_VIEW_SET_DRAWING_MODE: 3238 { 3239 int8 drawingMode; 3240 link.Read<int8>(&drawingMode); 3241 3242 picture->WriteSetDrawingMode((drawing_mode)drawingMode); 3243 3244 fCurrentView->CurrentState()->SetDrawingMode( 3245 (drawing_mode)drawingMode); 3246 fWindow->GetDrawingEngine()->SetDrawingMode( 3247 (drawing_mode)drawingMode); 3248 break; 3249 } 3250 3251 case AS_VIEW_SET_PEN_LOC: 3252 { 3253 BPoint location; 3254 link.Read<BPoint>(&location); 3255 picture->WriteSetPenLocation(location); 3256 3257 fCurrentView->CurrentState()->SetPenLocation(location); 3258 break; 3259 } 3260 3261 case AS_VIEW_SET_PEN_SIZE: 3262 { 3263 float penSize; 3264 link.Read<float>(&penSize); 3265 picture->WriteSetPenSize(penSize); 3266 3267 fCurrentView->CurrentState()->SetPenSize(penSize); 3268 fWindow->GetDrawingEngine()->SetPenSize( 3269 fCurrentView->CurrentState()->PenSize()); 3270 break; 3271 } 3272 3273 case AS_VIEW_SET_LINE_MODE: 3274 { 3275 3276 ViewSetLineModeInfo info; 3277 link.Read<ViewSetLineModeInfo>(&info); 3278 3279 picture->WriteSetLineMode(info.lineCap, info.lineJoin, 3280 info.miterLimit); 3281 3282 fCurrentView->CurrentState()->SetLineCapMode(info.lineCap); 3283 fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin); 3284 fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit); 3285 3286 fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap, 3287 info.lineJoin, info.miterLimit); 3288 break; 3289 } 3290 case AS_VIEW_SET_FILL_RULE: 3291 { 3292 int32 fillRule; 3293 if (link.Read<int32>(&fillRule) != B_OK) 3294 break; 3295 3296 picture->WriteSetFillRule(fillRule); 3297 3298 fCurrentView->CurrentState()->SetFillRule(fillRule); 3299 fWindow->GetDrawingEngine()->SetFillRule(fillRule); 3300 3301 break; 3302 } 3303 case AS_VIEW_SET_SCALE: 3304 { 3305 float scale; 3306 if (link.Read<float>(&scale) != B_OK) 3307 break; 3308 3309 picture->WriteSetScale(scale); 3310 3311 fCurrentView->SetScale(scale); 3312 _UpdateDrawState(fCurrentView); 3313 break; 3314 } 3315 case AS_VIEW_SET_TRANSFORM: 3316 { 3317 BAffineTransform transform; 3318 if (link.Read<BAffineTransform>(&transform) != B_OK) 3319 break; 3320 3321 picture->WriteSetTransform(transform); 3322 3323 fCurrentView->CurrentState()->SetTransform(transform); 3324 _UpdateDrawState(fCurrentView); 3325 break; 3326 } 3327 3328 case AS_VIEW_AFFINE_TRANSLATE: 3329 { 3330 double x, y; 3331 link.Read<double>(&x); 3332 link.Read<double>(&y); 3333 3334 picture->WriteTranslateBy(x, y); 3335 3336 BAffineTransform current = 3337 fCurrentView->CurrentState()->Transform(); 3338 current.PreTranslateBy(x, y); 3339 fCurrentView->CurrentState()->SetTransform(current); 3340 _UpdateDrawState(fCurrentView); 3341 break; 3342 } 3343 3344 case AS_VIEW_AFFINE_SCALE: 3345 { 3346 double x, y; 3347 link.Read<double>(&x); 3348 link.Read<double>(&y); 3349 3350 picture->WriteScaleBy(x, y); 3351 3352 BAffineTransform current = 3353 fCurrentView->CurrentState()->Transform(); 3354 current.PreScaleBy(x, y); 3355 fCurrentView->CurrentState()->SetTransform(current); 3356 _UpdateDrawState(fCurrentView); 3357 break; 3358 } 3359 3360 case AS_VIEW_AFFINE_ROTATE: 3361 { 3362 double angleRadians; 3363 link.Read<double>(&angleRadians); 3364 3365 picture->WriteRotateBy(angleRadians); 3366 3367 BAffineTransform current = 3368 fCurrentView->CurrentState()->Transform(); 3369 current.PreRotateBy(angleRadians); 3370 fCurrentView->CurrentState()->SetTransform(current); 3371 _UpdateDrawState(fCurrentView); 3372 break; 3373 } 3374 3375 3376 case AS_VIEW_SET_PATTERN: 3377 { 3378 pattern pat; 3379 link.Read(&pat, sizeof(pattern)); 3380 picture->WriteSetPattern(pat); 3381 break; 3382 } 3383 3384 case AS_VIEW_SET_FONT_STATE: 3385 { 3386 uint16 mask = fCurrentView->CurrentState()->ReadFontFromLink(link); 3387 fWindow->GetDrawingEngine()->SetFont( 3388 fCurrentView->CurrentState()); 3389 3390 picture->WriteFontState(fCurrentView->CurrentState()->Font(), mask); 3391 break; 3392 } 3393 3394 case AS_FILL_RECT: 3395 case AS_STROKE_RECT: 3396 { 3397 BRect rect; 3398 link.Read<BRect>(&rect); 3399 3400 picture->WriteDrawRect(rect, code == AS_FILL_RECT); 3401 break; 3402 } 3403 3404 case AS_FILL_REGION: 3405 { 3406 // There is no B_PIC_FILL_REGION op, we have to 3407 // implement it using B_PIC_FILL_RECT 3408 BRegion region; 3409 if (link.ReadRegion(®ion) < B_OK) 3410 break; 3411 for (int32 i = 0; i < region.CountRects(); i++) 3412 picture->WriteDrawRect(region.RectAt(i), true); 3413 break; 3414 } 3415 3416 case AS_STROKE_ROUNDRECT: 3417 case AS_FILL_ROUNDRECT: 3418 { 3419 BRect rect; 3420 link.Read<BRect>(&rect); 3421 3422 BPoint radii; 3423 link.Read<float>(&radii.x); 3424 link.Read<float>(&radii.y); 3425 3426 picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT); 3427 break; 3428 } 3429 3430 case AS_STROKE_ELLIPSE: 3431 case AS_FILL_ELLIPSE: 3432 { 3433 BRect rect; 3434 link.Read<BRect>(&rect); 3435 picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE); 3436 break; 3437 } 3438 3439 case AS_STROKE_ARC: 3440 case AS_FILL_ARC: 3441 { 3442 BRect rect; 3443 link.Read<BRect>(&rect); 3444 float startTheta, arcTheta; 3445 link.Read<float>(&startTheta); 3446 link.Read<float>(&arcTheta); 3447 3448 BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2); 3449 BPoint center = rect.LeftTop() + radii; 3450 3451 picture->WriteDrawArc(center, radii, startTheta, arcTheta, 3452 code == AS_FILL_ARC); 3453 break; 3454 } 3455 3456 case AS_STROKE_TRIANGLE: 3457 case AS_FILL_TRIANGLE: 3458 { 3459 // There is no B_PIC_FILL/STROKE_TRIANGLE op, 3460 // we implement it using B_PIC_FILL/STROKE_POLYGON 3461 BPoint points[3]; 3462 3463 for (int32 i = 0; i < 3; i++) { 3464 link.Read<BPoint>(&(points[i])); 3465 } 3466 3467 BRect rect; 3468 link.Read<BRect>(&rect); 3469 3470 picture->WriteDrawPolygon(3, points, 3471 true, code == AS_FILL_TRIANGLE); 3472 break; 3473 } 3474 case AS_STROKE_POLYGON: 3475 case AS_FILL_POLYGON: 3476 { 3477 BRect polyFrame; 3478 bool isClosed = true; 3479 int32 pointCount; 3480 const bool fill = (code == AS_FILL_POLYGON); 3481 3482 link.Read<BRect>(&polyFrame); 3483 if (code == AS_STROKE_POLYGON) 3484 link.Read<bool>(&isClosed); 3485 link.Read<int32>(&pointCount); 3486 3487 BPoint* pointList = new(nothrow) BPoint[pointCount]; 3488 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { 3489 picture->WriteDrawPolygon(pointCount, pointList, 3490 isClosed && pointCount > 2, fill); 3491 } 3492 delete[] pointList; 3493 break; 3494 } 3495 3496 case AS_STROKE_BEZIER: 3497 case AS_FILL_BEZIER: 3498 { 3499 BPoint points[4]; 3500 for (int32 i = 0; i < 4; i++) { 3501 link.Read<BPoint>(&(points[i])); 3502 } 3503 picture->WriteDrawBezier(points, code == AS_FILL_BEZIER); 3504 break; 3505 } 3506 3507 //case AS_STROKE_RECT_GRADIENT: 3508 case AS_FILL_RECT_GRADIENT: 3509 { 3510 BRect rect; 3511 link.Read<BRect>(&rect); 3512 BGradient* gradient; 3513 if (link.ReadGradient(&gradient) != B_OK) 3514 break; 3515 ObjectDeleter<BGradient> gradientDeleter(gradient); 3516 3517 picture->WriteDrawRectGradient(rect, *gradient, code == AS_FILL_RECT_GRADIENT); 3518 break; 3519 } 3520 3521 //case AS_STROKE_ARC_GRADIENT: 3522 case AS_FILL_ARC_GRADIENT: 3523 { 3524 BRect rect; 3525 link.Read<BRect>(&rect); 3526 float startTheta, arcTheta; 3527 link.Read<float>(&startTheta); 3528 link.Read<float>(&arcTheta); 3529 BGradient* gradient; 3530 if (link.ReadGradient(&gradient) != B_OK) 3531 break; 3532 ObjectDeleter<BGradient> gradientDeleter(gradient); 3533 3534 BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2); 3535 BPoint center = rect.LeftTop() + radii; 3536 3537 picture->WriteDrawArcGradient(center, radii, startTheta, arcTheta, *gradient, 3538 code == AS_FILL_ARC_GRADIENT); 3539 break; 3540 } 3541 3542 //case AS_STROKE_BEZIER_GRADIENT: 3543 case AS_FILL_BEZIER_GRADIENT: 3544 { 3545 BPoint points[4]; 3546 for (int32 i = 0; i < 4; i++) { 3547 link.Read<BPoint>(&(points[i])); 3548 } 3549 BGradient* gradient; 3550 if (link.ReadGradient(&gradient) != B_OK) 3551 break; 3552 ObjectDeleter<BGradient> gradientDeleter(gradient); 3553 3554 picture->WriteDrawBezierGradient(points, *gradient, code == AS_FILL_BEZIER_GRADIENT); 3555 break; 3556 } 3557 3558 //case AS_STROKE_ELLIPSE_GRADIENT: 3559 case AS_FILL_ELLIPSE_GRADIENT: 3560 { 3561 BRect rect; 3562 link.Read<BRect>(&rect); 3563 BGradient* gradient; 3564 if (link.ReadGradient(&gradient) != B_OK) 3565 break; 3566 ObjectDeleter<BGradient> gradientDeleter(gradient); 3567 3568 picture->WriteDrawEllipseGradient(rect, *gradient, code == AS_FILL_ELLIPSE_GRADIENT); 3569 break; 3570 } 3571 3572 //case AS_STROKE_ROUNDRECT_GRADIENT: 3573 case AS_FILL_ROUNDRECT_GRADIENT: 3574 { 3575 BRect rect; 3576 link.Read<BRect>(&rect); 3577 3578 BPoint radii; 3579 link.Read<float>(&radii.x); 3580 link.Read<float>(&radii.y); 3581 BGradient* gradient; 3582 if (link.ReadGradient(&gradient) != B_OK) 3583 break; 3584 ObjectDeleter<BGradient> gradientDeleter(gradient); 3585 3586 picture->WriteDrawRoundRectGradient(rect, radii, *gradient, code == AS_FILL_ROUNDRECT_GRADIENT); 3587 break; 3588 } 3589 3590 //case AS_STROKE_TRIANGLE_GRADIENT: 3591 case AS_FILL_TRIANGLE_GRADIENT: 3592 { 3593 // There is no B_PIC_FILL/STROKE_TRIANGLE op, 3594 // we implement it using B_PIC_FILL/STROKE_POLYGON 3595 BPoint points[3]; 3596 3597 for (int32 i = 0; i < 3; i++) { 3598 link.Read<BPoint>(&(points[i])); 3599 } 3600 3601 BRect rect; 3602 link.Read<BRect>(&rect); 3603 BGradient* gradient; 3604 if (link.ReadGradient(&gradient) != B_OK) 3605 break; 3606 ObjectDeleter<BGradient> gradientDeleter(gradient); 3607 3608 picture->WriteDrawPolygonGradient(3, points, 3609 true, *gradient, code == AS_FILL_TRIANGLE_GRADIENT); 3610 break; 3611 } 3612 3613 //case AS_STROKE_POLYGON_GRADIENT: 3614 case AS_FILL_POLYGON_GRADIENT: 3615 { 3616 BRect polyFrame; 3617 bool isClosed = true; 3618 int32 pointCount; 3619 const bool fill = (code == AS_FILL_POLYGON_GRADIENT); 3620 3621 link.Read<BRect>(&polyFrame); 3622 if (code == AS_STROKE_POLYGON) 3623 link.Read<bool>(&isClosed); 3624 link.Read<int32>(&pointCount); 3625 3626 ArrayDeleter<BPoint> pointList(new(nothrow) BPoint[pointCount]); 3627 if (link.Read(pointList.Get(), pointCount * sizeof(BPoint)) != B_OK) 3628 break; 3629 3630 BGradient* gradient; 3631 if (link.ReadGradient(&gradient) != B_OK) 3632 break; 3633 ObjectDeleter<BGradient> gradientDeleter(gradient); 3634 3635 picture->WriteDrawPolygonGradient(pointCount, pointList.Get(), 3636 isClosed && pointCount > 2, *gradient, fill); 3637 break; 3638 } 3639 3640 //case AS_STROKE_SHAPE_GRADIENT: 3641 case AS_FILL_SHAPE_GRADIENT: 3642 { 3643 BRect shapeFrame; 3644 int32 opCount; 3645 int32 ptCount; 3646 3647 link.Read<BRect>(&shapeFrame); 3648 link.Read<int32>(&opCount); 3649 link.Read<int32>(&ptCount); 3650 3651 ArrayDeleter<uint32> opList(new(std::nothrow) uint32[opCount]); 3652 ArrayDeleter<BPoint> ptList(new(std::nothrow) BPoint[ptCount]); 3653 if (!opList.IsSet() || !ptList.IsSet() 3654 || link.Read(opList.Get(), opCount * sizeof(uint32)) != B_OK 3655 || link.Read(ptList.Get(), ptCount * sizeof(BPoint)) != B_OK) 3656 break; 3657 3658 BGradient* gradient; 3659 if (link.ReadGradient(&gradient) != B_OK) 3660 break; 3661 ObjectDeleter<BGradient> gradientDeleter(gradient); 3662 3663 // This might seem a bit weird, but under BeOS, the shapes 3664 // are always offset by the current pen location 3665 BPoint penLocation 3666 = fCurrentView->CurrentState()->PenLocation(); 3667 for (int32 i = 0; i < ptCount; i++) { 3668 ptList.Get()[i] += penLocation; 3669 } 3670 const bool fill = (code == AS_FILL_SHAPE_GRADIENT); 3671 picture->WriteDrawShapeGradient(opCount, opList.Get(), ptCount, ptList.Get(), *gradient, fill); 3672 3673 break; 3674 } 3675 3676 case AS_FILL_REGION_GRADIENT: 3677 { 3678 // There is no B_PIC_FILL_REGION op, we have to 3679 // implement it using B_PIC_FILL_RECT 3680 BRegion region; 3681 if (link.ReadRegion(®ion) < B_OK) 3682 break; 3683 3684 BGradient* gradient; 3685 if (link.ReadGradient(&gradient) != B_OK) 3686 break; 3687 ObjectDeleter<BGradient> gradientDeleter(gradient); 3688 3689 for (int32 i = 0; i < region.CountRects(); i++) 3690 picture->WriteDrawRectGradient(region.RectAt(i), *gradient, true); 3691 break; 3692 } 3693 3694 case AS_STROKE_LINE: 3695 { 3696 ViewStrokeLineInfo info; 3697 link.Read<ViewStrokeLineInfo>(&info); 3698 3699 picture->WriteStrokeLine(info.startPoint, info.endPoint); 3700 3701 BPoint penPos = info.endPoint; 3702 const SimpleTransform transform = 3703 fCurrentView->PenToScreenTransform(); 3704 transform.Apply(&info.endPoint); 3705 fCurrentView->CurrentState()->SetPenLocation(penPos); 3706 break; 3707 } 3708 3709 case AS_STROKE_LINEARRAY: 3710 { 3711 int32 lineCount; 3712 if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0) 3713 break; 3714 3715 // To speed things up, try to use a stack allocation and only 3716 // fall back to the heap if there are enough lines... 3717 ViewLineArrayInfo* lineData; 3718 const int32 kStackBufferLineDataCount = 64; 3719 ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount]; 3720 if (lineCount > kStackBufferLineDataCount) { 3721 lineData = new(std::nothrow) ViewLineArrayInfo[lineCount]; 3722 if (lineData == NULL) 3723 break; 3724 } else 3725 lineData = lineDataStackBuffer; 3726 3727 // Read them all in one go 3728 size_t dataSize = lineCount * sizeof(ViewLineArrayInfo); 3729 if (link.Read(lineData, dataSize) != B_OK) { 3730 if (lineData != lineDataStackBuffer) 3731 delete[] lineData; 3732 break; 3733 } 3734 3735 picture->WritePushState(); 3736 3737 for (int32 i = 0; i < lineCount; i++) { 3738 picture->WriteSetHighColor(lineData[i].color); 3739 picture->WriteStrokeLine(lineData[i].startPoint, 3740 lineData[i].endPoint); 3741 } 3742 3743 picture->WritePopState(); 3744 3745 if (lineData != lineDataStackBuffer) 3746 delete[] lineData; 3747 break; 3748 } 3749 3750 case AS_VIEW_SET_LOW_COLOR: 3751 case AS_VIEW_SET_HIGH_COLOR: 3752 { 3753 rgb_color color; 3754 link.Read(&color, sizeof(rgb_color)); 3755 3756 if (code == AS_VIEW_SET_HIGH_COLOR) { 3757 picture->WriteSetHighColor(color); 3758 fCurrentView->CurrentState()->SetHighColor(color); 3759 fWindow->GetDrawingEngine()->SetHighColor(color); 3760 } else { 3761 picture->WriteSetLowColor(color); 3762 fCurrentView->CurrentState()->SetLowColor(color); 3763 fWindow->GetDrawingEngine()->SetLowColor(color); 3764 } 3765 } break; 3766 3767 case AS_DRAW_STRING: 3768 case AS_DRAW_STRING_WITH_DELTA: 3769 { 3770 ViewDrawStringInfo info; 3771 if (link.Read<ViewDrawStringInfo>(&info) != B_OK) 3772 break; 3773 3774 char* string = (char*)malloc(info.stringLength + 1); 3775 if (string == NULL) 3776 break; 3777 3778 if (code != AS_DRAW_STRING_WITH_DELTA) { 3779 // In this case, info.delta will NOT contain valid values. 3780 info.delta = (escapement_delta){ 0, 0 }; 3781 } 3782 3783 if (link.Read(string, info.stringLength) != B_OK) { 3784 free(string); 3785 break; 3786 } 3787 // Terminate the string 3788 string[info.stringLength] = '\0'; 3789 3790 picture->WriteDrawString(info.location, string, info.stringLength, 3791 info.delta); 3792 3793 // We need to update the pen location 3794 fCurrentView->PenToScreenTransform().Apply(&info.location); 3795 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 3796 if (drawingEngine->LockParallelAccess()) { 3797 BPoint penLocation = drawingEngine->DrawStringDry( 3798 string, info.stringLength, info.location, &info.delta); 3799 3800 fCurrentView->ScreenToPenTransform().Apply(&penLocation); 3801 fCurrentView->CurrentState()->SetPenLocation(penLocation); 3802 3803 drawingEngine->UnlockParallelAccess(); 3804 } 3805 3806 free(string); 3807 break; 3808 } 3809 3810 case AS_DRAW_STRING_WITH_OFFSETS: 3811 { 3812 int32 stringLength; 3813 if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0) 3814 break; 3815 3816 int32 glyphCount; 3817 if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0) 3818 break; 3819 3820 // NOTE: Careful, the + 1 is for termination! 3821 BStackOrHeapArray<char, 512> string( 3822 (stringLength + 1 + 63) / 64 * 64); 3823 BStackOrHeapArray<BPoint, 512> locations(glyphCount); 3824 if (!string.IsValid() || !locations.IsValid()) 3825 break; 3826 3827 if (link.Read(string, stringLength) != B_OK) 3828 break; 3829 // Count UTF8 glyphs and make sure we have enough locations 3830 if ((int32)UTF8CountChars(string, stringLength) > glyphCount) 3831 break; 3832 if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK) 3833 break; 3834 // Terminate the string 3835 string[stringLength] = '\0'; 3836 3837 const SimpleTransform transform = 3838 fCurrentView->PenToScreenTransform(); 3839 for (int32 i = 0; i < glyphCount; i++) 3840 transform.Apply(&locations[i]); 3841 3842 picture->WriteDrawString(string, stringLength, locations, 3843 glyphCount); 3844 3845 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 3846 if (drawingEngine->LockParallelAccess()) { 3847 // Update pen location 3848 BPoint penLocation = drawingEngine->DrawStringDry( 3849 string, stringLength, locations); 3850 3851 fCurrentView->ScreenToPenTransform().Apply(&penLocation); 3852 fCurrentView->CurrentState()->SetPenLocation(penLocation); 3853 3854 drawingEngine->UnlockParallelAccess(); 3855 } 3856 3857 break; 3858 } 3859 3860 case AS_STROKE_SHAPE: 3861 case AS_FILL_SHAPE: 3862 { 3863 BRect shapeFrame; 3864 int32 opCount; 3865 int32 ptCount; 3866 3867 link.Read<BRect>(&shapeFrame); 3868 link.Read<int32>(&opCount); 3869 link.Read<int32>(&ptCount); 3870 3871 BStackOrHeapArray<uint32, 512> opList(opCount); 3872 BStackOrHeapArray<BPoint, 512> ptList(ptCount); 3873 if (!opList.IsValid() || !ptList.IsValid() 3874 || link.Read(opList, opCount * sizeof(uint32)) < B_OK 3875 || link.Read(ptList, ptCount * sizeof(BPoint)) < B_OK) { 3876 break; 3877 } 3878 picture->WriteDrawShape(opCount, opList, ptCount, 3879 ptList, code == AS_FILL_SHAPE); 3880 3881 break; 3882 } 3883 3884 case AS_VIEW_DRAW_BITMAP: 3885 { 3886 ViewDrawBitmapInfo info; 3887 link.Read<ViewDrawBitmapInfo>(&info); 3888 3889 BReference<ServerBitmap> bitmap(App()->GetBitmap(info.bitmapToken), true); 3890 if (bitmap == NULL) 3891 break; 3892 3893 picture->WriteDrawBitmap(info.bitmapRect, info.viewRect, 3894 bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(), 3895 bitmap->ColorSpace(), info.options, bitmap->Bits(), 3896 bitmap->BitsLength()); 3897 3898 break; 3899 } 3900 3901 case AS_VIEW_DRAW_PICTURE: 3902 { 3903 int32 token; 3904 link.Read<int32>(&token); 3905 3906 BPoint where; 3907 if (link.Read<BPoint>(&where) == B_OK) { 3908 BReference<ServerPicture> pictureToDraw(App()->GetPicture(token), true); 3909 if (pictureToDraw != NULL) { 3910 // We need to make a copy of the picture, since it can 3911 // change after it has been drawn 3912 BReference<ServerPicture> copy(App()->CreatePicture(pictureToDraw), true); 3913 picture->NestPicture(copy); 3914 picture->WriteDrawPicture(where, copy->Token()); 3915 } 3916 } 3917 break; 3918 } 3919 3920 case AS_VIEW_SET_CLIP_REGION: 3921 { 3922 int32 rectCount; 3923 status_t status = link.Read<int32>(&rectCount); 3924 // a negative count means no 3925 // region for the current draw state, 3926 // but an *empty* region is actually valid! 3927 // even if it means no drawing is allowed 3928 3929 if (status < B_OK) 3930 break; 3931 3932 if (rectCount >= 0) { 3933 // we are supposed to set the clipping region 3934 BRegion region; 3935 if (rectCount > 0 && link.ReadRegion(®ion) < B_OK) 3936 break; 3937 picture->WriteSetClipping(region); 3938 } else { 3939 // we are supposed to clear the clipping region 3940 picture->WriteClearClipping(); 3941 } 3942 break; 3943 } 3944 3945 case AS_VIEW_CLIP_TO_PICTURE: 3946 { 3947 int32 pictureToken; 3948 BPoint where; 3949 bool inverse = false; 3950 3951 link.Read<int32>(&pictureToken); 3952 if (pictureToken < 0) 3953 break; 3954 3955 link.Read<BPoint>(&where); 3956 if (link.Read<bool>(&inverse) != B_OK) 3957 break; 3958 3959 BReference<ServerPicture> pictureToClip(fServerApp->GetPicture(pictureToken), true); 3960 if (pictureToClip != NULL) { 3961 // We need to make a copy of the picture, since it can 3962 // change after it has been drawn 3963 BReference<ServerPicture> copy(App()->CreatePicture(pictureToClip), true); 3964 picture->NestPicture(copy); 3965 picture->WriteClipToPicture(copy->Token(), where, inverse); 3966 } 3967 break; 3968 } 3969 3970 case AS_VIEW_CLIP_TO_RECT: 3971 { 3972 bool inverse; 3973 BRect rect; 3974 link.Read<bool>(&inverse); 3975 link.Read<BRect>(&rect); 3976 picture->WriteClipToRect(rect, inverse); 3977 3978 break; 3979 } 3980 3981 case AS_VIEW_CLIP_TO_SHAPE: 3982 { 3983 bool inverse; 3984 link.Read<bool>(&inverse); 3985 3986 shape_data shape; 3987 link.Read<int32>(&shape.opCount); 3988 link.Read<int32>(&shape.ptCount); 3989 shape.opSize = shape.opCount * sizeof(uint32); 3990 shape.ptSize = shape.ptCount * sizeof(BPoint); 3991 shape.opList = new(nothrow) uint32[shape.opCount]; 3992 shape.ptList = new(nothrow) BPoint[shape.ptCount]; 3993 if (link.Read(shape.opList, shape.opSize) >= B_OK 3994 && link.Read(shape.ptList, shape.ptSize) >= B_OK) { 3995 picture->WriteClipToShape(shape.opCount, shape.opList, 3996 shape.ptCount, shape.ptList, inverse); 3997 } 3998 3999 delete[] shape.opList; 4000 delete[] shape.ptList; 4001 break; 4002 } 4003 4004 case AS_VIEW_BEGIN_PICTURE: 4005 { 4006 BReference <ServerPicture> newPicture(App()->CreatePicture(), true); 4007 if (newPicture != NULL) { 4008 newPicture->PushPicture(picture); 4009 newPicture->SyncState(fCurrentView); 4010 fCurrentView->SetPicture(newPicture); 4011 } 4012 break; 4013 } 4014 4015 case AS_VIEW_APPEND_TO_PICTURE: 4016 { 4017 int32 token; 4018 link.Read<int32>(&token); 4019 4020 BReference<ServerPicture> appendPicture(App()->GetPicture(token), true); 4021 if (appendPicture != NULL) { 4022 //picture->SyncState(fCurrentView); 4023 appendPicture->AppendPicture(picture); 4024 } 4025 4026 fCurrentView->SetPicture(appendPicture); 4027 4028 break; 4029 } 4030 4031 case AS_VIEW_END_PICTURE: 4032 { 4033 BReference<ServerPicture> poppedPicture(picture->PopPicture(), true); 4034 fCurrentView->SetPicture(poppedPicture); 4035 4036 fLink.StartMessage(B_OK); 4037 fLink.Attach<int32>(picture->Token()); 4038 fLink.Flush(); 4039 return true; 4040 } 4041 4042 case AS_VIEW_BEGIN_LAYER: 4043 { 4044 uint8 opacity; 4045 link.Read<uint8>(&opacity); 4046 4047 Layer* layer = dynamic_cast<Layer*>(picture); 4048 if (layer == NULL) 4049 break; 4050 4051 Layer* nextLayer = new(std::nothrow) Layer(opacity); 4052 if (nextLayer == NULL) 4053 break; 4054 4055 if (opacity != 255) { 4056 fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA); 4057 fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA, 4058 B_ALPHA_COMPOSITE); 4059 fCurrentView->CurrentState()->SetDrawingModeLocked(true); 4060 } 4061 4062 nextLayer->PushLayer(layer); 4063 fCurrentView->SetPicture(nextLayer); 4064 break; 4065 } 4066 4067 case AS_VIEW_END_LAYER: 4068 { 4069 Layer* layer = dynamic_cast<Layer*>(picture); 4070 if (layer == NULL) 4071 break; 4072 4073 BReference<Layer> previousLayer(layer->PopLayer(), true); 4074 if (previousLayer == NULL) { 4075 // End last layer 4076 return false; 4077 } 4078 fCurrentView->SetPicture(previousLayer); 4079 4080 previousLayer->WriteBlendLayer(layer); 4081 break; 4082 } 4083 4084 /* 4085 case AS_VIEW_SET_BLENDING_MODE: 4086 { 4087 ViewBlendingModeInfo info; 4088 link.Read<ViewBlendingModeInfo>(&info); 4089 4090 picture->BeginOp(B_PIC_SET_BLENDING_MODE); 4091 picture->AddInt16((int16)info.sourceAlpha); 4092 picture->AddInt16((int16)info.alphaFunction); 4093 picture->EndOp(); 4094 4095 fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha, 4096 info.alphaFunction); 4097 fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha, 4098 info.alphaFunction); 4099 break; 4100 }*/ 4101 default: 4102 return false; 4103 } 4104 4105 if (link.NeedsReply()) { 4106 fLink.StartMessage(B_ERROR); 4107 fLink.Flush(); 4108 } 4109 return true; 4110 } 4111 4112 4113 /*! \brief Message-dispatching loop for the ServerWindow 4114 4115 Watches the ServerWindow's message port and dispatches as necessary 4116 */ 4117 void 4118 ServerWindow::_MessageLooper() 4119 { 4120 // Send a reply to our window - it is expecting fMessagePort 4121 // port and some other info. 4122 4123 fLink.StartMessage(B_OK); 4124 fLink.Attach<port_id>(fMessagePort); 4125 4126 int32 minWidth, maxWidth, minHeight, maxHeight; 4127 fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); 4128 4129 fLink.Attach<BRect>(fWindow->Frame()); 4130 fLink.Attach<float>((float)minWidth); 4131 fLink.Attach<float>((float)maxWidth); 4132 fLink.Attach<float>((float)minHeight); 4133 fLink.Attach<float>((float)maxHeight); 4134 fLink.Flush(); 4135 4136 BPrivate::LinkReceiver& receiver = fLink.Receiver(); 4137 bool quitLoop = false; 4138 4139 while (!quitLoop) { 4140 //STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n", 4141 // fMessagePort)); 4142 4143 int32 code; 4144 status_t status = receiver.GetNextMessage(code); 4145 if (status != B_OK) { 4146 // that shouldn't happen, it's our port 4147 printf("Someone deleted our message port!\n"); 4148 4149 // try to let our client die happily 4150 NotifyQuitRequested(); 4151 break; 4152 } 4153 4154 #ifdef PROFILE_MESSAGE_LOOP 4155 bigtime_t start = system_time(); 4156 #endif 4157 4158 Lock(); 4159 4160 #ifdef PROFILE_MESSAGE_LOOP 4161 bigtime_t diff = system_time() - start; 4162 if (diff > 10000) { 4163 printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n", 4164 Title(), diff); 4165 } 4166 #endif 4167 4168 int32 messagesProcessed = 0; 4169 bigtime_t processingStart = system_time(); 4170 bool lockedDesktopSingleWindow = false; 4171 4172 while (true) { 4173 if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) { 4174 // this means the client has been killed 4175 DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message " 4176 "code\n", Title())); 4177 4178 if (code == AS_DELETE_WINDOW) { 4179 fLink.StartMessage(B_OK); 4180 fLink.Flush(); 4181 } 4182 4183 if (lockedDesktopSingleWindow) 4184 fDesktop->UnlockSingleWindow(); 4185 4186 quitLoop = true; 4187 4188 // ServerWindow's destructor takes care of pulling this object 4189 // off the desktop. 4190 ASSERT(fWindow->IsHidden()); 4191 break; 4192 } 4193 4194 // Acquire the appropriate lock 4195 bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code); 4196 if (needsAllWindowsLocked) { 4197 // We may already still hold the read-lock from the previous 4198 // inner-loop iteration. 4199 if (lockedDesktopSingleWindow) { 4200 fDesktop->UnlockSingleWindow(); 4201 lockedDesktopSingleWindow = false; 4202 } 4203 fDesktop->LockAllWindows(); 4204 } else { 4205 // We never keep the write-lock across inner-loop iterations, 4206 // so there is nothing else to do besides read-locking unless 4207 // we already have the read-lock from the previous iteration. 4208 if (!lockedDesktopSingleWindow) { 4209 fDesktop->LockSingleWindow(); 4210 lockedDesktopSingleWindow = true; 4211 } 4212 } 4213 4214 if (atomic_and(&fRedrawRequested, 0) != 0) { 4215 #ifdef PROFILE_MESSAGE_LOOP 4216 bigtime_t redrawStart = system_time(); 4217 #endif 4218 fWindow->RedrawDirtyRegion(); 4219 #ifdef PROFILE_MESSAGE_LOOP 4220 diff = system_time() - redrawStart; 4221 atomic_add(&sRedrawProcessingTime.count, 1); 4222 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 4223 atomic_add64(&sRedrawProcessingTime.time, diff); 4224 # else 4225 sRedrawProcessingTime.time += diff; 4226 # endif 4227 #endif 4228 } 4229 4230 #ifdef PROFILE_MESSAGE_LOOP 4231 bigtime_t dispatchStart = system_time(); 4232 #endif 4233 _DispatchMessage(code, receiver); 4234 4235 #ifdef PROFILE_MESSAGE_LOOP 4236 if (code >= 0 && code < AS_LAST_CODE) { 4237 diff = system_time() - dispatchStart; 4238 atomic_add(&sMessageProfile[code].count, 1); 4239 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 4240 atomic_add64(&sMessageProfile[code].time, diff); 4241 #else 4242 sMessageProfile[code].time += diff; 4243 #endif 4244 if (diff > 10000) { 4245 printf("ServerWindow %s: message %" B_PRId32 " took %" 4246 B_PRId64 " usecs\n", Title(), code, diff); 4247 } 4248 } 4249 #endif 4250 4251 if (needsAllWindowsLocked) 4252 fDesktop->UnlockAllWindows(); 4253 4254 // Only process up to 70 waiting messages at once (we have the 4255 // Desktop locked), but don't hold the lock longer than 10 ms 4256 if (!receiver.HasMessages() || ++messagesProcessed > 70 4257 || system_time() - processingStart > 10000) { 4258 if (lockedDesktopSingleWindow) 4259 fDesktop->UnlockSingleWindow(); 4260 break; 4261 } 4262 4263 // next message 4264 status_t status = receiver.GetNextMessage(code); 4265 if (status != B_OK) { 4266 // that shouldn't happen, it's our port 4267 printf("Someone deleted our message port!\n"); 4268 if (lockedDesktopSingleWindow) 4269 fDesktop->UnlockSingleWindow(); 4270 4271 // try to let our client die happily 4272 NotifyQuitRequested(); 4273 break; 4274 } 4275 } 4276 4277 Unlock(); 4278 } 4279 4280 // We were asked to quit the message loop - either on request or because of 4281 // an error. 4282 Quit(); 4283 // does not return 4284 } 4285 4286 4287 void 4288 ServerWindow::ScreenChanged(const BMessage* message) 4289 { 4290 SendMessageToClient(message); 4291 4292 if (fDirectWindowInfo.IsSet() && fDirectWindowInfo->IsFullScreen()) 4293 _ResizeToFullScreen(); 4294 } 4295 4296 4297 status_t 4298 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const 4299 { 4300 if (target == B_NULL_TOKEN) 4301 target = fClientToken; 4302 4303 BMessenger reply; 4304 BMessage::Private messagePrivate((BMessage*)msg); 4305 return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target, 4306 0, false, reply); 4307 } 4308 4309 4310 Window* 4311 ServerWindow::MakeWindow(BRect frame, const char* name, 4312 window_look look, window_feel feel, uint32 flags, uint32 workspace) 4313 { 4314 // The non-offscreen ServerWindow uses the DrawingEngine instance from 4315 // the desktop. 4316 return new(std::nothrow) ::Window(frame, name, look, feel, flags, 4317 workspace, this, fDesktop->HWInterface()->CreateDrawingEngine()); 4318 } 4319 4320 4321 void 4322 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState) 4323 { 4324 ASSERT_MULTI_LOCKED(fDesktop->WindowLocker()); 4325 4326 if (!fDirectWindowInfo.IsSet()) 4327 return; 4328 4329 STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = " 4330 "%" B_PRId32 ")\n", bufferState, driverState)); 4331 4332 status_t status = fDirectWindowInfo->SetState( 4333 (direct_buffer_state)bufferState, (direct_driver_state)driverState, 4334 fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(), 4335 fWindow->VisibleContentRegion()); 4336 4337 if (status != B_OK) { 4338 char errorString[256]; 4339 snprintf(errorString, sizeof(errorString), 4340 "%s killed for a problem in DirectConnected(): %s", 4341 App()->Signature(), strerror(status)); 4342 syslog(LOG_ERR, errorString); 4343 4344 // The client application didn't release the semaphore 4345 // within the given timeout. Or something else went wrong. 4346 // Deleting this member should make it crash. 4347 fDirectWindowInfo.Unset(); 4348 } else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START) 4349 fIsDirectlyAccessing = true; 4350 else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) 4351 fIsDirectlyAccessing = false; 4352 } 4353 4354 4355 void 4356 ServerWindow::_SetCurrentView(View* view) 4357 { 4358 if (fCurrentView == view) 4359 return; 4360 4361 fCurrentView = view; 4362 fCurrentDrawingRegionValid = false; 4363 _UpdateDrawState(fCurrentView); 4364 4365 #if 0 4366 #if DELAYED_BACKGROUND_CLEARING 4367 if (fCurrentView && fCurrentView->IsBackgroundDirty() 4368 && fWindow->InUpdate()) { 4369 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 4370 if (drawingEngine->LockParallelAccess()) { 4371 fWindow->GetEffectiveDrawingRegion(fCurrentView, 4372 fCurrentDrawingRegion); 4373 fCurrentDrawingRegionValid = true; 4374 BRegion dirty(fCurrentDrawingRegion); 4375 4376 BRegion content; 4377 fWindow->GetContentRegion(&content); 4378 4379 fCurrentView->Draw(drawingEngine, &dirty, &content, false); 4380 4381 drawingEngine->UnlockParallelAccess(); 4382 } 4383 } 4384 #endif 4385 #endif // 0 4386 } 4387 4388 4389 void 4390 ServerWindow::_UpdateDrawState(View* view) 4391 { 4392 // switch the drawing state 4393 // TODO: is it possible to scroll a view while it 4394 // is being drawn? probably not... otherwise the 4395 // "offsets" passed below would need to be updated again 4396 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 4397 if (view != NULL && drawingEngine != NULL) { 4398 BPoint leftTop(0, 0); 4399 if (view->GetAlphaMask() != NULL) { 4400 view->LocalToScreenTransform().Apply(&leftTop); 4401 view->GetAlphaMask()->SetCanvasGeometry(leftTop, view->Bounds()); 4402 leftTop = BPoint(0, 0); 4403 } 4404 view->PenToScreenTransform().Apply(&leftTop); 4405 drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y); 4406 } 4407 } 4408 4409 4410 void 4411 ServerWindow::_UpdateCurrentDrawingRegion() 4412 { 4413 if (!fCurrentDrawingRegionValid 4414 || fWindow->DrawingRegionChanged(fCurrentView)) { 4415 fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion); 4416 fCurrentDrawingRegionValid = true; 4417 } 4418 } 4419 4420 4421 bool 4422 ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const 4423 { 4424 switch (code) { 4425 case AS_SET_WINDOW_TITLE: 4426 case AS_ADD_TO_SUBSET: 4427 case AS_REMOVE_FROM_SUBSET: 4428 case AS_VIEW_CREATE_ROOT: 4429 case AS_VIEW_CREATE: 4430 case AS_SEND_BEHIND: 4431 case AS_SET_LOOK: 4432 case AS_SET_FEEL: 4433 case AS_SET_FLAGS: 4434 case AS_SET_WORKSPACES: 4435 case AS_WINDOW_MOVE: 4436 case AS_WINDOW_RESIZE: 4437 case AS_SET_SIZE_LIMITS: 4438 case AS_SYSTEM_FONT_CHANGED: 4439 case AS_SET_DECORATOR_SETTINGS: 4440 case AS_GET_MOUSE: 4441 case AS_DIRECT_WINDOW_SET_FULLSCREEN: 4442 // case AS_VIEW_SET_EVENT_MASK: 4443 // case AS_VIEW_SET_MOUSE_EVENT_MASK: 4444 case AS_TALK_TO_DESKTOP_LISTENER: 4445 return true; 4446 default: 4447 return false; 4448 } 4449 } 4450 4451 4452 void 4453 ServerWindow::_ResizeToFullScreen() 4454 { 4455 BRect screenFrame; 4456 4457 { 4458 AutoReadLocker _(fDesktop->ScreenLocker()); 4459 const Screen* screen = fWindow->Screen(); 4460 if (screen == NULL) 4461 return; 4462 4463 screenFrame = fWindow->Screen()->Frame(); 4464 } 4465 4466 fDesktop->MoveWindowBy(fWindow.Get(), 4467 screenFrame.left - fWindow->Frame().left, 4468 screenFrame.top - fWindow->Frame().top); 4469 fDesktop->ResizeWindowBy(fWindow.Get(), 4470 screenFrame.Width() - fWindow->Frame().Width(), 4471 screenFrame.Height() - fWindow->Frame().Height()); 4472 } 4473 4474 4475 status_t 4476 ServerWindow::_EnableDirectWindowMode() 4477 { 4478 if (fDirectWindowInfo.IsSet()) { 4479 // already in direct window mode 4480 return B_ERROR; 4481 } 4482 4483 if (fDesktop->HWInterface()->FrontBuffer() == NULL) { 4484 // direct window mode not supported 4485 return B_UNSUPPORTED; 4486 } 4487 4488 fDirectWindowInfo.SetTo(new(std::nothrow) DirectWindowInfo); 4489 if (!fDirectWindowInfo.IsSet()) 4490 return B_NO_MEMORY; 4491 4492 status_t status = fDirectWindowInfo->InitCheck(); 4493 if (status != B_OK) { 4494 fDirectWindowInfo.Unset(); 4495 4496 return status; 4497 } 4498 4499 return B_OK; 4500 } 4501 4502 4503 void 4504 ServerWindow::_DirectWindowSetFullScreen(bool enable) 4505 { 4506 window_feel feel = kWindowScreenFeel; 4507 4508 if (enable) { 4509 fDesktop->HWInterface()->SetCursorVisible(false); 4510 4511 fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel()); 4512 _ResizeToFullScreen(); 4513 } else { 4514 const BRect& originalFrame = fDirectWindowInfo->OriginalFrame(); 4515 4516 fDirectWindowInfo->DisableFullScreen(); 4517 4518 // Resize window back to its original size 4519 fDesktop->MoveWindowBy(fWindow.Get(), 4520 originalFrame.left - fWindow->Frame().left, 4521 originalFrame.top - fWindow->Frame().top); 4522 fDesktop->ResizeWindowBy(fWindow.Get(), 4523 originalFrame.Width() - fWindow->Frame().Width(), 4524 originalFrame.Height() - fWindow->Frame().Height()); 4525 4526 fDesktop->HWInterface()->SetCursorVisible(true); 4527 } 4528 4529 fDesktop->SetWindowFeel(fWindow.Get(), feel); 4530 } 4531