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