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