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