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