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