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