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