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