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