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