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