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