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: %ld\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 if (fCurrentView == view) 1269 _SetCurrentView(parent); 1270 delete view; 1271 } // else we don't delete the root view 1272 } 1273 break; 1274 } 1275 case AS_VIEW_SET_STATE: 1276 { 1277 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: " 1278 "View name: %s\n", fTitle, fCurrentView->Name())); 1279 1280 fCurrentView->CurrentState()->ReadFromLink(link); 1281 // TODO: When is this used?!? 1282 fCurrentView->RebuildClipping(true); 1283 _UpdateDrawState(fCurrentView); 1284 1285 break; 1286 } 1287 case AS_VIEW_SET_FONT_STATE: 1288 { 1289 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: " 1290 "View name: %s\n", fTitle, fCurrentView->Name())); 1291 1292 fCurrentView->CurrentState()->ReadFontFromLink(link); 1293 fWindow->GetDrawingEngine()->SetFont( 1294 fCurrentView->CurrentState()); 1295 break; 1296 } 1297 case AS_VIEW_GET_STATE: 1298 { 1299 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: " 1300 "View name: %s\n", fTitle, fCurrentView->Name())); 1301 1302 fLink.StartMessage(B_OK); 1303 1304 // attach state data 1305 fCurrentView->CurrentState()->WriteToLink(fLink.Sender()); 1306 fLink.Flush(); 1307 break; 1308 } 1309 case AS_VIEW_SET_EVENT_MASK: 1310 { 1311 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: " 1312 "View name: %s\n", fTitle, fCurrentView->Name())); 1313 uint32 eventMask, options; 1314 1315 link.Read<uint32>(&eventMask); 1316 if (link.Read<uint32>(&options) == B_OK) { 1317 fCurrentView->SetEventMask(eventMask, options); 1318 1319 fDesktop->UnlockSingleWindow(); 1320 // TODO: possible deadlock! 1321 if (eventMask != 0 || options != 0) { 1322 fDesktop->EventDispatcher().AddListener(EventTarget(), 1323 fCurrentView->Token(), eventMask, options); 1324 } else { 1325 fDesktop->EventDispatcher().RemoveListener(EventTarget(), 1326 fCurrentView->Token()); 1327 } 1328 fDesktop->LockSingleWindow(); 1329 } 1330 break; 1331 } 1332 case AS_VIEW_SET_MOUSE_EVENT_MASK: 1333 { 1334 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: " 1335 "View name: %s\n", fTitle, fCurrentView->Name())); 1336 uint32 eventMask, options; 1337 1338 link.Read<uint32>(&eventMask); 1339 if (link.Read<uint32>(&options) == B_OK) { 1340 fDesktop->UnlockSingleWindow(); 1341 // TODO: possible deadlock 1342 if (eventMask != 0 || options != 0) { 1343 if (options & B_LOCK_WINDOW_FOCUS) 1344 fDesktop->SetFocusLocked(fWindow); 1345 fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(), 1346 fCurrentView->Token(), eventMask, options); 1347 } else { 1348 fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(), 1349 fCurrentView->Token()); 1350 } 1351 fDesktop->LockSingleWindow(); 1352 } 1353 1354 // TODO: support B_LOCK_WINDOW_FOCUS option in Desktop 1355 break; 1356 } 1357 case AS_VIEW_MOVE_TO: 1358 { 1359 float x, y; 1360 link.Read<float>(&x); 1361 if (link.Read<float>(&y) != B_OK) 1362 break; 1363 1364 DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: " 1365 "%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y)); 1366 1367 float offsetX = x - fCurrentView->Frame().left; 1368 float offsetY = y - fCurrentView->Frame().top; 1369 1370 BRegion dirty; 1371 fCurrentView->MoveBy(offsetX, offsetY, &dirty); 1372 1373 // TODO: think about how to avoid this hack: 1374 // the parent clipping needs to be updated, it is not 1375 // done in MoveBy() since it would cause 1376 // too much computations when children are resized because 1377 // follow modes 1378 if (View* parent = fCurrentView->Parent()) 1379 parent->RebuildClipping(false); 1380 1381 fWindow->MarkContentDirty(dirty); 1382 break; 1383 } 1384 case AS_VIEW_RESIZE_TO: 1385 { 1386 float newWidth, newHeight; 1387 link.Read<float>(&newWidth); 1388 if (link.Read<float>(&newHeight) != B_OK) 1389 break; 1390 1391 DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: " 1392 "%s, width: %.1f, height: %.1f\n", fTitle, 1393 fCurrentView->Name(), newWidth, newHeight)); 1394 1395 float deltaWidth = newWidth - fCurrentView->Frame().Width(); 1396 float deltaHeight = newHeight - fCurrentView->Frame().Height(); 1397 1398 BRegion dirty; 1399 fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty); 1400 1401 // TODO: see above 1402 if (View* parent = fCurrentView->Parent()) 1403 parent->RebuildClipping(false); 1404 1405 fWindow->MarkContentDirty(dirty); 1406 break; 1407 } 1408 case AS_VIEW_GET_COORD: 1409 { 1410 // our offset in the parent -> will be originX and originY 1411 // in BView 1412 BPoint parentOffset = fCurrentView->Frame().LeftTop(); 1413 1414 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: " 1415 "View: %s -> x: %.1f, y: %.1f\n", Title(), 1416 fCurrentView->Name(), parentOffset.x, parentOffset.y)); 1417 1418 fLink.StartMessage(B_OK); 1419 fLink.Attach<BPoint>(parentOffset); 1420 fLink.Attach<BRect>(fCurrentView->Bounds()); 1421 fLink.Flush(); 1422 break; 1423 } 1424 case AS_VIEW_SET_ORIGIN: 1425 { 1426 float x, y; 1427 link.Read<float>(&x); 1428 if (link.Read<float>(&y) != B_OK) 1429 break; 1430 1431 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: " 1432 "View: %s -> x: %.1f, y: %.1f\n", Title(), 1433 fCurrentView->Name(), x, y)); 1434 1435 fCurrentView->SetDrawingOrigin(BPoint(x, y)); 1436 _UpdateDrawState(fCurrentView); 1437 break; 1438 } 1439 case AS_VIEW_GET_ORIGIN: 1440 { 1441 BPoint drawingOrigin = fCurrentView->DrawingOrigin(); 1442 1443 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: " 1444 "View: %s -> x: %.1f, y: %.1f\n", Title(), 1445 fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y)); 1446 1447 fLink.StartMessage(B_OK); 1448 fLink.Attach<BPoint>(drawingOrigin); 1449 fLink.Flush(); 1450 break; 1451 } 1452 case AS_VIEW_RESIZE_MODE: 1453 { 1454 uint32 resizeMode; 1455 if (link.Read<uint32>(&resizeMode) != B_OK) 1456 break; 1457 1458 DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: " 1459 "View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(), 1460 resizeMode)); 1461 1462 fCurrentView->SetResizeMode(resizeMode); 1463 break; 1464 } 1465 case AS_VIEW_SET_FLAGS: 1466 { 1467 uint32 flags; 1468 link.Read<uint32>(&flags); 1469 1470 // The views clipping changes when the B_DRAW_ON_CHILDREN flag is 1471 // toggled. 1472 bool updateClipping = (flags & B_DRAW_ON_CHILDREN) 1473 ^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN); 1474 1475 fCurrentView->SetFlags(flags); 1476 _UpdateDrawState(fCurrentView); 1477 1478 if (updateClipping) { 1479 fCurrentView->RebuildClipping(false); 1480 fCurrentDrawingRegionValid = false; 1481 } 1482 1483 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: " 1484 "View: %s -> flags: %" B_PRIu32 "\n", Title(), 1485 fCurrentView->Name(), flags)); 1486 break; 1487 } 1488 case AS_VIEW_HIDE: 1489 DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n", 1490 Title(), fCurrentView->Name())); 1491 fCurrentView->SetHidden(true); 1492 break; 1493 1494 case AS_VIEW_SHOW: 1495 DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n", 1496 Title(), fCurrentView->Name())); 1497 fCurrentView->SetHidden(false); 1498 break; 1499 1500 case AS_VIEW_SET_LINE_MODE: 1501 { 1502 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: " 1503 "View: %s\n", Title(), fCurrentView->Name())); 1504 ViewSetLineModeInfo info; 1505 if (link.Read<ViewSetLineModeInfo>(&info) != B_OK) 1506 break; 1507 1508 fCurrentView->CurrentState()->SetLineCapMode(info.lineCap); 1509 fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin); 1510 fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit); 1511 1512 fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap, 1513 info.lineJoin, info.miterLimit); 1514 1515 break; 1516 } 1517 case AS_VIEW_GET_LINE_MODE: 1518 { 1519 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: " 1520 "View: %s\n", Title(), fCurrentView->Name())); 1521 ViewSetLineModeInfo info; 1522 info.lineJoin = fCurrentView->CurrentState()->LineJoinMode(); 1523 info.lineCap = fCurrentView->CurrentState()->LineCapMode(); 1524 info.miterLimit = fCurrentView->CurrentState()->MiterLimit(); 1525 1526 fLink.StartMessage(B_OK); 1527 fLink.Attach<ViewSetLineModeInfo>(info); 1528 fLink.Flush(); 1529 1530 break; 1531 } 1532 case AS_VIEW_SET_FILL_RULE: 1533 { 1534 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: " 1535 "View: %s\n", Title(), fCurrentView->Name())); 1536 int32 fillRule; 1537 if (link.Read<int32>(&fillRule) != B_OK) 1538 break; 1539 1540 fCurrentView->CurrentState()->SetFillRule(fillRule); 1541 fWindow->GetDrawingEngine()->SetFillRule(fillRule); 1542 1543 break; 1544 } 1545 case AS_VIEW_GET_FILL_RULE: 1546 { 1547 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: " 1548 "View: %s\n", Title(), fCurrentView->Name())); 1549 int32 fillRule = fCurrentView->CurrentState()->FillRule(); 1550 1551 fLink.StartMessage(B_OK); 1552 fLink.Attach<int32>(fillRule); 1553 fLink.Flush(); 1554 1555 break; 1556 } 1557 case AS_VIEW_PUSH_STATE: 1558 { 1559 DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: " 1560 "%s\n", Title(), fCurrentView->Name())); 1561 1562 fCurrentView->PushState(); 1563 // TODO: is this necessary? 1564 // _UpdateDrawState(fCurrentView); 1565 break; 1566 } 1567 case AS_VIEW_POP_STATE: 1568 { 1569 DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n", 1570 Title(), fCurrentView->Name())); 1571 1572 fCurrentView->PopState(); 1573 _UpdateDrawState(fCurrentView); 1574 break; 1575 } 1576 case AS_VIEW_SET_SCALE: 1577 { 1578 float scale; 1579 if (link.Read<float>(&scale) != B_OK) 1580 break; 1581 1582 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: " 1583 "View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(), 1584 scale)); 1585 1586 fCurrentView->SetScale(scale); 1587 _UpdateDrawState(fCurrentView); 1588 break; 1589 } 1590 case AS_VIEW_GET_SCALE: 1591 { 1592 float scale = fCurrentView->CurrentState()->Scale(); 1593 1594 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: " 1595 "View: %s -> scale: %.2f\n", 1596 Title(), fCurrentView->Name(), scale)); 1597 1598 fLink.StartMessage(B_OK); 1599 fLink.Attach<float>(scale); 1600 fLink.Flush(); 1601 break; 1602 } 1603 case AS_VIEW_SET_TRANSFORM: 1604 { 1605 BAffineTransform transform; 1606 if (link.Read<BAffineTransform>(&transform) != B_OK) 1607 break; 1608 1609 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: " 1610 "View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n", 1611 Title(), fCurrentView->Name(), transform.sx, transform.shy, 1612 transform.shx, transform.sy, transform.tx, transform.ty)); 1613 1614 fCurrentView->CurrentState()->SetTransform(transform); 1615 _UpdateDrawState(fCurrentView); 1616 break; 1617 } 1618 case AS_VIEW_GET_TRANSFORM: 1619 { 1620 BAffineTransform transform 1621 = fCurrentView->CurrentState()->Transform(); 1622 1623 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: " 1624 "View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n", 1625 Title(), fCurrentView->Name(), transform.sx, transform.shy, 1626 transform.shx, transform.sy, transform.tx, transform.ty)); 1627 1628 fLink.StartMessage(B_OK); 1629 fLink.Attach<BAffineTransform>(transform); 1630 fLink.Flush(); 1631 break; 1632 } 1633 case AS_VIEW_SET_PEN_LOC: 1634 { 1635 BPoint location; 1636 if (link.Read<BPoint>(&location) != B_OK) 1637 break; 1638 1639 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: " 1640 "View: %s -> BPoint(%.1f, %.1f)\n", Title(), 1641 fCurrentView->Name(), location.x, location.y)); 1642 1643 fCurrentView->CurrentState()->SetPenLocation(location); 1644 break; 1645 } 1646 case AS_VIEW_GET_PEN_LOC: 1647 { 1648 BPoint location = fCurrentView->CurrentState()->PenLocation(); 1649 1650 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: " 1651 "View: %s -> BPoint(%.1f, %.1f)\n", Title(), 1652 fCurrentView->Name(), location.x, location.y)); 1653 1654 fLink.StartMessage(B_OK); 1655 fLink.Attach<BPoint>(location); 1656 fLink.Flush(); 1657 1658 break; 1659 } 1660 case AS_VIEW_SET_PEN_SIZE: 1661 { 1662 float penSize; 1663 if (link.Read<float>(&penSize) != B_OK) 1664 break; 1665 1666 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: " 1667 "View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize)); 1668 1669 fCurrentView->CurrentState()->SetPenSize(penSize); 1670 fWindow->GetDrawingEngine()->SetPenSize( 1671 fCurrentView->CurrentState()->PenSize()); 1672 break; 1673 } 1674 case AS_VIEW_GET_PEN_SIZE: 1675 { 1676 float penSize = fCurrentView->CurrentState()->UnscaledPenSize(); 1677 1678 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: " 1679 "View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize)); 1680 1681 fLink.StartMessage(B_OK); 1682 fLink.Attach<float>(penSize); 1683 fLink.Flush(); 1684 1685 break; 1686 } 1687 case AS_VIEW_SET_VIEW_COLOR: 1688 { 1689 rgb_color color; 1690 if (link.Read(&color, sizeof(rgb_color)) != B_OK) 1691 break; 1692 1693 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: " 1694 "View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(), 1695 fCurrentView->Name(), color.red, color.green, color.blue, 1696 color.alpha)); 1697 1698 fCurrentView->SetViewColor(color); 1699 break; 1700 } 1701 case AS_VIEW_GET_VIEW_COLOR: 1702 { 1703 rgb_color color = fCurrentView->ViewColor(); 1704 1705 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: " 1706 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1707 Title(), fCurrentView->Name(), color.red, color.green, 1708 color.blue, color.alpha)); 1709 1710 fLink.StartMessage(B_OK); 1711 fLink.Attach<rgb_color>(color); 1712 fLink.Flush(); 1713 break; 1714 } 1715 case AS_VIEW_SET_HIGH_COLOR: 1716 { 1717 rgb_color color; 1718 if (link.Read(&color, sizeof(rgb_color)) != B_OK) 1719 break; 1720 1721 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: " 1722 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1723 Title(), fCurrentView->Name(), color.red, color.green, 1724 color.blue, color.alpha)); 1725 1726 fCurrentView->CurrentState()->SetHighColor(color); 1727 fWindow->GetDrawingEngine()->SetHighColor(color); 1728 break; 1729 } 1730 case AS_VIEW_GET_HIGH_COLOR: 1731 { 1732 rgb_color color = fCurrentView->CurrentState()->HighColor(); 1733 1734 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: " 1735 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1736 Title(), fCurrentView->Name(), color.red, color.green, 1737 color.blue, color.alpha)); 1738 1739 fLink.StartMessage(B_OK); 1740 fLink.Attach<rgb_color>(color); 1741 fLink.Flush(); 1742 break; 1743 } 1744 case AS_VIEW_SET_LOW_COLOR: 1745 { 1746 rgb_color color; 1747 if (link.Read(&color, sizeof(rgb_color)) != B_OK) 1748 break; 1749 1750 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: " 1751 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1752 Title(), fCurrentView->Name(), color.red, color.green, 1753 color.blue, color.alpha)); 1754 1755 fCurrentView->CurrentState()->SetLowColor(color); 1756 fWindow->GetDrawingEngine()->SetLowColor(color); 1757 break; 1758 } 1759 case AS_VIEW_GET_LOW_COLOR: 1760 { 1761 rgb_color color = fCurrentView->CurrentState()->LowColor(); 1762 1763 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: " 1764 "View: %s -> rgb_color(%d, %d, %d, %d)\n", 1765 Title(), fCurrentView->Name(), color.red, color.green, 1766 color.blue, color.alpha)); 1767 1768 fLink.StartMessage(B_OK); 1769 fLink.Attach<rgb_color>(color); 1770 fLink.Flush(); 1771 break; 1772 } 1773 case AS_VIEW_SET_PATTERN: 1774 { 1775 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: " 1776 "View: %s\n", fTitle, fCurrentView->Name())); 1777 1778 pattern pat; 1779 if (link.Read(&pat, sizeof(pattern)) != B_OK) 1780 break; 1781 1782 fCurrentView->CurrentState()->SetPattern(Pattern(pat)); 1783 fWindow->GetDrawingEngine()->SetPattern(pat); 1784 break; 1785 } 1786 1787 case AS_VIEW_SET_BLENDING_MODE: 1788 { 1789 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: " 1790 "View: %s\n", Title(), fCurrentView->Name())); 1791 1792 ViewBlendingModeInfo info; 1793 if (link.Read<ViewBlendingModeInfo>(&info) != B_OK) 1794 break; 1795 1796 fCurrentView->CurrentState()->SetBlendingMode( 1797 info.sourceAlpha, info.alphaFunction); 1798 fWindow->GetDrawingEngine()->SetBlendingMode( 1799 info.sourceAlpha, info.alphaFunction); 1800 break; 1801 } 1802 case AS_VIEW_GET_BLENDING_MODE: 1803 { 1804 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: " 1805 "View: %s\n", Title(), fCurrentView->Name())); 1806 1807 ViewBlendingModeInfo info; 1808 info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode(); 1809 info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode(); 1810 1811 fLink.StartMessage(B_OK); 1812 fLink.Attach<ViewBlendingModeInfo>(info); 1813 fLink.Flush(); 1814 1815 break; 1816 } 1817 case AS_VIEW_SET_DRAWING_MODE: 1818 { 1819 int8 drawingMode; 1820 if (link.Read<int8>(&drawingMode) != B_OK) 1821 break; 1822 1823 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: " 1824 "View: %s -> %s\n", Title(), fCurrentView->Name(), 1825 kDrawingModeMap[drawingMode])); 1826 1827 fCurrentView->CurrentState()->SetDrawingMode( 1828 (drawing_mode)drawingMode); 1829 fWindow->GetDrawingEngine()->SetDrawingMode( 1830 (drawing_mode)drawingMode); 1831 break; 1832 } 1833 case AS_VIEW_GET_DRAWING_MODE: 1834 { 1835 int8 drawingMode 1836 = (int8)(fCurrentView->CurrentState()->GetDrawingMode()); 1837 1838 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: " 1839 "View: %s -> %s\n", Title(), fCurrentView->Name(), 1840 kDrawingModeMap[drawingMode])); 1841 1842 fLink.StartMessage(B_OK); 1843 fLink.Attach<int8>(drawingMode); 1844 fLink.Flush(); 1845 1846 break; 1847 } 1848 case AS_VIEW_SET_VIEW_BITMAP: 1849 { 1850 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: " 1851 "View: %s\n", Title(), fCurrentView->Name())); 1852 1853 int32 bitmapToken, resizingMode, options; 1854 BRect srcRect, dstRect; 1855 1856 link.Read<int32>(&bitmapToken); 1857 link.Read<BRect>(&srcRect); 1858 link.Read<BRect>(&dstRect); 1859 link.Read<int32>(&resizingMode); 1860 status_t status = link.Read<int32>(&options); 1861 1862 rgb_color colorKey = {0}; 1863 1864 if (status == B_OK) { 1865 ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken); 1866 if (bitmapToken == -1 || bitmap != NULL) { 1867 bool wasOverlay = fCurrentView->ViewBitmap() != NULL 1868 && fCurrentView->ViewBitmap()->Overlay() != NULL; 1869 1870 fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect, 1871 resizingMode, options); 1872 1873 // TODO: if we revert the view color overlay handling 1874 // in View::Draw() to the BeOS version, we never 1875 // need to invalidate the view for overlays. 1876 1877 // Invalidate view - but only if this is a non-overlay 1878 // switch 1879 if (bitmap == NULL || bitmap->Overlay() == NULL 1880 || !wasOverlay) { 1881 BRegion dirty((BRect)fCurrentView->Bounds()); 1882 fWindow->InvalidateView(fCurrentView, dirty); 1883 } 1884 1885 if (bitmap != NULL && bitmap->Overlay() != NULL) { 1886 bitmap->Overlay()->SetFlags(options); 1887 colorKey = bitmap->Overlay()->Color(); 1888 } 1889 1890 if (bitmap != NULL) 1891 bitmap->ReleaseReference(); 1892 } else 1893 status = B_BAD_VALUE; 1894 } 1895 1896 fLink.StartMessage(status); 1897 if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) { 1898 // Attach color key for the overlay bitmap 1899 fLink.Attach<rgb_color>(colorKey); 1900 } 1901 1902 fLink.Flush(); 1903 break; 1904 } 1905 case AS_VIEW_PRINT_ALIASING: 1906 { 1907 DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: " 1908 "View: %s\n", Title(), fCurrentView->Name())); 1909 1910 bool fontAliasing; 1911 if (link.Read<bool>(&fontAliasing) == B_OK) { 1912 fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing); 1913 _UpdateDrawState(fCurrentView); 1914 } 1915 break; 1916 } 1917 case AS_VIEW_CLIP_TO_PICTURE: 1918 { 1919 DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: " 1920 "View: %s\n", Title(), fCurrentView->Name())); 1921 1922 int32 pictureToken; 1923 BPoint where; 1924 bool inverse = false; 1925 1926 link.Read<int32>(&pictureToken); 1927 if (pictureToken < 0) { 1928 fCurrentView->SetAlphaMask(NULL); 1929 _UpdateDrawState(fCurrentView); 1930 break; 1931 } 1932 1933 link.Read<BPoint>(&where); 1934 if (link.Read<bool>(&inverse) != B_OK) 1935 break; 1936 1937 ServerPicture* picture = fServerApp->GetPicture(pictureToken); 1938 if (picture == NULL) 1939 break; 1940 1941 AlphaMask* mask = new(std::nothrow) AlphaMask( 1942 picture, inverse, where, *fCurrentView->CurrentState()); 1943 fCurrentView->SetAlphaMask(mask); 1944 if (mask != NULL) 1945 mask->ReleaseReference(); 1946 _UpdateDrawState(fCurrentView); 1947 1948 picture->ReleaseReference(); 1949 break; 1950 } 1951 1952 case AS_VIEW_GET_CLIP_REGION: 1953 { 1954 DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: " 1955 "View: %s\n", Title(), fCurrentView->Name())); 1956 1957 // if this view is hidden, it has no visible region 1958 fLink.StartMessage(B_OK); 1959 if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) { 1960 BRegion empty; 1961 fLink.AttachRegion(empty); 1962 } else { 1963 _UpdateCurrentDrawingRegion(); 1964 BRegion region(fCurrentDrawingRegion); 1965 fCurrentView->ConvertFromScreen(®ion); 1966 fLink.AttachRegion(region); 1967 } 1968 fLink.Flush(); 1969 1970 break; 1971 } 1972 case AS_VIEW_SET_CLIP_REGION: 1973 { 1974 int32 rectCount; 1975 status_t status = link.Read<int32>(&rectCount); 1976 // a negative count means no 1977 // region for the current draw state, 1978 // but an *empty* region is actually valid! 1979 // even if it means no drawing is allowed 1980 1981 if (status < B_OK) 1982 break; 1983 1984 if (rectCount >= 0) { 1985 // we are supposed to set the clipping region 1986 BRegion region; 1987 if (rectCount > 0 && link.ReadRegion(®ion) < B_OK) 1988 break; 1989 1990 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: " 1991 "View: %s -> rect count: %" B_PRId32 ", frame = " 1992 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 1993 Title(), fCurrentView->Name(), rectCount, 1994 region.Frame().left, region.Frame().top, 1995 region.Frame().right, region.Frame().bottom)); 1996 1997 fCurrentView->SetUserClipping(®ion); 1998 } else { 1999 // we are supposed to unset the clipping region 2000 // passing NULL sets this states region to that 2001 // of the previous state 2002 2003 DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: " 2004 "View: %s -> unset\n", Title(), fCurrentView->Name())); 2005 2006 fCurrentView->SetUserClipping(NULL); 2007 } 2008 fCurrentDrawingRegionValid = false; 2009 2010 break; 2011 } 2012 2013 case AS_VIEW_INVALIDATE_RECT: 2014 { 2015 // NOTE: looks like this call is NOT affected by origin and scale 2016 // on R5 so this implementation is "correct" 2017 BRect invalidRect; 2018 if (link.Read<BRect>(&invalidRect) == B_OK) { 2019 DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: " 2020 "View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2021 fCurrentView->Name(), invalidRect.left, invalidRect.top, 2022 invalidRect.right, invalidRect.bottom)); 2023 2024 BRegion dirty(invalidRect); 2025 fWindow->InvalidateView(fCurrentView, dirty); 2026 } 2027 break; 2028 } 2029 case AS_VIEW_INVALIDATE_REGION: 2030 { 2031 // NOTE: looks like this call is NOT affected by origin and scale 2032 // on R5 so this implementation is "correct" 2033 BRegion region; 2034 if (link.ReadRegion(®ion) < B_OK) 2035 break; 2036 2037 DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: " 2038 "View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, " 2039 "%.1f, %.1f, %.1f)\n", Title(), 2040 fCurrentView->Name(), region.CountRects(), 2041 region.Frame().left, region.Frame().top, 2042 region.Frame().right, region.Frame().bottom)); 2043 2044 fWindow->InvalidateView(fCurrentView, region); 2045 break; 2046 } 2047 2048 case AS_VIEW_DRAG_IMAGE: 2049 { 2050 // TODO: flesh out AS_VIEW_DRAG_IMAGE 2051 DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title())); 2052 2053 int32 bitmapToken; 2054 drawing_mode dragMode; 2055 BPoint offset; 2056 int32 bufferSize; 2057 2058 link.Read<int32>(&bitmapToken); 2059 link.Read<int32>((int32*)&dragMode); 2060 link.Read<BPoint>(&offset); 2061 link.Read<int32>(&bufferSize); 2062 2063 if (bufferSize > 0) { 2064 char* buffer = new (nothrow) char[bufferSize]; 2065 BMessage dragMessage; 2066 if (link.Read(buffer, bufferSize) == B_OK 2067 && dragMessage.Unflatten(buffer) == B_OK) { 2068 ServerBitmap* bitmap 2069 = fServerApp->GetBitmap(bitmapToken); 2070 // TODO: possible deadlock 2071 fDesktop->UnlockSingleWindow(); 2072 fDesktop->EventDispatcher().SetDragMessage(dragMessage, 2073 bitmap, offset); 2074 fDesktop->LockSingleWindow(); 2075 bitmap->ReleaseReference(); 2076 } 2077 delete[] buffer; 2078 } 2079 // sync the client (it can now delete the bitmap) 2080 fLink.StartMessage(B_OK); 2081 fLink.Flush(); 2082 2083 break; 2084 } 2085 case AS_VIEW_DRAG_RECT: 2086 { 2087 // TODO: flesh out AS_VIEW_DRAG_RECT 2088 DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title())); 2089 2090 BRect dragRect; 2091 BPoint offset; 2092 int32 bufferSize; 2093 2094 link.Read<BRect>(&dragRect); 2095 link.Read<BPoint>(&offset); 2096 link.Read<int32>(&bufferSize); 2097 2098 if (bufferSize > 0) { 2099 char* buffer = new (nothrow) char[bufferSize]; 2100 BMessage dragMessage; 2101 if (link.Read(buffer, bufferSize) == B_OK 2102 && dragMessage.Unflatten(buffer) == B_OK) { 2103 // TODO: possible deadlock 2104 fDesktop->UnlockSingleWindow(); 2105 fDesktop->EventDispatcher().SetDragMessage(dragMessage, 2106 NULL /* should be dragRect */, offset); 2107 fDesktop->LockSingleWindow(); 2108 } 2109 delete[] buffer; 2110 } 2111 break; 2112 } 2113 2114 case AS_VIEW_BEGIN_RECT_TRACK: 2115 { 2116 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n", 2117 Title())); 2118 BRect dragRect; 2119 uint32 style; 2120 2121 link.Read<BRect>(&dragRect); 2122 link.Read<uint32>(&style); 2123 2124 // TODO: implement rect tracking (used sometimes for selecting 2125 // a group of things, also sometimes used to appear to drag 2126 // something, but without real drag message) 2127 break; 2128 } 2129 case AS_VIEW_END_RECT_TRACK: 2130 { 2131 DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n", 2132 Title())); 2133 // TODO: implement rect tracking 2134 break; 2135 } 2136 2137 case AS_VIEW_BEGIN_PICTURE: 2138 { 2139 DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n", 2140 Title())); 2141 ServerPicture* picture = App()->CreatePicture(); 2142 if (picture != NULL) { 2143 picture->SyncState(fCurrentView); 2144 fCurrentView->SetPicture(picture); 2145 } 2146 break; 2147 } 2148 2149 case AS_VIEW_APPEND_TO_PICTURE: 2150 { 2151 DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n", 2152 Title())); 2153 2154 int32 token; 2155 link.Read<int32>(&token); 2156 2157 ServerPicture* picture = App()->GetPicture(token); 2158 if (picture != NULL) 2159 picture->SyncState(fCurrentView); 2160 2161 fCurrentView->SetPicture(picture); 2162 2163 if (picture != NULL) 2164 picture->ReleaseReference(); 2165 break; 2166 } 2167 2168 case AS_VIEW_END_PICTURE: 2169 { 2170 DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n", 2171 Title())); 2172 2173 ServerPicture* picture = fCurrentView->Picture(); 2174 if (picture != NULL) { 2175 fCurrentView->SetPicture(NULL); 2176 fLink.StartMessage(B_OK); 2177 fLink.Attach<int32>(picture->Token()); 2178 } else 2179 fLink.StartMessage(B_ERROR); 2180 2181 fLink.Flush(); 2182 break; 2183 } 2184 2185 default: 2186 _DispatchViewDrawingMessage(code, link); 2187 break; 2188 } 2189 } 2190 2191 2192 /*! Dispatches all view drawing messages. 2193 The desktop clipping must be read locked when entering this method. 2194 Requires a valid fCurrentView. 2195 */ 2196 void 2197 ServerWindow::_DispatchViewDrawingMessage(int32 code, 2198 BPrivate::LinkReceiver &link) 2199 { 2200 if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) { 2201 if (link.NeedsReply()) { 2202 debug_printf("ServerWindow::DispatchViewDrawingMessage() got " 2203 "message %" B_PRId32 " that needs a reply!\n", code); 2204 // the client is now blocking and waiting for a reply! 2205 fLink.StartMessage(B_ERROR); 2206 fLink.Flush(); 2207 } 2208 return; 2209 } 2210 2211 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 2212 if (!drawingEngine) { 2213 // ?!? 2214 debug_printf("ServerWindow %s: no drawing engine!!\n", Title()); 2215 if (link.NeedsReply()) { 2216 // the client is now blocking and waiting for a reply! 2217 fLink.StartMessage(B_ERROR); 2218 fLink.Flush(); 2219 } 2220 return; 2221 } 2222 2223 _UpdateCurrentDrawingRegion(); 2224 if (fCurrentDrawingRegion.CountRects() <= 0) { 2225 DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, " 2226 "INVALID CLIPPING!\n", Title(), fCurrentView->Name())); 2227 if (link.NeedsReply()) { 2228 // the client is now blocking and waiting for a reply! 2229 fLink.StartMessage(B_ERROR); 2230 fLink.Flush(); 2231 } 2232 return; 2233 } 2234 2235 drawingEngine->LockParallelAccess(); 2236 // NOTE: the region is not copied, Painter keeps a pointer, 2237 // that's why you need to use the clipping only for as long 2238 // as you have it locked 2239 drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion); 2240 2241 switch (code) { 2242 case AS_STROKE_LINE: 2243 { 2244 ViewStrokeLineInfo info; 2245 if (link.Read<ViewStrokeLineInfo>(&info) != B_OK) 2246 break; 2247 2248 DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> " 2249 "BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(), 2250 fCurrentView->Name(), 2251 info.startPoint.x, info.startPoint.y, 2252 info.endPoint.x, info.endPoint.y)); 2253 2254 BPoint penPos = info.endPoint; 2255 fCurrentView->ConvertToScreenForDrawing(&info.startPoint); 2256 fCurrentView->ConvertToScreenForDrawing(&info.endPoint); 2257 drawingEngine->StrokeLine(info.startPoint, info.endPoint); 2258 2259 // We update the pen here because many DrawingEngine calls which 2260 // do not update the pen position actually call StrokeLine 2261 2262 // TODO: Decide where to put this, for example, it cannot be done 2263 // for DrawString(), also there needs to be a decision, if the pen 2264 // location is in View coordinates (I think it should be) or in 2265 // screen coordinates. 2266 fCurrentView->CurrentState()->SetPenLocation(penPos); 2267 break; 2268 } 2269 case AS_VIEW_INVERT_RECT: 2270 { 2271 BRect rect; 2272 if (link.Read<BRect>(&rect) != B_OK) 2273 break; 2274 2275 DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> " 2276 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2277 fCurrentView->Name(), rect.left, rect.top, rect.right, 2278 rect.bottom)); 2279 2280 fCurrentView->ConvertToScreenForDrawing(&rect); 2281 drawingEngine->InvertRect(rect); 2282 break; 2283 } 2284 case AS_STROKE_RECT: 2285 { 2286 BRect rect; 2287 if (link.Read<BRect>(&rect) != B_OK) 2288 break; 2289 2290 DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> " 2291 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2292 fCurrentView->Name(), rect.left, rect.top, rect.right, 2293 rect.bottom)); 2294 2295 fCurrentView->ConvertToScreenForDrawing(&rect); 2296 drawingEngine->StrokeRect(rect); 2297 break; 2298 } 2299 case AS_FILL_RECT: 2300 { 2301 BRect rect; 2302 if (link.Read<BRect>(&rect) != B_OK) 2303 break; 2304 2305 DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> " 2306 "BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2307 fCurrentView->Name(), rect.left, rect.top, rect.right, 2308 rect.bottom)); 2309 2310 fCurrentView->ConvertToScreenForDrawing(&rect); 2311 drawingEngine->FillRect(rect); 2312 break; 2313 } 2314 case AS_FILL_RECT_GRADIENT: 2315 { 2316 BRect rect; 2317 link.Read<BRect>(&rect); 2318 BGradient* gradient; 2319 if (link.ReadGradient(&gradient) != B_OK) 2320 break; 2321 2322 GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s " 2323 "-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(), 2324 fCurrentView->Name(), rect.left, rect.top, rect.right, 2325 rect.bottom)); 2326 2327 fCurrentView->ConvertToScreenForDrawing(&rect); 2328 fCurrentView->ConvertToScreenForDrawing(gradient); 2329 drawingEngine->FillRect(rect, *gradient); 2330 delete gradient; 2331 break; 2332 } 2333 case AS_VIEW_DRAW_BITMAP: 2334 { 2335 ViewDrawBitmapInfo info; 2336 if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK) 2337 break; 2338 2339 #if 0 2340 if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0) 2341 info.options |= B_FILTER_BITMAP_BILINEAR; 2342 #endif 2343 2344 ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken); 2345 if (bitmap != NULL) { 2346 DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: " 2347 "View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x " 2348 "%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> " 2349 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 2350 fTitle, fCurrentView->Name(), info.bitmapToken, 2351 bitmap->Width(), bitmap->Height(), 2352 info.bitmapRect.left, info.bitmapRect.top, 2353 info.bitmapRect.right, info.bitmapRect.bottom, 2354 info.viewRect.left, info.viewRect.top, 2355 info.viewRect.right, info.viewRect.bottom)); 2356 2357 fCurrentView->ConvertToScreenForDrawing(&info.viewRect); 2358 2359 // TODO: Unbreak... 2360 // if ((info.options & B_WAIT_FOR_RETRACE) != 0) 2361 // fDesktop->HWInterface()->WaitForRetrace(20000); 2362 2363 drawingEngine->DrawBitmap(bitmap, info.bitmapRect, 2364 info.viewRect, info.options); 2365 2366 bitmap->ReleaseReference(); 2367 } 2368 break; 2369 } 2370 case AS_STROKE_ARC: 2371 case AS_FILL_ARC: 2372 { 2373 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title())); 2374 2375 float angle, span; 2376 BRect r; 2377 2378 link.Read<BRect>(&r); 2379 link.Read<float>(&angle); 2380 if (link.Read<float>(&span) != B_OK) 2381 break; 2382 2383 fCurrentView->ConvertToScreenForDrawing(&r); 2384 drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC); 2385 break; 2386 } 2387 case AS_FILL_ARC_GRADIENT: 2388 { 2389 GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n", 2390 Title())); 2391 2392 float angle, span; 2393 BRect r; 2394 link.Read<BRect>(&r); 2395 link.Read<float>(&angle); 2396 link.Read<float>(&span); 2397 BGradient* gradient; 2398 if (link.ReadGradient(&gradient) != B_OK) 2399 break; 2400 fCurrentView->ConvertToScreenForDrawing(&r); 2401 fCurrentView->ConvertToScreenForDrawing(gradient); 2402 drawingEngine->FillArc(r, angle, span, *gradient); 2403 delete gradient; 2404 break; 2405 } 2406 case AS_STROKE_BEZIER: 2407 case AS_FILL_BEZIER: 2408 { 2409 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", 2410 Title())); 2411 2412 BPoint pts[4]; 2413 status_t status; 2414 for (int32 i = 0; i < 4; i++) { 2415 status = link.Read<BPoint>(&(pts[i])); 2416 fCurrentView->ConvertToScreenForDrawing(&pts[i]); 2417 } 2418 if (status != B_OK) 2419 break; 2420 2421 drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER); 2422 break; 2423 } 2424 case AS_FILL_BEZIER_GRADIENT: 2425 { 2426 GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n", 2427 Title())); 2428 2429 BPoint pts[4]; 2430 for (int32 i = 0; i < 4; i++) { 2431 link.Read<BPoint>(&(pts[i])); 2432 fCurrentView->ConvertToScreenForDrawing(&pts[i]); 2433 } 2434 BGradient* gradient; 2435 if (link.ReadGradient(&gradient) != B_OK) 2436 break; 2437 fCurrentView->ConvertToScreenForDrawing(gradient); 2438 drawingEngine->FillBezier(pts, *gradient); 2439 delete gradient; 2440 break; 2441 } 2442 case AS_STROKE_ELLIPSE: 2443 case AS_FILL_ELLIPSE: 2444 { 2445 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", 2446 Title())); 2447 2448 BRect rect; 2449 if (link.Read<BRect>(&rect) != B_OK) 2450 break; 2451 2452 fCurrentView->ConvertToScreenForDrawing(&rect); 2453 drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE); 2454 break; 2455 } 2456 case AS_FILL_ELLIPSE_GRADIENT: 2457 { 2458 GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n", 2459 Title())); 2460 2461 BRect rect; 2462 link.Read<BRect>(&rect); 2463 BGradient* gradient; 2464 if (link.ReadGradient(&gradient) != B_OK) 2465 break; 2466 fCurrentView->ConvertToScreenForDrawing(&rect); 2467 fCurrentView->ConvertToScreenForDrawing(gradient); 2468 drawingEngine->FillEllipse(rect, *gradient); 2469 delete gradient; 2470 break; 2471 } 2472 case AS_STROKE_ROUNDRECT: 2473 case AS_FILL_ROUNDRECT: 2474 { 2475 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", 2476 Title())); 2477 2478 BRect rect; 2479 float xRadius; 2480 float yRadius; 2481 link.Read<BRect>(&rect); 2482 link.Read<float>(&xRadius); 2483 if (link.Read<float>(&yRadius) != B_OK) 2484 break; 2485 2486 fCurrentView->ConvertToScreenForDrawing(&rect); 2487 float scale = fCurrentView->CurrentState()->CombinedScale(); 2488 drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale, 2489 code == AS_FILL_ROUNDRECT); 2490 break; 2491 } 2492 case AS_FILL_ROUNDRECT_GRADIENT: 2493 { 2494 GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n", 2495 Title())); 2496 2497 BRect rect; 2498 float xrad,yrad; 2499 link.Read<BRect>(&rect); 2500 link.Read<float>(&xrad); 2501 link.Read<float>(&yrad); 2502 BGradient* gradient; 2503 if (link.ReadGradient(&gradient) != B_OK) 2504 break; 2505 fCurrentView->ConvertToScreenForDrawing(&rect); 2506 fCurrentView->ConvertToScreenForDrawing(gradient); 2507 drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient); 2508 delete gradient; 2509 break; 2510 } 2511 case AS_STROKE_TRIANGLE: 2512 case AS_FILL_TRIANGLE: 2513 { 2514 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", 2515 Title())); 2516 2517 BPoint pts[3]; 2518 BRect rect; 2519 2520 for (int32 i = 0; i < 3; i++) { 2521 link.Read<BPoint>(&(pts[i])); 2522 fCurrentView->ConvertToScreenForDrawing(&pts[i]); 2523 } 2524 2525 if (link.Read<BRect>(&rect) != B_OK) 2526 break; 2527 2528 fCurrentView->ConvertToScreenForDrawing(&rect); 2529 drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE); 2530 break; 2531 } 2532 case AS_FILL_TRIANGLE_GRADIENT: 2533 { 2534 DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n", 2535 Title())); 2536 2537 BPoint pts[3]; 2538 BRect rect; 2539 for (int32 i = 0; i < 3; i++) { 2540 link.Read<BPoint>(&(pts[i])); 2541 fCurrentView->ConvertToScreenForDrawing(&pts[i]); 2542 } 2543 link.Read<BRect>(&rect); 2544 BGradient* gradient; 2545 if (link.ReadGradient(&gradient) != B_OK) 2546 break; 2547 fCurrentView->ConvertToScreenForDrawing(&rect); 2548 fCurrentView->ConvertToScreenForDrawing(gradient); 2549 drawingEngine->FillTriangle(pts, rect, *gradient); 2550 delete gradient; 2551 break; 2552 } 2553 case AS_STROKE_POLYGON: 2554 case AS_FILL_POLYGON: 2555 { 2556 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", 2557 Title())); 2558 2559 BRect polyFrame; 2560 bool isClosed = true; 2561 int32 pointCount; 2562 2563 link.Read<BRect>(&polyFrame); 2564 if (code == AS_STROKE_POLYGON) 2565 link.Read<bool>(&isClosed); 2566 link.Read<int32>(&pointCount); 2567 2568 BPoint* pointList = new(nothrow) BPoint[pointCount]; 2569 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { 2570 for (int32 i = 0; i < pointCount; i++) 2571 fCurrentView->ConvertToScreenForDrawing(&pointList[i]); 2572 fCurrentView->ConvertToScreenForDrawing(&polyFrame); 2573 2574 drawingEngine->DrawPolygon(pointList, pointCount, polyFrame, 2575 code == AS_FILL_POLYGON, isClosed && pointCount > 2); 2576 } 2577 delete[] pointList; 2578 break; 2579 } 2580 case AS_FILL_POLYGON_GRADIENT: 2581 { 2582 DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n", 2583 Title())); 2584 2585 BRect polyFrame; 2586 bool isClosed = true; 2587 int32 pointCount; 2588 link.Read<BRect>(&polyFrame); 2589 link.Read<int32>(&pointCount); 2590 2591 BPoint* pointList = new(nothrow) BPoint[pointCount]; 2592 BGradient* gradient; 2593 if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK 2594 && link.ReadGradient(&gradient) == B_OK) { 2595 for (int32 i = 0; i < pointCount; i++) 2596 fCurrentView->ConvertToScreenForDrawing(&pointList[i]); 2597 fCurrentView->ConvertToScreenForDrawing(&polyFrame); 2598 fCurrentView->ConvertToScreenForDrawing(gradient); 2599 2600 drawingEngine->FillPolygon(pointList, pointCount, 2601 polyFrame, *gradient, isClosed && pointCount > 2); 2602 delete gradient; 2603 } 2604 delete[] pointList; 2605 break; 2606 } 2607 case AS_STROKE_SHAPE: 2608 case AS_FILL_SHAPE: 2609 { 2610 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", 2611 Title())); 2612 2613 BRect shapeFrame; 2614 int32 opCount; 2615 int32 ptCount; 2616 2617 link.Read<BRect>(&shapeFrame); 2618 link.Read<int32>(&opCount); 2619 link.Read<int32>(&ptCount); 2620 2621 uint32* opList = new(nothrow) uint32[opCount]; 2622 BPoint* ptList = new(nothrow) BPoint[ptCount]; 2623 if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK && 2624 link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) { 2625 2626 // this might seem a bit weird, but under R5, the shapes 2627 // are always offset by the current pen location 2628 BPoint screenOffset 2629 = fCurrentView->CurrentState()->PenLocation(); 2630 shapeFrame.OffsetBy(screenOffset); 2631 2632 fCurrentView->ConvertToScreenForDrawing(&screenOffset); 2633 fCurrentView->ConvertToScreenForDrawing(&shapeFrame); 2634 2635 drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, 2636 ptList, code == AS_FILL_SHAPE, screenOffset, 2637 fCurrentView->Scale()); 2638 } 2639 2640 delete[] opList; 2641 delete[] ptList; 2642 break; 2643 } 2644 case AS_FILL_SHAPE_GRADIENT: 2645 { 2646 DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n", 2647 Title())); 2648 2649 BRect shapeFrame; 2650 int32 opCount; 2651 int32 ptCount; 2652 2653 link.Read<BRect>(&shapeFrame); 2654 link.Read<int32>(&opCount); 2655 link.Read<int32>(&ptCount); 2656 2657 uint32* opList = new(nothrow) uint32[opCount]; 2658 BPoint* ptList = new(nothrow) BPoint[ptCount]; 2659 BGradient* gradient; 2660 if (link.Read(opList, opCount * sizeof(uint32)) == B_OK 2661 && link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK 2662 && link.ReadGradient(&gradient) == B_OK) { 2663 2664 // this might seem a bit weird, but under R5, the shapes 2665 // are always offset by the current pen location 2666 BPoint screenOffset 2667 = fCurrentView->CurrentState()->PenLocation(); 2668 shapeFrame.OffsetBy(screenOffset); 2669 2670 fCurrentView->ConvertToScreenForDrawing(&screenOffset); 2671 fCurrentView->ConvertToScreenForDrawing(&shapeFrame); 2672 fCurrentView->ConvertToScreenForDrawing(gradient); 2673 drawingEngine->FillShape(shapeFrame, opCount, opList, 2674 ptCount, ptList, *gradient, screenOffset, 2675 fCurrentView->Scale()); 2676 delete gradient; 2677 } 2678 2679 delete[] opList; 2680 delete[] ptList; 2681 break; 2682 } 2683 case AS_FILL_REGION: 2684 { 2685 DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title())); 2686 2687 BRegion region; 2688 if (link.ReadRegion(®ion) < B_OK) 2689 break; 2690 2691 fCurrentView->ConvertToScreenForDrawing(®ion); 2692 drawingEngine->FillRegion(region); 2693 2694 break; 2695 } 2696 case AS_FILL_REGION_GRADIENT: 2697 { 2698 DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n", 2699 Title())); 2700 2701 BRegion region; 2702 link.ReadRegion(®ion); 2703 2704 BGradient* gradient; 2705 if (link.ReadGradient(&gradient) != B_OK) 2706 break; 2707 2708 fCurrentView->ConvertToScreenForDrawing(®ion); 2709 fCurrentView->ConvertToScreenForDrawing(gradient); 2710 drawingEngine->FillRegion(region, *gradient); 2711 delete gradient; 2712 break; 2713 } 2714 case AS_STROKE_LINEARRAY: 2715 { 2716 DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", 2717 Title())); 2718 2719 // Attached Data: 2720 // 1) int32 Number of lines in the array 2721 // 2) LineArrayData 2722 2723 int32 lineCount; 2724 if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0) 2725 break; 2726 2727 // To speed things up, try to use a stack allocation and only 2728 // fall back to the heap if there are enough lines... 2729 ViewLineArrayInfo* lineData; 2730 const int32 kStackBufferLineDataCount = 64; 2731 ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount]; 2732 if (lineCount > kStackBufferLineDataCount) { 2733 lineData = new(std::nothrow) ViewLineArrayInfo[lineCount]; 2734 if (lineData == NULL) 2735 break; 2736 } else 2737 lineData = lineDataStackBuffer; 2738 2739 // Read them all in one go 2740 size_t dataSize = lineCount * sizeof(ViewLineArrayInfo); 2741 if (link.Read(lineData, dataSize) != B_OK) { 2742 if (lineData != lineDataStackBuffer) 2743 delete[] lineData; 2744 break; 2745 } 2746 2747 // Convert to screen coords and draw 2748 for (int32 i = 0; i < lineCount; i++) { 2749 fCurrentView->ConvertToScreenForDrawing( 2750 &lineData[i].startPoint); 2751 fCurrentView->ConvertToScreenForDrawing( 2752 &lineData[i].endPoint); 2753 } 2754 drawingEngine->StrokeLineArray(lineCount, lineData); 2755 2756 if (lineData != lineDataStackBuffer) 2757 delete[] lineData; 2758 break; 2759 } 2760 case AS_DRAW_STRING: 2761 case AS_DRAW_STRING_WITH_DELTA: 2762 { 2763 ViewDrawStringInfo info; 2764 if (link.Read<ViewDrawStringInfo>(&info) != B_OK 2765 || info.stringLength <= 0) { 2766 break; 2767 } 2768 2769 const ssize_t kMaxStackStringSize = 4096; 2770 char stackString[kMaxStackStringSize]; 2771 char* string = stackString; 2772 if (info.stringLength >= kMaxStackStringSize) { 2773 // NOTE: Careful, the + 1 is for termination! 2774 string = (char*)malloc((info.stringLength + 1 + 63) / 64 * 64); 2775 if (string == NULL) 2776 break; 2777 } 2778 2779 escapement_delta* delta = NULL; 2780 if (code == AS_DRAW_STRING_WITH_DELTA) { 2781 // In this case, info.delta will contain valid values. 2782 delta = &info.delta; 2783 } 2784 2785 if (link.Read(string, info.stringLength) != B_OK) { 2786 if (string != stackString) 2787 free(string); 2788 break; 2789 } 2790 // Terminate the string, if nothing else, it's important 2791 // for the DTRACE call below... 2792 string[info.stringLength] = '\0'; 2793 2794 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s " 2795 "-> %s\n", Title(), fCurrentView->Name(), string)); 2796 2797 fCurrentView->ConvertToScreenForDrawing(&info.location); 2798 BPoint penLocation = drawingEngine->DrawString(string, 2799 info.stringLength, info.location, delta); 2800 2801 fCurrentView->ConvertFromScreenForDrawing(&penLocation); 2802 fCurrentView->CurrentState()->SetPenLocation(penLocation); 2803 2804 if (string != stackString) 2805 free(string); 2806 break; 2807 } 2808 case AS_DRAW_STRING_WITH_OFFSETS: 2809 { 2810 int32 stringLength; 2811 if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0) 2812 break; 2813 2814 int32 glyphCount; 2815 if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0) 2816 break; 2817 2818 const ssize_t kMaxStackStringSize = 512; 2819 char stackString[kMaxStackStringSize]; 2820 char* string = stackString; 2821 BPoint stackLocations[kMaxStackStringSize]; 2822 BPoint* locations = stackLocations; 2823 MemoryDeleter stringDeleter; 2824 MemoryDeleter locationsDeleter; 2825 if (stringLength >= kMaxStackStringSize) { 2826 // NOTE: Careful, the + 1 is for termination! 2827 string = (char*)malloc((stringLength + 1 + 63) / 64 * 64); 2828 if (string == NULL) 2829 break; 2830 stringDeleter.SetTo(string); 2831 } 2832 if (glyphCount > kMaxStackStringSize) { 2833 locations = (BPoint*)malloc( 2834 ((glyphCount * sizeof(BPoint)) + 63) / 64 * 64); 2835 if (locations == NULL) 2836 break; 2837 locationsDeleter.SetTo(locations); 2838 } 2839 2840 if (link.Read(string, stringLength) != B_OK) 2841 break; 2842 // Count UTF8 glyphs and make sure we have enough locations 2843 if ((int32)UTF8CountChars(string, stringLength) > glyphCount) 2844 break; 2845 if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK) 2846 break; 2847 // Terminate the string, if nothing else, it's important 2848 // for the DTRACE call below... 2849 string[stringLength] = '\0'; 2850 2851 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s " 2852 "-> %s\n", Title(), fCurrentView->Name(), string)); 2853 2854 for (int32 i = 0; i < glyphCount; i++) 2855 fCurrentView->ConvertToScreenForDrawing(&locations[i]); 2856 2857 BPoint penLocation = drawingEngine->DrawString(string, 2858 stringLength, locations); 2859 2860 fCurrentView->ConvertFromScreenForDrawing(&penLocation); 2861 fCurrentView->CurrentState()->SetPenLocation(penLocation); 2862 2863 break; 2864 } 2865 2866 case AS_VIEW_DRAW_PICTURE: 2867 { 2868 int32 token; 2869 link.Read<int32>(&token); 2870 2871 BPoint where; 2872 if (link.Read<BPoint>(&where) == B_OK) { 2873 ServerPicture* picture = App()->GetPicture(token); 2874 if (picture != NULL) { 2875 // Setting the drawing origin outside of the 2876 // state makes sure that everything the picture 2877 // does is relative to the global picture offset. 2878 fCurrentView->PushState(); 2879 fCurrentView->SetDrawingOrigin(where); 2880 2881 fCurrentView->PushState(); 2882 picture->Play(fCurrentView); 2883 fCurrentView->PopState(); 2884 2885 fCurrentView->PopState(); 2886 2887 picture->ReleaseReference(); 2888 } 2889 } 2890 break; 2891 } 2892 2893 default: 2894 BString codeString; 2895 string_for_message_code(code, codeString); 2896 debug_printf("ServerWindow %s received unexpected code: %s\n", 2897 Title(), codeString.String()); 2898 2899 if (link.NeedsReply()) { 2900 // the client is now blocking and waiting for a reply! 2901 fLink.StartMessage(B_ERROR); 2902 fLink.Flush(); 2903 } 2904 break; 2905 } 2906 2907 drawingEngine->UnlockParallelAccess(); 2908 } 2909 2910 2911 bool 2912 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) 2913 { 2914 ServerPicture* picture = fCurrentView->Picture(); 2915 if (picture == NULL) 2916 return false; 2917 2918 switch (code) { 2919 case AS_VIEW_SET_ORIGIN: 2920 { 2921 float x, y; 2922 link.Read<float>(&x); 2923 link.Read<float>(&y); 2924 2925 picture->WriteSetOrigin(BPoint(x, y)); 2926 break; 2927 } 2928 2929 case AS_VIEW_INVERT_RECT: 2930 { 2931 BRect rect; 2932 link.Read<BRect>(&rect); 2933 picture->WriteInvertRect(rect); 2934 break; 2935 } 2936 2937 case AS_VIEW_PUSH_STATE: 2938 { 2939 picture->WritePushState(); 2940 break; 2941 } 2942 2943 case AS_VIEW_POP_STATE: 2944 { 2945 picture->WritePopState(); 2946 break; 2947 } 2948 2949 case AS_VIEW_SET_DRAWING_MODE: 2950 { 2951 int8 drawingMode; 2952 link.Read<int8>(&drawingMode); 2953 2954 picture->WriteSetDrawingMode((drawing_mode)drawingMode); 2955 2956 fCurrentView->CurrentState()->SetDrawingMode( 2957 (drawing_mode)drawingMode); 2958 fWindow->GetDrawingEngine()->SetDrawingMode( 2959 (drawing_mode)drawingMode); 2960 break; 2961 } 2962 2963 case AS_VIEW_SET_PEN_LOC: 2964 { 2965 BPoint location; 2966 link.Read<BPoint>(&location); 2967 picture->WriteSetPenLocation(location); 2968 2969 fCurrentView->CurrentState()->SetPenLocation(location); 2970 break; 2971 } 2972 case AS_VIEW_SET_PEN_SIZE: 2973 { 2974 float penSize; 2975 link.Read<float>(&penSize); 2976 picture->WriteSetPenSize(penSize); 2977 2978 fCurrentView->CurrentState()->SetPenSize(penSize); 2979 fWindow->GetDrawingEngine()->SetPenSize( 2980 fCurrentView->CurrentState()->PenSize()); 2981 break; 2982 } 2983 2984 case AS_VIEW_SET_LINE_MODE: 2985 { 2986 2987 ViewSetLineModeInfo info; 2988 link.Read<ViewSetLineModeInfo>(&info); 2989 2990 picture->WriteSetLineMode(info.lineCap, info.lineJoin, 2991 info.miterLimit); 2992 2993 fCurrentView->CurrentState()->SetLineCapMode(info.lineCap); 2994 fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin); 2995 fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit); 2996 2997 fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap, 2998 info.lineJoin, info.miterLimit); 2999 break; 3000 } 3001 case AS_VIEW_SET_SCALE: 3002 { 3003 float scale; 3004 if (link.Read<float>(&scale) != B_OK) 3005 break; 3006 3007 picture->WriteSetScale(scale); 3008 3009 fCurrentView->SetScale(scale); 3010 _UpdateDrawState(fCurrentView); 3011 break; 3012 } 3013 case AS_VIEW_SET_TRANSFORM: 3014 { 3015 BAffineTransform transform; 3016 if (link.Read<BAffineTransform>(&transform) != B_OK) 3017 break; 3018 3019 picture->WriteSetTransform(transform); 3020 3021 fCurrentView->CurrentState()->SetTransform(transform); 3022 _UpdateDrawState(fCurrentView); 3023 break; 3024 } 3025 3026 case AS_VIEW_SET_PATTERN: 3027 { 3028 pattern pat; 3029 link.Read(&pat, sizeof(pattern)); 3030 picture->WriteSetPattern(pat); 3031 break; 3032 } 3033 3034 case AS_VIEW_SET_FONT_STATE: 3035 { 3036 picture->SetFontFromLink(link); 3037 break; 3038 } 3039 3040 case AS_FILL_RECT: 3041 case AS_STROKE_RECT: 3042 { 3043 BRect rect; 3044 link.Read<BRect>(&rect); 3045 3046 picture->WriteDrawRect(rect, code == AS_FILL_RECT); 3047 break; 3048 } 3049 3050 case AS_FILL_REGION: 3051 { 3052 // There is no B_PIC_FILL_REGION op, we have to 3053 // implement it using B_PIC_FILL_RECT 3054 BRegion region; 3055 if (link.ReadRegion(®ion) < B_OK) 3056 break; 3057 for (int32 i = 0; i < region.CountRects(); i++) 3058 picture->WriteDrawRect(region.RectAt(i), true); 3059 break; 3060 } 3061 3062 case AS_STROKE_ROUNDRECT: 3063 case AS_FILL_ROUNDRECT: 3064 { 3065 BRect rect; 3066 link.Read<BRect>(&rect); 3067 3068 BPoint radii; 3069 link.Read<float>(&radii.x); 3070 link.Read<float>(&radii.y); 3071 3072 picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT); 3073 break; 3074 } 3075 3076 case AS_STROKE_ELLIPSE: 3077 case AS_FILL_ELLIPSE: 3078 { 3079 BRect rect; 3080 link.Read<BRect>(&rect); 3081 picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE); 3082 break; 3083 } 3084 3085 case AS_STROKE_ARC: 3086 case AS_FILL_ARC: 3087 { 3088 BRect rect; 3089 link.Read<BRect>(&rect); 3090 float startTheta, arcTheta; 3091 link.Read<float>(&startTheta); 3092 link.Read<float>(&arcTheta); 3093 3094 BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2); 3095 BPoint center = rect.LeftTop() + radii; 3096 3097 picture->WriteDrawArc(center, radii, startTheta, arcTheta, 3098 code == AS_FILL_ARC); 3099 break; 3100 } 3101 3102 case AS_STROKE_TRIANGLE: 3103 case AS_FILL_TRIANGLE: 3104 { 3105 // There is no B_PIC_FILL/STROKE_TRIANGLE op, 3106 // we implement it using B_PIC_FILL/STROKE_POLYGON 3107 BPoint points[3]; 3108 3109 for (int32 i = 0; i < 3; i++) { 3110 link.Read<BPoint>(&(points[i])); 3111 } 3112 3113 BRect rect; 3114 link.Read<BRect>(&rect); 3115 3116 picture->WriteDrawPolygon(3, points, 3117 true, code == AS_FILL_TRIANGLE); 3118 break; 3119 } 3120 case AS_STROKE_POLYGON: 3121 case AS_FILL_POLYGON: 3122 { 3123 BRect polyFrame; 3124 bool isClosed = true; 3125 int32 pointCount; 3126 const bool fill = (code == AS_FILL_POLYGON); 3127 3128 link.Read<BRect>(&polyFrame); 3129 if (code == AS_STROKE_POLYGON) 3130 link.Read<bool>(&isClosed); 3131 link.Read<int32>(&pointCount); 3132 3133 BPoint* pointList = new(nothrow) BPoint[pointCount]; 3134 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { 3135 picture->WriteDrawPolygon(pointCount, pointList, 3136 isClosed && pointCount > 2, fill); 3137 } 3138 delete[] pointList; 3139 break; 3140 } 3141 3142 case AS_STROKE_BEZIER: 3143 case AS_FILL_BEZIER: 3144 { 3145 BPoint points[4]; 3146 for (int32 i = 0; i < 4; i++) { 3147 link.Read<BPoint>(&(points[i])); 3148 } 3149 picture->WriteDrawBezier(points, code == AS_FILL_BEZIER); 3150 break; 3151 } 3152 3153 case AS_STROKE_LINE: 3154 { 3155 ViewStrokeLineInfo info; 3156 link.Read<ViewStrokeLineInfo>(&info); 3157 3158 picture->WriteStrokeLine(info.startPoint, info.endPoint); 3159 break; 3160 } 3161 3162 case AS_STROKE_LINEARRAY: 3163 { 3164 int32 lineCount; 3165 if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0) 3166 break; 3167 3168 // To speed things up, try to use a stack allocation and only 3169 // fall back to the heap if there are enough lines... 3170 ViewLineArrayInfo* lineData; 3171 const int32 kStackBufferLineDataCount = 64; 3172 ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount]; 3173 if (lineCount > kStackBufferLineDataCount) { 3174 lineData = new(std::nothrow) ViewLineArrayInfo[lineCount]; 3175 if (lineData == NULL) 3176 break; 3177 } else 3178 lineData = lineDataStackBuffer; 3179 3180 // Read them all in one go 3181 size_t dataSize = lineCount * sizeof(ViewLineArrayInfo); 3182 if (link.Read(lineData, dataSize) != B_OK) { 3183 if (lineData != lineDataStackBuffer) 3184 delete[] lineData; 3185 break; 3186 } 3187 3188 picture->WritePushState(); 3189 3190 for (int32 i = 0; i < lineCount; i++) { 3191 picture->WriteSetHighColor(lineData[i].color); 3192 picture->WriteStrokeLine(lineData[i].startPoint, 3193 lineData[i].endPoint); 3194 } 3195 3196 picture->WritePopState(); 3197 3198 if (lineData != lineDataStackBuffer) 3199 delete[] lineData; 3200 break; 3201 } 3202 3203 case AS_VIEW_SET_LOW_COLOR: 3204 case AS_VIEW_SET_HIGH_COLOR: 3205 { 3206 rgb_color color; 3207 link.Read(&color, sizeof(rgb_color)); 3208 3209 if (code == AS_VIEW_SET_HIGH_COLOR) { 3210 picture->WriteSetHighColor(color); 3211 fCurrentView->CurrentState()->SetHighColor(color); 3212 fWindow->GetDrawingEngine()->SetHighColor(color); 3213 } else { 3214 picture->WriteSetLowColor(color); 3215 fCurrentView->CurrentState()->SetLowColor(color); 3216 fWindow->GetDrawingEngine()->SetLowColor(color); 3217 } 3218 } break; 3219 3220 case AS_DRAW_STRING: 3221 case AS_DRAW_STRING_WITH_DELTA: 3222 { 3223 ViewDrawStringInfo info; 3224 if (link.Read<ViewDrawStringInfo>(&info) != B_OK) 3225 break; 3226 3227 char* string = (char*)malloc(info.stringLength + 1); 3228 if (string == NULL) 3229 break; 3230 3231 if (code != AS_DRAW_STRING_WITH_DELTA) { 3232 // In this case, info.delta will NOT contain valid values. 3233 info.delta = (escapement_delta){ 0, 0 }; 3234 } 3235 3236 if (link.Read(string, info.stringLength) != B_OK) { 3237 free(string); 3238 break; 3239 } 3240 // Terminate the string 3241 string[info.stringLength] = '\0'; 3242 3243 picture->WriteDrawString(info.location, string, info.stringLength, 3244 info.delta); 3245 3246 free(string); 3247 break; 3248 } 3249 3250 case AS_STROKE_SHAPE: 3251 case AS_FILL_SHAPE: 3252 { 3253 BRect shapeFrame; 3254 int32 opCount; 3255 int32 ptCount; 3256 3257 link.Read<BRect>(&shapeFrame); 3258 link.Read<int32>(&opCount); 3259 link.Read<int32>(&ptCount); 3260 3261 uint32* opList = new(std::nothrow) uint32[opCount]; 3262 BPoint* ptList = new(std::nothrow) BPoint[ptCount]; 3263 if (opList != NULL && ptList != NULL 3264 && link.Read(opList, opCount * sizeof(uint32)) >= B_OK 3265 && link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) { 3266 // This might seem a bit weird, but under BeOS, the shapes 3267 // are always offset by the current pen location 3268 BPoint penLocation 3269 = fCurrentView->CurrentState()->PenLocation(); 3270 for (int32 i = 0; i < ptCount; i++) { 3271 ptList[i] += penLocation; 3272 } 3273 const bool fill = (code == AS_FILL_SHAPE); 3274 picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill); 3275 } 3276 3277 delete[] opList; 3278 delete[] ptList; 3279 break; 3280 } 3281 3282 case AS_VIEW_DRAW_BITMAP: 3283 { 3284 ViewDrawBitmapInfo info; 3285 link.Read<ViewDrawBitmapInfo>(&info); 3286 3287 ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken); 3288 if (bitmap == NULL) 3289 break; 3290 3291 picture->WriteDrawBitmap(info.bitmapRect, info.viewRect, 3292 bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(), 3293 bitmap->ColorSpace(), info.options, bitmap->Bits(), 3294 bitmap->BitsLength()); 3295 3296 bitmap->ReleaseReference(); 3297 break; 3298 } 3299 3300 case AS_VIEW_DRAW_PICTURE: 3301 { 3302 int32 token; 3303 link.Read<int32>(&token); 3304 3305 BPoint where; 3306 if (link.Read<BPoint>(&where) == B_OK) { 3307 ServerPicture* pictureToDraw = App()->GetPicture(token); 3308 if (pictureToDraw != NULL) { 3309 // We need to make a copy of the picture, since it can 3310 // change after it has been drawn 3311 ServerPicture* copy = App()->CreatePicture(pictureToDraw); 3312 picture->NestPicture(copy); 3313 picture->WriteDrawPicture(where, copy->Token()); 3314 3315 pictureToDraw->ReleaseReference(); 3316 } 3317 } 3318 break; 3319 } 3320 3321 case AS_VIEW_SET_CLIP_REGION: 3322 { 3323 int32 rectCount; 3324 status_t status = link.Read<int32>(&rectCount); 3325 // a negative count means no 3326 // region for the current draw state, 3327 // but an *empty* region is actually valid! 3328 // even if it means no drawing is allowed 3329 3330 if (status < B_OK) 3331 break; 3332 3333 if (rectCount >= 0) { 3334 // we are supposed to set the clipping region 3335 BRegion region; 3336 if (rectCount > 0 && link.ReadRegion(®ion) < B_OK) 3337 break; 3338 picture->WriteSetClipping(region); 3339 } else { 3340 // we are supposed to clear the clipping region 3341 picture->WriteClearClipping(); 3342 } 3343 break; 3344 } 3345 3346 case AS_VIEW_BEGIN_PICTURE: 3347 { 3348 ServerPicture* newPicture = App()->CreatePicture(); 3349 if (newPicture != NULL) { 3350 newPicture->PushPicture(picture); 3351 newPicture->SyncState(fCurrentView); 3352 fCurrentView->SetPicture(newPicture); 3353 } 3354 break; 3355 } 3356 3357 case AS_VIEW_APPEND_TO_PICTURE: 3358 { 3359 int32 token; 3360 link.Read<int32>(&token); 3361 3362 ServerPicture* appendPicture = App()->GetPicture(token); 3363 if (appendPicture != NULL) { 3364 //picture->SyncState(fCurrentView); 3365 appendPicture->AppendPicture(picture); 3366 } 3367 3368 fCurrentView->SetPicture(appendPicture); 3369 3370 if (appendPicture != NULL) 3371 appendPicture->ReleaseReference(); 3372 break; 3373 } 3374 3375 case AS_VIEW_END_PICTURE: 3376 { 3377 ServerPicture* poppedPicture = picture->PopPicture(); 3378 fCurrentView->SetPicture(poppedPicture); 3379 if (poppedPicture != NULL) 3380 poppedPicture->ReleaseReference(); 3381 3382 fLink.StartMessage(B_OK); 3383 fLink.Attach<int32>(picture->Token()); 3384 fLink.Flush(); 3385 return true; 3386 } 3387 /* 3388 case AS_VIEW_SET_BLENDING_MODE: 3389 { 3390 ViewBlendingModeInfo info; 3391 link.Read<ViewBlendingModeInfo>(&info); 3392 3393 picture->BeginOp(B_PIC_SET_BLENDING_MODE); 3394 picture->AddInt16((int16)info.sourceAlpha); 3395 picture->AddInt16((int16)info.alphaFunction); 3396 picture->EndOp(); 3397 3398 fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha, 3399 info.alphaFunction); 3400 fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha, 3401 info.alphaFunction); 3402 break; 3403 }*/ 3404 default: 3405 return false; 3406 } 3407 3408 if (link.NeedsReply()) { 3409 fLink.StartMessage(B_ERROR); 3410 fLink.Flush(); 3411 } 3412 return true; 3413 } 3414 3415 3416 /*! \brief Message-dispatching loop for the ServerWindow 3417 3418 Watches the ServerWindow's message port and dispatches as necessary 3419 */ 3420 void 3421 ServerWindow::_MessageLooper() 3422 { 3423 // Send a reply to our window - it is expecting fMessagePort 3424 // port and some other info. 3425 3426 fLink.StartMessage(B_OK); 3427 fLink.Attach<port_id>(fMessagePort); 3428 3429 int32 minWidth, maxWidth, minHeight, maxHeight; 3430 fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); 3431 3432 fLink.Attach<BRect>(fWindow->Frame()); 3433 fLink.Attach<float>((float)minWidth); 3434 fLink.Attach<float>((float)maxWidth); 3435 fLink.Attach<float>((float)minHeight); 3436 fLink.Attach<float>((float)maxHeight); 3437 fLink.Flush(); 3438 3439 BPrivate::LinkReceiver& receiver = fLink.Receiver(); 3440 bool quitLoop = false; 3441 3442 while (!quitLoop) { 3443 //STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n", 3444 // fMessagePort)); 3445 3446 int32 code; 3447 status_t status = receiver.GetNextMessage(code); 3448 if (status != B_OK) { 3449 // that shouldn't happen, it's our port 3450 printf("Someone deleted our message port!\n"); 3451 3452 // try to let our client die happily 3453 NotifyQuitRequested(); 3454 break; 3455 } 3456 3457 #ifdef PROFILE_MESSAGE_LOOP 3458 bigtime_t start = system_time(); 3459 #endif 3460 3461 Lock(); 3462 3463 #ifdef PROFILE_MESSAGE_LOOP 3464 bigtime_t diff = system_time() - start; 3465 if (diff > 10000) { 3466 printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n", 3467 Title(), diff); 3468 } 3469 #endif 3470 3471 int32 messagesProcessed = 0; 3472 bigtime_t processingStart = system_time(); 3473 bool lockedDesktopSingleWindow = false; 3474 3475 while (true) { 3476 if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) { 3477 // this means the client has been killed 3478 DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message " 3479 "code\n", Title())); 3480 3481 if (code == AS_DELETE_WINDOW) { 3482 fLink.StartMessage(B_OK); 3483 fLink.Flush(); 3484 } 3485 3486 if (lockedDesktopSingleWindow) 3487 fDesktop->UnlockSingleWindow(); 3488 3489 quitLoop = true; 3490 3491 // ServerWindow's destructor takes care of pulling this object 3492 // off the desktop. 3493 ASSERT(fWindow->IsHidden()); 3494 break; 3495 } 3496 3497 // Acquire the appropriate lock 3498 bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code); 3499 if (needsAllWindowsLocked) { 3500 // We may already still hold the read-lock from the previous 3501 // inner-loop iteration. 3502 if (lockedDesktopSingleWindow) { 3503 fDesktop->UnlockSingleWindow(); 3504 lockedDesktopSingleWindow = false; 3505 } 3506 fDesktop->LockAllWindows(); 3507 } else { 3508 // We never keep the write-lock across inner-loop iterations, 3509 // so there is nothing else to do besides read-locking unless 3510 // we already have the read-lock from the previous iteration. 3511 if (!lockedDesktopSingleWindow) { 3512 fDesktop->LockSingleWindow(); 3513 lockedDesktopSingleWindow = true; 3514 } 3515 } 3516 3517 if (atomic_and(&fRedrawRequested, 0) != 0) { 3518 #ifdef PROFILE_MESSAGE_LOOP 3519 bigtime_t redrawStart = system_time(); 3520 #endif 3521 fWindow->RedrawDirtyRegion(); 3522 #ifdef PROFILE_MESSAGE_LOOP 3523 diff = system_time() - redrawStart; 3524 atomic_add(&sRedrawProcessingTime.count, 1); 3525 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 3526 atomic_add64(&sRedrawProcessingTime.time, diff); 3527 # else 3528 sRedrawProcessingTime.time += diff; 3529 # endif 3530 #endif 3531 } 3532 3533 #ifdef PROFILE_MESSAGE_LOOP 3534 bigtime_t dispatchStart = system_time(); 3535 #endif 3536 _DispatchMessage(code, receiver); 3537 3538 #ifdef PROFILE_MESSAGE_LOOP 3539 if (code >= 0 && code < AS_LAST_CODE) { 3540 diff = system_time() - dispatchStart; 3541 atomic_add(&sMessageProfile[code].count, 1); 3542 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 3543 atomic_add64(&sMessageProfile[code].time, diff); 3544 #else 3545 sMessageProfile[code].time += diff; 3546 #endif 3547 if (diff > 10000) { 3548 printf("ServerWindow %s: message %" B_PRId32 " took %" 3549 B_PRId64 " usecs\n", Title(), code, diff); 3550 } 3551 } 3552 #endif 3553 3554 if (needsAllWindowsLocked) 3555 fDesktop->UnlockAllWindows(); 3556 3557 // Only process up to 70 waiting messages at once (we have the 3558 // Desktop locked), but don't hold the lock longer than 10 ms 3559 if (!receiver.HasMessages() || ++messagesProcessed > 70 3560 || system_time() - processingStart > 10000) { 3561 if (lockedDesktopSingleWindow) 3562 fDesktop->UnlockSingleWindow(); 3563 break; 3564 } 3565 3566 // next message 3567 status_t status = receiver.GetNextMessage(code); 3568 if (status != B_OK) { 3569 // that shouldn't happen, it's our port 3570 printf("Someone deleted our message port!\n"); 3571 if (lockedDesktopSingleWindow) 3572 fDesktop->UnlockSingleWindow(); 3573 3574 // try to let our client die happily 3575 NotifyQuitRequested(); 3576 break; 3577 } 3578 } 3579 3580 Unlock(); 3581 } 3582 3583 // We were asked to quit the message loop - either on request or because of 3584 // an error. 3585 Quit(); 3586 // does not return 3587 } 3588 3589 3590 void 3591 ServerWindow::ScreenChanged(const BMessage* message) 3592 { 3593 SendMessageToClient(message); 3594 3595 if (fDirectWindowInfo != NULL && fDirectWindowInfo->IsFullScreen()) 3596 _ResizeToFullScreen(); 3597 } 3598 3599 3600 status_t 3601 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const 3602 { 3603 if (target == B_NULL_TOKEN) 3604 target = fClientToken; 3605 3606 BMessenger reply; 3607 BMessage::Private messagePrivate((BMessage*)msg); 3608 return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target, 3609 0, false, reply); 3610 } 3611 3612 3613 Window* 3614 ServerWindow::MakeWindow(BRect frame, const char* name, 3615 window_look look, window_feel feel, uint32 flags, uint32 workspace) 3616 { 3617 // The non-offscreen ServerWindow uses the DrawingEngine instance from 3618 // the desktop. 3619 return new(std::nothrow) ::Window(frame, name, look, feel, flags, 3620 workspace, this, fDesktop->HWInterface()->CreateDrawingEngine()); 3621 } 3622 3623 3624 void 3625 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState) 3626 { 3627 ASSERT_MULTI_LOCKED(fDesktop->WindowLocker()); 3628 3629 if (fDirectWindowInfo == NULL) 3630 return; 3631 3632 STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = " 3633 "%" B_PRId32 ")\n", bufferState, driverState)); 3634 3635 status_t status = fDirectWindowInfo->SetState( 3636 (direct_buffer_state)bufferState, (direct_driver_state)driverState, 3637 fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(), 3638 fWindow->VisibleContentRegion()); 3639 3640 if (status != B_OK) { 3641 char errorString[256]; 3642 snprintf(errorString, sizeof(errorString), 3643 "%s killed for a problem in DirectConnected(): %s", 3644 App()->Signature(), strerror(status)); 3645 syslog(LOG_ERR, errorString); 3646 3647 // The client application didn't release the semaphore 3648 // within the given timeout. Or something else went wrong. 3649 // Deleting this member should make it crash. 3650 delete fDirectWindowInfo; 3651 fDirectWindowInfo = NULL; 3652 } else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START) 3653 fIsDirectlyAccessing = true; 3654 else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) 3655 fIsDirectlyAccessing = false; 3656 } 3657 3658 3659 void 3660 ServerWindow::_SetCurrentView(View* view) 3661 { 3662 if (fCurrentView == view) 3663 return; 3664 3665 fCurrentView = view; 3666 fCurrentDrawingRegionValid = false; 3667 _UpdateDrawState(fCurrentView); 3668 3669 #if 0 3670 #if DELAYED_BACKGROUND_CLEARING 3671 if (fCurrentView && fCurrentView->IsBackgroundDirty() 3672 && fWindow->InUpdate()) { 3673 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 3674 if (drawingEngine->LockParallelAccess()) { 3675 fWindow->GetEffectiveDrawingRegion(fCurrentView, 3676 fCurrentDrawingRegion); 3677 fCurrentDrawingRegionValid = true; 3678 BRegion dirty(fCurrentDrawingRegion); 3679 3680 BRegion content; 3681 fWindow->GetContentRegion(&content); 3682 3683 fCurrentView->Draw(drawingEngine, &dirty, &content, false); 3684 3685 drawingEngine->UnlockParallelAccess(); 3686 } 3687 } 3688 #endif 3689 #endif // 0 3690 } 3691 3692 3693 void 3694 ServerWindow::_UpdateDrawState(View* view) 3695 { 3696 // switch the drawing state 3697 // TODO: is it possible to scroll a view while it 3698 // is being drawn? probably not... otherwise the 3699 // "offsets" passed below would need to be updated again 3700 DrawingEngine* drawingEngine = fWindow->GetDrawingEngine(); 3701 if (view != NULL && drawingEngine != NULL) { 3702 BPoint leftTop(0, 0); 3703 if (view->GetAlphaMask() != NULL) { 3704 view->ConvertToScreen(&leftTop); 3705 view->GetAlphaMask()->Update(view->Bounds(), leftTop); 3706 leftTop = BPoint(0, 0); 3707 } 3708 view->ConvertToScreenForDrawing(&leftTop); 3709 drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y); 3710 } 3711 } 3712 3713 3714 void 3715 ServerWindow::_UpdateCurrentDrawingRegion() 3716 { 3717 if (!fCurrentDrawingRegionValid 3718 || fWindow->DrawingRegionChanged(fCurrentView)) { 3719 fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion); 3720 fCurrentDrawingRegionValid = true; 3721 } 3722 } 3723 3724 3725 bool 3726 ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const 3727 { 3728 switch (code) { 3729 case AS_SET_WINDOW_TITLE: 3730 case AS_ADD_TO_SUBSET: 3731 case AS_REMOVE_FROM_SUBSET: 3732 case AS_VIEW_CREATE_ROOT: 3733 case AS_VIEW_CREATE: 3734 case AS_SEND_BEHIND: 3735 case AS_SET_LOOK: 3736 case AS_SET_FEEL: 3737 case AS_SET_FLAGS: 3738 case AS_SET_WORKSPACES: 3739 case AS_WINDOW_MOVE: 3740 case AS_WINDOW_RESIZE: 3741 case AS_SET_SIZE_LIMITS: 3742 case AS_SYSTEM_FONT_CHANGED: 3743 case AS_SET_DECORATOR_SETTINGS: 3744 case AS_GET_MOUSE: 3745 case AS_DIRECT_WINDOW_SET_FULLSCREEN: 3746 // case AS_VIEW_SET_EVENT_MASK: 3747 // case AS_VIEW_SET_MOUSE_EVENT_MASK: 3748 case AS_TALK_TO_DESKTOP_LISTENER: 3749 return true; 3750 default: 3751 return false; 3752 } 3753 } 3754 3755 3756 void 3757 ServerWindow::_ResizeToFullScreen() 3758 { 3759 BRect screenFrame; 3760 3761 { 3762 AutoReadLocker _(fDesktop->ScreenLocker()); 3763 const Screen* screen = fWindow->Screen(); 3764 if (screen == NULL) 3765 return; 3766 3767 screenFrame = fWindow->Screen()->Frame(); 3768 } 3769 3770 fDesktop->MoveWindowBy(fWindow, 3771 screenFrame.left - fWindow->Frame().left, 3772 screenFrame.top - fWindow->Frame().top); 3773 fDesktop->ResizeWindowBy(fWindow, 3774 screenFrame.Width() - fWindow->Frame().Width(), 3775 screenFrame.Height() - fWindow->Frame().Height()); 3776 } 3777 3778 3779 status_t 3780 ServerWindow::_EnableDirectWindowMode() 3781 { 3782 if (fDirectWindowInfo != NULL) { 3783 // already in direct window mode 3784 return B_ERROR; 3785 } 3786 3787 if (fDesktop->HWInterface()->FrontBuffer() == NULL) { 3788 // direct window mode not supported 3789 return B_UNSUPPORTED; 3790 } 3791 3792 fDirectWindowInfo = new(std::nothrow) DirectWindowInfo; 3793 if (fDirectWindowInfo == NULL) 3794 return B_NO_MEMORY; 3795 3796 status_t status = fDirectWindowInfo->InitCheck(); 3797 if (status != B_OK) { 3798 delete fDirectWindowInfo; 3799 fDirectWindowInfo = NULL; 3800 3801 return status; 3802 } 3803 3804 return B_OK; 3805 } 3806 3807 3808 void 3809 ServerWindow::_DirectWindowSetFullScreen(bool enable) 3810 { 3811 window_feel feel = kWindowScreenFeel; 3812 3813 if (enable) { 3814 fDesktop->HWInterface()->SetCursorVisible(false); 3815 3816 fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel()); 3817 _ResizeToFullScreen(); 3818 } else { 3819 const BRect& originalFrame = fDirectWindowInfo->OriginalFrame(); 3820 3821 fDirectWindowInfo->DisableFullScreen(); 3822 3823 // Resize window back to its original size 3824 fDesktop->MoveWindowBy(fWindow, 3825 originalFrame.left - fWindow->Frame().left, 3826 originalFrame.top - fWindow->Frame().top); 3827 fDesktop->ResizeWindowBy(fWindow, 3828 originalFrame.Width() - fWindow->Frame().Width(), 3829 originalFrame.Height() - fWindow->Frame().Height()); 3830 3831 fDesktop->HWInterface()->SetCursorVisible(true); 3832 } 3833 3834 fDesktop->SetWindowFeel(fWindow, feel); 3835 } 3836