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