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