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