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