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