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