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