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