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