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_BEGIN_UPDATE: 1038 DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title())); 1039 fWindowLayer->BeginUpdate(fLink); 1040 break; 1041 1042 case AS_END_UPDATE: 1043 DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title())); 1044 fWindowLayer->EndUpdate(); 1045 break; 1046 1047 case AS_GET_MOUSE: 1048 { 1049 DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle)); 1050 1051 fDesktop->UnlockSingleWindow(); 1052 // Returns 1053 // 1) BPoint mouse location 1054 // 2) int32 button state 1055 1056 BPoint where; 1057 int32 buttons; 1058 fDesktop->EventDispatcher().GetMouse(where, buttons); 1059 fDesktop->LockSingleWindow(); 1060 1061 fLink.StartMessage(B_OK); 1062 fLink.Attach<BPoint>(where); 1063 fLink.Attach<int32>(buttons); 1064 fLink.Flush(); 1065 break; 1066 } 1067 1068 // BDirectWindow communication 1069 1070 case AS_DIRECT_WINDOW_GET_SYNC_DATA: 1071 { 1072 status_t status = _EnableDirectWindowMode(); 1073 1074 fLink.StartMessage(status); 1075 if (status == B_OK) { 1076 struct direct_window_sync_data syncData = { 1077 fDirectWindowData->area, 1078 fDirectWindowData->sem, 1079 fDirectWindowData->sem_ack 1080 }; 1081 1082 fLink.Attach(&syncData, sizeof(syncData)); 1083 } 1084 1085 fLink.Flush(); 1086 break; 1087 } 1088 case AS_DIRECT_WINDOW_SET_FULLSCREEN: 1089 { 1090 // TODO: maybe there is more to do than this? 1091 bool enable; 1092 link.Read<bool>(&enable); 1093 1094 status_t status = B_OK; 1095 if (!fWindowLayer->IsOffscreenWindow()) { 1096 fDesktop->UnlockSingleWindow(); 1097 fDesktop->SetWindowFeel(fWindowLayer, 1098 enable ? kWindowScreenFeel : B_NORMAL_WINDOW_FEEL); 1099 fDesktop->LockSingleWindow(); 1100 } else 1101 status = B_BAD_TYPE; 1102 1103 fLink.StartMessage(status); 1104 fLink.Flush(); 1105 break; 1106 } 1107 1108 // View creation and destruction (don't need a valid fCurrentLayer) 1109 1110 case AS_SET_CURRENT_LAYER: 1111 { 1112 int32 token; 1113 if (link.Read<int32>(&token) != B_OK) 1114 break; 1115 1116 ViewLayer *current; 1117 if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN, 1118 (void**)¤t) != B_OK 1119 || current->Window()->ServerWindow() != this) { 1120 // ToDo: if this happens, we probably want to kill the app and clean up 1121 fprintf(stderr, "ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle, token); 1122 current = NULL; 1123 } else { 1124 DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle, current->Name(), token)); 1125 _SetCurrentLayer(current); 1126 } 1127 break; 1128 } 1129 1130 case AS_LAYER_CREATE_ROOT: 1131 { 1132 STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle)); 1133 1134 // Start receiving top_view data -- pass NULL as the parent view. 1135 // This should be the *only* place where this happens. 1136 if (fCurrentLayer != NULL) { 1137 fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE_ROOT: fCurrentLayer already set!!\n", fTitle); 1138 break; 1139 } 1140 1141 _SetCurrentLayer(_CreateLayerTree(link, NULL)); 1142 fWindowLayer->SetTopLayer(fCurrentLayer); 1143 break; 1144 } 1145 1146 case AS_LAYER_CREATE: 1147 { 1148 STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1149 1150 ViewLayer* parent = NULL; 1151 ViewLayer* newLayer = _CreateLayerTree(link, &parent); 1152 if (parent != NULL && newLayer != NULL) 1153 parent->AddChild(newLayer); 1154 else 1155 fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE: parent or newLayer NULL!!\n", fTitle); 1156 break; 1157 } 1158 1159 default: 1160 // TODO: when creating a ViewLayer, check for yet non-existing ViewLayer::InitCheck() 1161 // and take appropriate actions, then checking for fCurrentLayer->CurrentState() 1162 // is unnecessary 1163 if (fCurrentLayer == NULL || fCurrentLayer->CurrentState() == NULL) { 1164 printf("ServerWindow %s received unexpected code - message offset %ld before top_view attached.\n", Title(), code - B_OK); 1165 return; 1166 } 1167 1168 _DispatchViewMessage(code, link); 1169 break; 1170 } 1171 } 1172 1173 1174 /*! 1175 Dispatches all view messages that need a valid fCurrentLayer. 1176 */ 1177 void 1178 ServerWindow::_DispatchViewMessage(int32 code, 1179 BPrivate::LinkReceiver &link) 1180 { 1181 if (_DispatchPictureMessage(code, link)) 1182 return; 1183 1184 switch (code) { 1185 case AS_LAYER_SCROLL: 1186 { 1187 DTRACE(("ServerWindow %s: Message AS_LAYER_SCROLL: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1188 float dh; 1189 float dv; 1190 1191 link.Read<float>(&dh); 1192 link.Read<float>(&dv); 1193 fWindowLayer->ScrollViewBy(fCurrentLayer, dh, dv); 1194 break; 1195 } 1196 case AS_LAYER_COPY_BITS: 1197 { 1198 BRect src; 1199 BRect dst; 1200 1201 link.Read<BRect>(&src); 1202 link.Read<BRect>(&dst); 1203 1204 BRegion contentRegion; 1205 // TODO: avoid copy operation maybe? 1206 fWindowLayer->GetContentRegion(&contentRegion); 1207 fCurrentLayer->CopyBits(src, dst, contentRegion); 1208 break; 1209 } 1210 case AS_LAYER_DELETE: 1211 { 1212 // Received when a view is detached from a window 1213 1214 int32 token; 1215 if (link.Read<int32>(&token) != B_OK) 1216 break; 1217 1218 ViewLayer *view; 1219 if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN, 1220 (void**)&view) == B_OK 1221 && view->Window()->ServerWindow() == this) { 1222 ViewLayer* parent = view->Parent(); 1223 1224 STRACE(("ServerWindow %s: AS_LAYER_DELETE view: %p, parent: %p\n", 1225 fTitle, view, parent)); 1226 1227 if (parent != NULL) { 1228 parent->RemoveChild(view); 1229 1230 if (view->EventMask() != 0) { 1231 fDesktop->EventDispatcher().RemoveListener(EventTarget(), 1232 token); 1233 } 1234 delete view; 1235 } 1236 } 1237 break; 1238 } 1239 case AS_LAYER_SET_STATE: 1240 { 1241 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1242 1243 fCurrentLayer->CurrentState()->ReadFromLink(link); 1244 // TODO: When is this used?!? 1245 fCurrentLayer->RebuildClipping(true); 1246 _UpdateDrawState(fCurrentLayer); 1247 1248 break; 1249 } 1250 case AS_LAYER_SET_FONT_STATE: 1251 { 1252 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1253 fCurrentLayer->CurrentState()->ReadFontFromLink(link); 1254 _UpdateDrawState(fCurrentLayer); 1255 break; 1256 } 1257 case AS_LAYER_GET_STATE: 1258 { 1259 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1260 1261 fLink.StartMessage(B_OK); 1262 1263 // attach state data 1264 fCurrentLayer->CurrentState()->WriteToLink(fLink.Sender()); 1265 fLink.Flush(); 1266 break; 1267 } 1268 case AS_LAYER_SET_EVENT_MASK: 1269 { 1270 STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1271 uint32 eventMask, options; 1272 1273 link.Read<uint32>(&eventMask); 1274 if (link.Read<uint32>(&options) == B_OK) { 1275 fDesktop->UnlockSingleWindow(); 1276 fCurrentLayer->SetEventMask(eventMask, options); 1277 1278 if (eventMask != 0 || options != 0) { 1279 fDesktop->EventDispatcher().AddListener(EventTarget(), 1280 fCurrentLayer->Token(), eventMask, options); 1281 } else { 1282 fDesktop->EventDispatcher().RemoveListener(EventTarget(), 1283 fCurrentLayer->Token()); 1284 } 1285 fDesktop->LockSingleWindow(); 1286 } 1287 break; 1288 } 1289 case AS_LAYER_SET_MOUSE_EVENT_MASK: 1290 { 1291 STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 1292 uint32 eventMask, options; 1293 1294 link.Read<uint32>(&eventMask); 1295 if (link.Read<uint32>(&options) == B_OK) { 1296 fDesktop->UnlockSingleWindow(); 1297 if (eventMask != 0 || options != 0) { 1298 fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(), 1299 fCurrentLayer->Token(), eventMask, options); 1300 } else { 1301 fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(), 1302 fCurrentLayer->Token()); 1303 } 1304 fDesktop->LockSingleWindow(); 1305 } 1306 1307 // TODO: support B_LOCK_WINDOW_FOCUS option in Desktop 1308 break; 1309 } 1310 case AS_LAYER_MOVE_TO: 1311 { 1312 STRACE(("ServerWindow %s: Message AS_LAYER_MOVE_TO: ViewLayer name: %s\n", 1313 fTitle, fCurrentLayer->Name())); 1314 1315 float x, y; 1316 link.Read<float>(&x); 1317 link.Read<float>(&y); 1318 1319 float offsetX = x - fCurrentLayer->Frame().left; 1320 float offsetY = y - fCurrentLayer->Frame().top; 1321 1322 BRegion dirty; 1323 fCurrentLayer->MoveBy(offsetX, offsetY, &dirty); 1324 1325 // TODO: think about how to avoid this hack: 1326 // the parent clipping needs to be updated, it is not 1327 // done in MoveBy() since it would need to avoid 1328 // too much computations when children are resized because 1329 // follow modes 1330 if (ViewLayer* parent = fCurrentLayer->Parent()) 1331 parent->RebuildClipping(false); 1332 1333 fWindowLayer->MarkContentDirty(dirty); 1334 break; 1335 } 1336 case AS_LAYER_RESIZE_TO: 1337 { 1338 STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_TO: ViewLayer name: %s\n", 1339 fTitle, fCurrentLayer->Name())); 1340 1341 float newWidth, newHeight; 1342 link.Read<float>(&newWidth); 1343 link.Read<float>(&newHeight); 1344 1345 float deltaWidth = newWidth - fCurrentLayer->Frame().Width(); 1346 float deltaHeight = newHeight - fCurrentLayer->Frame().Height(); 1347 1348 BRegion dirty; 1349 fCurrentLayer->ResizeBy(deltaWidth, deltaHeight, &dirty); 1350 1351 // TODO: see above 1352 if (ViewLayer* parent = fCurrentLayer->Parent()) 1353 parent->RebuildClipping(false); 1354 1355 fWindowLayer->MarkContentDirty(dirty); 1356 break; 1357 } 1358 case AS_LAYER_GET_COORD: 1359 { 1360 STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1361 fLink.StartMessage(B_OK); 1362 // our offset in the parent -> will be originX and originY in BView 1363 fLink.Attach<float>(fCurrentLayer->Frame().left); 1364 fLink.Attach<float>(fCurrentLayer->Frame().top); 1365 fLink.Attach<BRect>(fCurrentLayer->Bounds()); 1366 fLink.Flush(); 1367 break; 1368 } 1369 case AS_LAYER_SET_ORIGIN: 1370 { 1371 STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1372 1373 float x, y; 1374 link.Read<float>(&x); 1375 link.Read<float>(&y); 1376 1377 fCurrentLayer->SetDrawingOrigin(BPoint(x, y)); 1378 _UpdateDrawState(fCurrentLayer); 1379 break; 1380 } 1381 case AS_LAYER_GET_ORIGIN: 1382 { 1383 STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1384 fLink.StartMessage(B_OK); 1385 // TODO: rename this where it is used in the BView code! 1386 // (it wants to know scrolling offset, not drawing origin) 1387 fLink.Attach<BPoint>(fCurrentLayer->ScrollingOffset()); 1388 fLink.Flush(); 1389 break; 1390 } 1391 case AS_LAYER_RESIZE_MODE: 1392 { 1393 STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: ViewLayer: %s\n", 1394 Title(), fCurrentLayer->Name())); 1395 1396 uint32 resizeMode; 1397 if (link.Read<uint32>(&resizeMode) == B_OK) 1398 fCurrentLayer->SetResizeMode(resizeMode); 1399 break; 1400 } 1401 case AS_LAYER_SET_CURSOR: 1402 { 1403 DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: ViewLayer: %s\n", Title(), 1404 fCurrentLayer->Name())); 1405 1406 int32 token; 1407 bool sync; 1408 link.Read<int32>(&token); 1409 if (link.Read<bool>(&sync) != B_OK) 1410 break; 1411 1412 if (!fDesktop->GetCursorManager().Lock()) 1413 break; 1414 1415 ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token); 1416 fCurrentLayer->SetCursor(cursor); 1417 1418 fDesktop->GetCursorManager().Unlock(); 1419 1420 if (fWindowLayer->IsFocus()) { 1421 // The cursor might need to be updated now 1422 if (fDesktop->ViewUnderMouse(fWindowLayer) == fCurrentLayer->Token()) 1423 fServerApp->SetCurrentCursor(cursor); 1424 } 1425 if (sync) { 1426 // sync the client (it can now delete the cursor) 1427 fLink.StartMessage(B_OK); 1428 fLink.Flush(); 1429 } 1430 1431 break; 1432 } 1433 case AS_LAYER_SET_FLAGS: 1434 { 1435 uint32 flags; 1436 link.Read<uint32>(&flags); 1437 fCurrentLayer->SetFlags(flags); 1438 _UpdateDrawState(fCurrentLayer); 1439 1440 STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1441 break; 1442 } 1443 case AS_LAYER_HIDE: 1444 { 1445 STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1446 fCurrentLayer->SetHidden(true); 1447 break; 1448 } 1449 case AS_LAYER_SHOW: 1450 { 1451 STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1452 fCurrentLayer->SetHidden(false); 1453 break; 1454 } 1455 case AS_LAYER_SET_LINE_MODE: 1456 { 1457 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1458 int8 lineCap, lineJoin; 1459 float miterLimit; 1460 1461 link.Read<int8>(&lineCap); 1462 link.Read<int8>(&lineJoin); 1463 link.Read<float>(&miterLimit); 1464 1465 fCurrentLayer->CurrentState()->SetLineCapMode((cap_mode)lineCap); 1466 fCurrentLayer->CurrentState()->SetLineJoinMode((join_mode)lineJoin); 1467 fCurrentLayer->CurrentState()->SetMiterLimit(miterLimit); 1468 1469 _UpdateDrawState(fCurrentLayer); 1470 1471 break; 1472 } 1473 case AS_LAYER_GET_LINE_MODE: 1474 { 1475 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1476 fLink.StartMessage(B_OK); 1477 fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineCapMode())); 1478 fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineJoinMode())); 1479 fLink.Attach<float>(fCurrentLayer->CurrentState()->MiterLimit()); 1480 fLink.Flush(); 1481 1482 break; 1483 } 1484 case AS_LAYER_PUSH_STATE: 1485 { 1486 DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1487 1488 fCurrentLayer->PushState(); 1489 // TODO: is this necessary? 1490 _UpdateDrawState(fCurrentLayer); 1491 break; 1492 } 1493 case AS_LAYER_POP_STATE: 1494 { 1495 DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1496 1497 fCurrentLayer->PopState(); 1498 _UpdateDrawState(fCurrentLayer); 1499 break; 1500 } 1501 case AS_LAYER_SET_SCALE: 1502 { 1503 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1504 float scale; 1505 link.Read<float>(&scale); 1506 1507 fCurrentLayer->SetScale(scale); 1508 _UpdateDrawState(fCurrentLayer); 1509 break; 1510 } 1511 case AS_LAYER_GET_SCALE: 1512 { 1513 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1514 1515 fLink.StartMessage(B_OK); 1516 fLink.Attach<float>(fCurrentLayer->CurrentState()->Scale()); 1517 fLink.Flush(); 1518 break; 1519 } 1520 case AS_LAYER_SET_PEN_LOC: 1521 { 1522 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1523 float x, y; 1524 1525 link.Read<float>(&x); 1526 link.Read<float>(&y); 1527 1528 fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y)); 1529 // TODO: is this necessary? 1530 _UpdateDrawState(fCurrentLayer); 1531 break; 1532 } 1533 case AS_LAYER_GET_PEN_LOC: 1534 { 1535 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1536 fLink.StartMessage(B_OK); 1537 fLink.Attach<BPoint>(fCurrentLayer->CurrentState()->PenLocation()); 1538 fLink.Flush(); 1539 1540 break; 1541 } 1542 case AS_LAYER_SET_PEN_SIZE: 1543 { 1544 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1545 float penSize; 1546 link.Read<float>(&penSize); 1547 1548 fCurrentLayer->CurrentState()->SetPenSize(penSize); 1549 //_UpdateDrawState(fCurrentLayer); 1550 fWindowLayer->GetDrawingEngine()->SetPenSize(penSize); 1551 break; 1552 } 1553 case AS_LAYER_GET_PEN_SIZE: 1554 { 1555 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1556 fLink.StartMessage(B_OK); 1557 fLink.Attach<float>(fCurrentLayer->CurrentState()->PenSize()); 1558 fLink.Flush(); 1559 1560 break; 1561 } 1562 case AS_LAYER_SET_VIEW_COLOR: 1563 { 1564 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1565 rgb_color c; 1566 1567 link.Read(&c, sizeof(rgb_color)); 1568 1569 fCurrentLayer->SetViewColor(RGBColor(c)); 1570 break; 1571 } 1572 1573 case AS_LAYER_GET_HIGH_COLOR: 1574 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_HIGH_COLOR: ViewLayer: %s\n", 1575 Title(), fCurrentLayer->Name())); 1576 1577 fLink.StartMessage(B_OK); 1578 fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->HighColor().GetColor32()); 1579 fLink.Flush(); 1580 break; 1581 1582 case AS_LAYER_GET_LOW_COLOR: 1583 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LOW_COLOR: ViewLayer: %s\n", 1584 Title(), fCurrentLayer->Name())); 1585 1586 fLink.StartMessage(B_OK); 1587 fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->LowColor().GetColor32()); 1588 fLink.Flush(); 1589 break; 1590 1591 case AS_LAYER_GET_VIEW_COLOR: 1592 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_VIEW_COLOR: ViewLayer: %s\n", 1593 Title(), fCurrentLayer->Name())); 1594 1595 fLink.StartMessage(B_OK); 1596 fLink.Attach<rgb_color>(fCurrentLayer->ViewColor().GetColor32()); 1597 fLink.Flush(); 1598 break; 1599 1600 case AS_LAYER_SET_BLENDING_MODE: 1601 { 1602 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1603 int8 srcAlpha, alphaFunc; 1604 1605 link.Read<int8>(&srcAlpha); 1606 link.Read<int8>(&alphaFunc); 1607 1608 fCurrentLayer->CurrentState()->SetBlendingMode((source_alpha)srcAlpha, 1609 (alpha_function)alphaFunc); 1610 _UpdateDrawState(fCurrentLayer); 1611 break; 1612 } 1613 case AS_LAYER_GET_BLENDING_MODE: 1614 { 1615 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1616 fLink.StartMessage(B_OK); 1617 fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaSrcMode())); 1618 fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaFncMode())); 1619 fLink.Flush(); 1620 1621 break; 1622 } 1623 case AS_LAYER_SET_DRAWING_MODE: 1624 { 1625 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1626 int8 drawingMode; 1627 1628 link.Read<int8>(&drawingMode); 1629 1630 fCurrentLayer->CurrentState()->SetDrawingMode((drawing_mode)drawingMode); 1631 //_UpdateDrawState(fCurrentLayer); 1632 fWindowLayer->GetDrawingEngine()->SetDrawingMode((drawing_mode)drawingMode); 1633 break; 1634 } 1635 case AS_LAYER_GET_DRAWING_MODE: 1636 { 1637 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1638 fLink.StartMessage(B_OK); 1639 fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->GetDrawingMode())); 1640 fLink.Flush(); 1641 1642 break; 1643 } 1644 case AS_LAYER_SET_VIEW_BITMAP: 1645 { 1646 int32 bitmapToken, resizingMode, options; 1647 BRect srcRect, dstRect; 1648 1649 link.Read<int32>(&bitmapToken); 1650 link.Read<BRect>(&srcRect); 1651 link.Read<BRect>(&dstRect); 1652 link.Read<int32>(&resizingMode); 1653 status_t status = link.Read<int32>(&options); 1654 1655 rgb_color colorKey = {0}; 1656 1657 if (status == B_OK) { 1658 ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken); 1659 if (bitmapToken == -1 || bitmap != NULL) { 1660 bool wasOverlay = fCurrentLayer->ViewBitmap() != NULL 1661 && fCurrentLayer->ViewBitmap()->Overlay() != NULL; 1662 1663 // TODO: this is a race condition: the bitmap could have been 1664 // deleted in the mean time!! 1665 fCurrentLayer->SetViewBitmap(bitmap, srcRect, dstRect, 1666 resizingMode, options); 1667 1668 // TODO: if we revert the view color overlay handling 1669 // in ViewLayer::Draw() to the R5 version, we never 1670 // need to invalidate the view for overlays. 1671 1672 // invalidate view - but only if this is a non-overlay switch 1673 if (bitmap == NULL || bitmap->Overlay() == NULL || !wasOverlay) { 1674 BRegion dirty((BRect)fCurrentLayer->Bounds()); 1675 fWindowLayer->InvalidateView(fCurrentLayer, dirty); 1676 } 1677 1678 if (bitmap != NULL && bitmap->Overlay() != NULL) { 1679 bitmap->Overlay()->SetFlags(options); 1680 colorKey = bitmap->Overlay()->Color().GetColor32(); 1681 } 1682 } else 1683 status = B_BAD_VALUE; 1684 } 1685 1686 fLink.StartMessage(status); 1687 if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) { 1688 // Attach color key for the overlay bitmap 1689 fLink.Attach<rgb_color>(colorKey); 1690 } 1691 1692 fLink.Flush(); 1693 break; 1694 } 1695 case AS_LAYER_PRINT_ALIASING: 1696 { 1697 DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1698 bool fontAliasing; 1699 if (link.Read<bool>(&fontAliasing) == B_OK) { 1700 fCurrentLayer->CurrentState()->SetForceFontAliasing(fontAliasing); 1701 _UpdateDrawState(fCurrentLayer); 1702 } 1703 break; 1704 } 1705 case AS_LAYER_CLIP_TO_PICTURE: 1706 { 1707 DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1708 // TODO: you are not allowed to use ViewLayer regions here!!! 1709 1710 int32 pictureToken; 1711 BPoint where; 1712 bool inverse = false; 1713 1714 link.Read<int32>(&pictureToken); 1715 link.Read<BPoint>(&where); 1716 link.Read<bool>(&inverse); 1717 1718 // search for a picture with the specified token. 1719 ServerPicture *picture = fServerApp->FindPicture(pictureToken); 1720 // TODO: Increase that picture's reference count.(~ allocate a picture) 1721 if (picture == NULL) 1722 break; 1723 1724 BRegion region; 1725 // TODO: I think we also need the BView's token 1726 // I think PictureToRegion would fit better into the ViewLayer class (?) 1727 if (PictureToRegion(picture, region, inverse, where) < B_OK) 1728 break; 1729 1730 fCurrentLayer->SetUserClipping(®ion); 1731 1732 // TODO: reenable AS_LAYER_CLIP_TO_PICTURE 1733 #if 0 1734 if (rootLayer && !(fCurrentLayer->IsHidden()) && !fWindowLayer->InUpdate()) { 1735 BRegion invalidRegion; 1736 fCurrentLayer->GetOnScreenRegion(invalidRegion); 1737 1738 // TODO: this is broken! a smaller area may be invalidated! 1739 1740 fCurrentLayer->fParent->MarkForRebuild(invalidRegion); 1741 fCurrentLayer->fParent->TriggerRebuild(); 1742 rootLayer->MarkForRedraw(invalidRegion); 1743 rootLayer->TriggerRedraw(); 1744 } 1745 #endif 1746 break; 1747 } 1748 1749 case AS_LAYER_GET_CLIP_REGION: 1750 { 1751 DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1752 1753 // if this ViewLayer is hidden, it is clear that its visible region is void. 1754 fLink.StartMessage(B_OK); 1755 if (fCurrentLayer->IsHidden()) { 1756 BRegion empty; 1757 fLink.AttachRegion(empty); 1758 } else { 1759 BRegion drawingRegion = fCurrentLayer->LocalClipping(); 1760 fLink.AttachRegion(drawingRegion); 1761 } 1762 fLink.Flush(); 1763 1764 break; 1765 } 1766 case AS_LAYER_SET_CLIP_REGION: 1767 { 1768 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1769 1770 int32 rectCount; 1771 status_t status = link.Read<int32>(&rectCount); 1772 // a negative count means no 1773 // region for the current draw state, 1774 // but an *empty* region is actually valid! 1775 // even if it means no drawing is allowed 1776 1777 if (status < B_OK) 1778 break; 1779 1780 if (rectCount >= 0) { 1781 // we are supposed to set the clipping region 1782 BRegion region; 1783 if (link.ReadRegion(®ion) < B_OK) 1784 break; 1785 fCurrentLayer->SetUserClipping(®ion); 1786 } else { 1787 // we are supposed to unset the clipping region 1788 // passing NULL sets this states region to that 1789 // of the previous state 1790 fCurrentLayer->SetUserClipping(NULL); 1791 } 1792 1793 break; 1794 } 1795 1796 case AS_LAYER_INVALIDATE_RECT: 1797 { 1798 DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1799 1800 // NOTE: looks like this call is NOT affected by origin and scale on R5 1801 // so this implementation is "correct" 1802 BRect invalidRect; 1803 if (link.Read<BRect>(&invalidRect) == B_OK) { 1804 BRegion dirty(invalidRect); 1805 fWindowLayer->InvalidateView(fCurrentLayer, dirty); 1806 } 1807 break; 1808 } 1809 case AS_LAYER_INVALIDATE_REGION: 1810 { 1811 DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1812 1813 // NOTE: looks like this call is NOT affected by origin and scale on R5 1814 // so this implementation is "correct" 1815 BRegion region; 1816 if (link.ReadRegion(®ion) < B_OK) 1817 break; 1818 1819 fWindowLayer->InvalidateView(fCurrentLayer, region); 1820 break; 1821 } 1822 1823 case AS_LAYER_SET_HIGH_COLOR: 1824 { 1825 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1826 1827 rgb_color c; 1828 link.Read(&c, sizeof(rgb_color)); 1829 1830 fCurrentLayer->CurrentState()->SetHighColor(RGBColor(c)); 1831 // _UpdateDrawState(fCurrentLayer); 1832 fWindowLayer->GetDrawingEngine()->SetHighColor(c); 1833 break; 1834 } 1835 case AS_LAYER_SET_LOW_COLOR: 1836 { 1837 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); 1838 1839 rgb_color c; 1840 link.Read(&c, sizeof(rgb_color)); 1841 1842 fCurrentLayer->CurrentState()->SetLowColor(RGBColor(c)); 1843 // _UpdateDrawState(fCurrentLayer); 1844 fWindowLayer->GetDrawingEngine()->SetLowColor(c); 1845 break; 1846 } 1847 case AS_LAYER_SET_PATTERN: 1848 { 1849 DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: ViewLayer: %s\n", fTitle, fCurrentLayer->Name())); 1850 1851 pattern pat; 1852 link.Read(&pat, sizeof(pattern)); 1853 1854 fCurrentLayer->CurrentState()->SetPattern(Pattern(pat)); 1855 // _UpdateDrawState(fCurrentLayer); 1856 fWindowLayer->GetDrawingEngine()->SetPattern(pat); 1857 break; 1858 } 1859 case AS_SET_FONT: 1860 { 1861 DTRACE(("ServerWindow %s: Message AS_SET_FONT\n", Title())); 1862 // TODO: Implement AS_SET_FONT? 1863 // Confusing!! But it works already! 1864 break; 1865 } 1866 case AS_SET_FONT_SIZE: 1867 { 1868 DTRACE(("ServerWindow %s: Message AS_SET_FONT_SIZE\n", Title())); 1869 // TODO: Implement AS_SET_FONT_SIZE? 1870 break; 1871 } 1872 case AS_SYNC: 1873 { 1874 // the synchronisation works by the fact that the client 1875 // window is waiting for this reply, after having received it, 1876 // client and server queues are in sync (earlier, the client 1877 // may have pushed drawing commands at the server and now it 1878 // knows they have all been carried out) 1879 fLink.StartMessage(B_OK); 1880 fLink.Flush(); 1881 break; 1882 } 1883 case AS_LAYER_DRAG_IMAGE: 1884 { 1885 // TODO: flesh out AS_LAYER_DRAG_IMAGE 1886 STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title())); 1887 1888 int32 bitmapToken; 1889 drawing_mode dragMode; 1890 BPoint offset; 1891 int32 bufferSize; 1892 1893 link.Read<int32>(&bitmapToken); 1894 link.Read<int32>((int32*)&dragMode); 1895 link.Read<BPoint>(&offset); 1896 link.Read<int32>(&bufferSize); 1897 1898 if (bufferSize > 0) { 1899 char* buffer = new (nothrow) char[bufferSize]; 1900 BMessage dragMessage; 1901 if (link.Read(buffer, bufferSize) == B_OK 1902 && dragMessage.Unflatten(buffer) == B_OK) { 1903 ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken); 1904 fDesktop->EventDispatcher().SetDragMessage(dragMessage, 1905 bitmap, offset); 1906 } 1907 delete[] buffer; 1908 } 1909 // sync the client (it can now delete the bitmap) 1910 fLink.StartMessage(B_OK); 1911 fLink.Flush(); 1912 1913 break; 1914 } 1915 case AS_LAYER_DRAG_RECT: 1916 { 1917 // TODO: flesh out AS_LAYER_DRAG_RECT 1918 STRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title())); 1919 1920 BRect dragRect; 1921 BPoint offset; 1922 int32 bufferSize; 1923 1924 link.Read<BRect>(&dragRect); 1925 link.Read<BPoint>(&offset); 1926 link.Read<int32>(&bufferSize); 1927 1928 if (bufferSize > 0) { 1929 char* buffer = new (nothrow) char[bufferSize]; 1930 BMessage dragMessage; 1931 if (link.Read(buffer, bufferSize) == B_OK 1932 && dragMessage.Unflatten(buffer) == B_OK) { 1933 fDesktop->EventDispatcher().SetDragMessage(dragMessage, 1934 NULL /* should be dragRect */, offset); 1935 } 1936 delete[] buffer; 1937 } 1938 1939 break; 1940 } 1941 1942 case AS_LAYER_BEGIN_PICTURE: 1943 { 1944 DTRACE(("ServerWindow %s: Message AS_LAYER_BEGIN_PICTURE\n", Title())); 1945 ServerPicture *picture = App()->CreatePicture(); 1946 picture->SyncState(fCurrentLayer); 1947 fCurrentLayer->SetPicture(picture); 1948 break; 1949 } 1950 1951 case AS_LAYER_APPEND_TO_PICTURE: 1952 { 1953 DTRACE(("ServerWindow %s: Message AS_LAYER_APPEND_TO_PICTURE\n", Title())); 1954 1955 int32 pictureToken; 1956 link.Read<int32>(&pictureToken); 1957 ServerPicture *picture = App()->FindPicture(pictureToken); 1958 if (picture) 1959 picture->SyncState(fCurrentLayer); 1960 fCurrentLayer->SetPicture(picture); 1961 // we don't care if it's NULL 1962 break; 1963 } 1964 1965 case AS_LAYER_END_PICTURE: 1966 { 1967 DTRACE(("ServerWindow %s: Message AS_LAYER_END_PICTURE\n", Title())); 1968 1969 ServerPicture *picture = fCurrentLayer->Picture(); 1970 if (picture != NULL) { 1971 fCurrentLayer->SetPicture(NULL); 1972 fLink.StartMessage(B_OK); 1973 fLink.Attach<int32>(picture->Token()); 1974 } else 1975 fLink.StartMessage(B_ERROR); 1976 1977 fLink.Flush(); 1978 break; 1979 } 1980 1981 default: 1982 _DispatchViewDrawingMessage(code, link); 1983 break; 1984 } 1985 } 1986 1987 1988 /*! 1989 Dispatches all view drawing messages. 1990 The desktop clipping must be read locked when entering this method. 1991 Requires a valid fCurrentLayer. 1992 */ 1993 void 1994 ServerWindow::_DispatchViewDrawingMessage(int32 code, BPrivate::LinkReceiver &link) 1995 { 1996 if (!fCurrentLayer->IsVisible() || !fWindowLayer->IsVisible()) { 1997 if (link.NeedsReply()) { 1998 printf("ServerWindow::DispatchViewDrawingMessage() got message %ld that needs a reply!\n", code); 1999 // the client is now blocking and waiting for a reply! 2000 fLink.StartMessage(B_ERROR); 2001 fLink.Flush(); 2002 } 2003 return; 2004 } 2005 2006 DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine(); 2007 if (!drawingEngine) { 2008 // ?!? 2009 DTRACE(("ServerWindow %s: no drawing engine!!\n", Title())); 2010 if (link.NeedsReply()) { 2011 // the client is now blocking and waiting for a reply! 2012 fLink.StartMessage(B_ERROR); 2013 fLink.Flush(); 2014 } 2015 return; 2016 } 2017 2018 if (!fCurrentDrawingRegionValid || fWindowLayer->DrawingRegionChanged(fCurrentLayer)) { 2019 fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion); 2020 fCurrentDrawingRegionValid = true; 2021 } 2022 2023 if (fCurrentDrawingRegion.CountRects() <= 0) { 2024 if (link.NeedsReply()) { 2025 // the client is now blocking and waiting for a reply! 2026 fLink.StartMessage(B_ERROR); 2027 fLink.Flush(); 2028 } 2029 return; 2030 } 2031 2032 drawingEngine->LockParallelAccess(); 2033 // NOTE: the region is not copied, Painter keeps a pointer, 2034 // that's why you need to use the clipping only for as long 2035 // as you have it locked 2036 drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion); 2037 2038 switch (code) { 2039 case AS_STROKE_LINE: 2040 { 2041 DTRACE(("ServerWindow %s: Message AS_STROKE_LINE\n", Title())); 2042 2043 float x1, y1, x2, y2; 2044 2045 link.Read<float>(&x1); 2046 link.Read<float>(&y1); 2047 link.Read<float>(&x2); 2048 link.Read<float>(&y2); 2049 2050 BPoint p1(x1, y1); 2051 BPoint p2(x2, y2); 2052 BPoint penPos = p2; 2053 fCurrentLayer->ConvertToScreenForDrawing(&p1); 2054 fCurrentLayer->ConvertToScreenForDrawing(&p2); 2055 drawingEngine->StrokeLine(p1, p2, fCurrentLayer->CurrentState()); 2056 2057 // We update the pen here because many DrawingEngine calls which do not update the 2058 // pen position actually call StrokeLine 2059 2060 // TODO: Decide where to put this, for example, it cannot be done 2061 // for DrawString(), also there needs to be a decision, if penlocation 2062 // is in View coordinates (I think it should be) or in screen coordinates. 2063 fCurrentLayer->CurrentState()->SetPenLocation(penPos); 2064 break; 2065 } 2066 case AS_LAYER_INVERT_RECT: 2067 { 2068 DTRACE(("ServerWindow %s: Message AS_INVERT_RECT\n", Title())); 2069 2070 BRect rect; 2071 link.Read<BRect>(&rect); 2072 2073 fCurrentLayer->ConvertToScreenForDrawing(&rect); 2074 drawingEngine->InvertRect(rect); 2075 break; 2076 } 2077 case AS_STROKE_RECT: 2078 { 2079 DTRACE(("ServerWindow %s: Message AS_STROKE_RECT\n", Title())); 2080 2081 float left, top, right, bottom; 2082 link.Read<float>(&left); 2083 link.Read<float>(&top); 2084 link.Read<float>(&right); 2085 link.Read<float>(&bottom); 2086 BRect rect(left,top,right,bottom); 2087 2088 fCurrentLayer->ConvertToScreenForDrawing(&rect); 2089 drawingEngine->StrokeRect(rect, fCurrentLayer->CurrentState()); 2090 break; 2091 } 2092 case AS_FILL_RECT: 2093 { 2094 DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n", Title())); 2095 2096 BRect rect; 2097 link.Read<BRect>(&rect); 2098 2099 fCurrentLayer->ConvertToScreenForDrawing(&rect); 2100 drawingEngine->FillRect(rect, fCurrentLayer->CurrentState()); 2101 break; 2102 } 2103 case AS_LAYER_DRAW_BITMAP: 2104 { 2105 DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); 2106 int32 bitmapToken; 2107 BRect srcRect, dstRect; 2108 2109 link.Read<int32>(&bitmapToken); 2110 link.Read<BRect>(&dstRect); 2111 link.Read<BRect>(&srcRect); 2112 2113 ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken); 2114 if (bitmap) { 2115 fCurrentLayer->ConvertToScreenForDrawing(&dstRect); 2116 2117 drawingEngine->DrawBitmap(bitmap, srcRect, dstRect, fCurrentLayer->CurrentState()); 2118 } 2119 2120 break; 2121 } 2122 case AS_STROKE_ARC: 2123 case AS_FILL_ARC: 2124 { 2125 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title())); 2126 2127 float angle, span; 2128 BRect r; 2129 2130 link.Read<BRect>(&r); 2131 link.Read<float>(&angle); 2132 link.Read<float>(&span); 2133 2134 fCurrentLayer->ConvertToScreenForDrawing(&r); 2135 drawingEngine->DrawArc(r, angle, span, fCurrentLayer->CurrentState(), 2136 code == AS_FILL_ARC); 2137 break; 2138 } 2139 case AS_STROKE_BEZIER: 2140 case AS_FILL_BEZIER: 2141 { 2142 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title())); 2143 2144 BPoint pts[4]; 2145 for (int32 i = 0; i < 4; i++) { 2146 link.Read<BPoint>(&(pts[i])); 2147 fCurrentLayer->ConvertToScreenForDrawing(&pts[i]); 2148 } 2149 2150 drawingEngine->DrawBezier(pts, fCurrentLayer->CurrentState(), 2151 code == AS_FILL_BEZIER); 2152 break; 2153 } 2154 case AS_STROKE_ELLIPSE: 2155 case AS_FILL_ELLIPSE: 2156 { 2157 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", Title())); 2158 2159 BRect rect; 2160 link.Read<BRect>(&rect); 2161 2162 fCurrentLayer->ConvertToScreenForDrawing(&rect); 2163 drawingEngine->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE); 2164 break; 2165 } 2166 case AS_STROKE_ROUNDRECT: 2167 case AS_FILL_ROUNDRECT: 2168 { 2169 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", Title())); 2170 2171 BRect rect; 2172 float xrad,yrad; 2173 link.Read<BRect>(&rect); 2174 link.Read<float>(&xrad); 2175 link.Read<float>(&yrad); 2176 2177 fCurrentLayer->ConvertToScreenForDrawing(&rect); 2178 drawingEngine->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT); 2179 break; 2180 } 2181 case AS_STROKE_TRIANGLE: 2182 case AS_FILL_TRIANGLE: 2183 { 2184 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", Title())); 2185 2186 BPoint pts[3]; 2187 BRect rect; 2188 2189 for (int32 i = 0; i < 3; i++) { 2190 link.Read<BPoint>(&(pts[i])); 2191 fCurrentLayer->ConvertToScreenForDrawing(&pts[i]); 2192 } 2193 2194 link.Read<BRect>(&rect); 2195 2196 fCurrentLayer->ConvertToScreenForDrawing(&rect); 2197 drawingEngine->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE); 2198 break; 2199 } 2200 case AS_STROKE_POLYGON: 2201 case AS_FILL_POLYGON: 2202 { 2203 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", Title())); 2204 2205 BRect polyFrame; 2206 bool isClosed = true; 2207 int32 pointCount; 2208 2209 link.Read<BRect>(&polyFrame); 2210 if (code == AS_STROKE_POLYGON) 2211 link.Read<bool>(&isClosed); 2212 link.Read<int32>(&pointCount); 2213 2214 BPoint* pointList = new(nothrow) BPoint[pointCount]; 2215 if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { 2216 for (int32 i = 0; i < pointCount; i++) 2217 fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]); 2218 fCurrentLayer->ConvertToScreenForDrawing(&polyFrame); 2219 2220 drawingEngine->DrawPolygon(pointList, pointCount, polyFrame, 2221 fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON, 2222 isClosed && pointCount > 2); 2223 } 2224 delete[] pointList; 2225 break; 2226 } 2227 case AS_STROKE_SHAPE: 2228 case AS_FILL_SHAPE: 2229 { 2230 DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", Title())); 2231 2232 BRect shapeFrame; 2233 int32 opCount; 2234 int32 ptCount; 2235 2236 link.Read<BRect>(&shapeFrame); 2237 link.Read<int32>(&opCount); 2238 link.Read<int32>(&ptCount); 2239 2240 uint32* opList = new(nothrow) uint32[opCount]; 2241 BPoint* ptList = new(nothrow) BPoint[ptCount]; 2242 if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK && 2243 link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) { 2244 2245 for (int32 i = 0; i < ptCount; i++) 2246 fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]); 2247 2248 drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList, 2249 fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE); 2250 } 2251 2252 delete[] opList; 2253 delete[] ptList; 2254 break; 2255 } 2256 case AS_FILL_REGION: 2257 { 2258 DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title())); 2259 2260 BRegion region; 2261 if (link.ReadRegion(®ion) < B_OK) 2262 break; 2263 2264 fCurrentLayer->ConvertToScreenForDrawing(®ion); 2265 drawingEngine->FillRegion(region, fCurrentLayer->CurrentState()); 2266 2267 break; 2268 } 2269 case AS_STROKE_LINEARRAY: 2270 { 2271 DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", Title())); 2272 2273 // Attached Data: 2274 // 1) int32 Number of lines in the array 2275 // 2) LineArrayData 2276 2277 int32 lineCount; 2278 2279 link.Read<int32>(&lineCount); 2280 if (lineCount > 0) { 2281 LineArrayData lineData[lineCount]; 2282 2283 for (int32 i = 0; i < lineCount; i++) { 2284 LineArrayData* index = &lineData[i]; 2285 2286 link.Read<float>(&(index->pt1.x)); 2287 link.Read<float>(&(index->pt1.y)); 2288 link.Read<float>(&(index->pt2.x)); 2289 link.Read<float>(&(index->pt2.y)); 2290 link.Read<rgb_color>(&(index->color)); 2291 2292 fCurrentLayer->ConvertToScreenForDrawing(&index->pt1); 2293 fCurrentLayer->ConvertToScreenForDrawing(&index->pt2); 2294 } 2295 drawingEngine->StrokeLineArray(lineCount, lineData, 2296 fCurrentLayer->CurrentState()); 2297 } 2298 break; 2299 } 2300 case AS_DRAW_STRING: 2301 { 2302 DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n", Title())); 2303 char* string; 2304 int32 length; 2305 BPoint location; 2306 escapement_delta delta; 2307 2308 link.Read<int32>(&length); 2309 link.Read<BPoint>(&location); 2310 link.Read<escapement_delta>(&delta); 2311 link.ReadString(&string); 2312 2313 fCurrentLayer->ConvertToScreenForDrawing(&location); 2314 BPoint penLocation = drawingEngine->DrawString(string, length, location, 2315 fCurrentLayer->CurrentState(), &delta); 2316 2317 fCurrentLayer->ConvertFromScreenForDrawing(&penLocation); 2318 fCurrentLayer->CurrentState()->SetPenLocation(penLocation); 2319 // TODO: optimize with flags 2320 _UpdateDrawState(fCurrentLayer); 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->ConvertToScreenForDrawing(&where); 2336 fCurrentLayer->CurrentState()->SetPenLocation(where); 2337 // TODO: pass the location to the play method and handle it there 2338 picture->Play(fCurrentLayer); 2339 } 2340 } 2341 break; 2342 } 2343 2344 default: 2345 printf("ServerWindow %s received unexpected code - message offset %ld\n", 2346 Title(), code - B_OK); 2347 2348 if (link.NeedsReply()) { 2349 // the client is now blocking and waiting for a reply! 2350 fLink.StartMessage(B_ERROR); 2351 fLink.Flush(); 2352 } 2353 break; 2354 } 2355 2356 drawingEngine->UnlockParallelAccess(); 2357 } 2358 2359 2360 bool 2361 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link) 2362 { 2363 ServerPicture *picture = fCurrentLayer->Picture(); 2364 if (picture == NULL) 2365 return false; 2366 2367 switch (code) { 2368 case AS_LAYER_SET_ORIGIN: 2369 { 2370 float x, y; 2371 link.Read<float>(&x); 2372 link.Read<float>(&y); 2373 2374 picture->WriteSetOrigin(BPoint(x, y)); 2375 break; 2376 } 2377 2378 case AS_LAYER_INVERT_RECT: 2379 { 2380 BRect rect; 2381 link.Read<BRect>(&rect); 2382 picture->WriteInvertRect(rect); 2383 2384 break; 2385 } 2386 2387 case AS_LAYER_PUSH_STATE: 2388 { 2389 picture->WritePushState(); 2390 break; 2391 } 2392 2393 case AS_LAYER_POP_STATE: 2394 { 2395 picture->WritePopState(); 2396 break; 2397 } 2398 2399 case AS_LAYER_SET_DRAWING_MODE: 2400 { 2401 int8 drawingMode; 2402 link.Read<int8>(&drawingMode); 2403 2404 picture->WriteSetDrawingMode((drawing_mode)drawingMode); 2405 break; 2406 } 2407 2408 case AS_LAYER_SET_PEN_SIZE: 2409 { 2410 float penSize; 2411 link.Read<float>(&penSize); 2412 picture->WriteSetPenSize(penSize); 2413 break; 2414 } 2415 2416 case AS_LAYER_SET_LINE_MODE: 2417 { 2418 int8 lineCap, lineJoin; 2419 float miterLimit; 2420 2421 link.Read<int8>(&lineCap); 2422 link.Read<int8>(&lineJoin); 2423 link.Read<float>(&miterLimit); 2424 2425 picture->WriteSetLineMode((cap_mode)lineCap, (join_mode)lineJoin, miterLimit); 2426 2427 break; 2428 } 2429 case AS_LAYER_SET_SCALE: 2430 { 2431 float scale; 2432 link.Read<float>(&scale); 2433 picture->WriteSetScale(scale); 2434 break; 2435 } 2436 2437 case AS_FILL_RECT: 2438 case AS_STROKE_RECT: 2439 { 2440 BRect rect; 2441 link.Read<BRect>(&rect); 2442 2443 picture->WriteDrawRect(rect, code == AS_FILL_RECT); 2444 break; 2445 } 2446 2447 case AS_STROKE_ROUNDRECT: 2448 case AS_FILL_ROUNDRECT: 2449 { 2450 BRect rect; 2451 link.Read<BRect>(&rect); 2452 2453 BPoint radii; 2454 link.Read<float>(&radii.x); 2455 link.Read<float>(&radii.y); 2456 2457 picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT); 2458 break; 2459 } 2460 2461 case AS_STROKE_ELLIPSE: 2462 case AS_FILL_ELLIPSE: 2463 { 2464 BRect rect; 2465 link.Read<BRect>(&rect); 2466 picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE); 2467 break; 2468 } 2469 2470 case AS_STROKE_ARC: 2471 case AS_FILL_ARC: 2472 { 2473 BRect rect; 2474 link.Read<BRect>(&rect); 2475 float startTheta, arcTheta; 2476 link.Read<float>(&startTheta); 2477 link.Read<float>(&arcTheta); 2478 2479 BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2); 2480 BPoint center = rect.LeftTop() + radii; 2481 2482 picture->WriteDrawArc(center, radii, startTheta, arcTheta, code == AS_FILL_ARC); 2483 break; 2484 } 2485 2486 case AS_STROKE_LINE: 2487 { 2488 float x1, y1, x2, y2; 2489 2490 link.Read<float>(&x1); 2491 link.Read<float>(&y1); 2492 link.Read<float>(&x2); 2493 link.Read<float>(&y2); 2494 2495 picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2)); 2496 break; 2497 } 2498 2499 case AS_STROKE_LINEARRAY: 2500 { 2501 int32 lineCount; 2502 link.Read<int32>(&lineCount); 2503 if (lineCount <= 0) 2504 break; 2505 2506 picture->WritePushState(); 2507 2508 for (int32 i = 0; i < lineCount; i++) { 2509 float x1, y1, x2, y2; 2510 link.Read<float>(&x1); 2511 link.Read<float>(&y1); 2512 link.Read<float>(&x2); 2513 link.Read<float>(&y2); 2514 2515 rgb_color color; 2516 link.Read<rgb_color>(&color); 2517 2518 picture->WriteSetHighColor(color); 2519 picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2)); 2520 } 2521 2522 picture->WritePopState(); 2523 break; 2524 } 2525 2526 case AS_LAYER_SET_LOW_COLOR: 2527 case AS_LAYER_SET_HIGH_COLOR: 2528 { 2529 rgb_color color; 2530 link.Read(&color, sizeof(rgb_color)); 2531 2532 if (code == AS_LAYER_SET_HIGH_COLOR) 2533 picture->WriteSetHighColor(color); 2534 else 2535 picture->WriteSetLowColor(color); 2536 break; 2537 } 2538 2539 case AS_DRAW_STRING: 2540 { 2541 char* string = NULL; 2542 int32 length; 2543 BPoint location; 2544 escapement_delta delta; 2545 2546 link.Read<int32>(&length); 2547 link.Read<BPoint>(&location); 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 const bool fill = (code == AS_FILL_SHAPE); 2575 picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill); 2576 } 2577 delete[] opList; 2578 delete[] ptList; 2579 2580 break; 2581 } 2582 2583 case AS_LAYER_DRAW_BITMAP: 2584 { 2585 int32 token; 2586 link.Read<int32>(&token); 2587 2588 BRect destRect; 2589 link.Read<BRect>(&destRect); 2590 2591 BRect sourceRect; 2592 link.Read<BRect>(&sourceRect); 2593 2594 ServerBitmap *bitmap = App()->FindBitmap(token); 2595 if (bitmap == NULL) 2596 break; 2597 2598 picture->WriteDrawBitmap(sourceRect, destRect, bitmap->Width(), bitmap->Height(), 2599 bitmap->BytesPerRow(), bitmap->ColorSpace(), /*bitmap->Flags()*/0, 2600 bitmap->Bits(), bitmap->BitsLength()); 2601 2602 break; 2603 } 2604 /* 2605 case AS_LAYER_SET_BLENDING_MODE: 2606 { 2607 int8 srcAlpha, alphaFunc; 2608 2609 link.Read<int8>(&srcAlpha); 2610 link.Read<int8>(&alphaFunc); 2611 2612 picture->BeginOp(B_PIC_SET_BLENDING_MODE); 2613 picture->AddInt16((int16)srcAlpha); 2614 picture->AddInt16((int16)alphaFunc); 2615 picture->EndOp(); 2616 2617 break; 2618 }*/ 2619 default: 2620 return false; 2621 } 2622 2623 if (link.NeedsReply()) { 2624 fLink.StartMessage(B_ERROR); 2625 fLink.Flush(); 2626 } 2627 return true; 2628 } 2629 2630 2631 /*! 2632 \brief Message-dispatching loop for the ServerWindow 2633 2634 Watches the ServerWindow's message port and dispatches as necessary 2635 */ 2636 void 2637 ServerWindow::_MessageLooper() 2638 { 2639 BPrivate::LinkReceiver& receiver = fLink.Receiver(); 2640 bool quitLoop = false; 2641 2642 while (!quitLoop) { 2643 //STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n", 2644 // fMessagePort)); 2645 2646 int32 code; 2647 status_t status = receiver.GetNextMessage(code); 2648 if (status < B_OK) { 2649 // that shouldn't happen, it's our port 2650 printf("Someone deleted our message port!\n"); 2651 2652 // try to let our client die happily 2653 NotifyQuitRequested(); 2654 break; 2655 } 2656 2657 #ifdef PROFILE_MESSAGE_LOOP 2658 bigtime_t start = system_time(); 2659 #endif 2660 2661 Lock(); 2662 2663 #ifdef PROFILE_MESSAGE_LOOP 2664 bigtime_t diff = system_time() - start; 2665 if (diff > 10000) 2666 printf("ServerWindow %s: lock acquisition took %Ld usecs\n", Title(), diff); 2667 #endif 2668 2669 int32 messagesProcessed = 0; 2670 bool lockedDesktop = false; 2671 2672 while (true) { 2673 if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) { 2674 // this means the client has been killed 2675 STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n", 2676 Title())); 2677 2678 if (code == AS_DELETE_WINDOW) { 2679 fLink.StartMessage(B_OK); 2680 fLink.Flush(); 2681 } 2682 2683 if (lockedDesktop) 2684 fDesktop->UnlockSingleWindow(); 2685 2686 quitLoop = true; 2687 2688 // ServerWindow's destructor takes care of pulling this object off the desktop. 2689 if (!fWindowLayer->IsHidden()) 2690 CRITICAL("ServerWindow: a window must be hidden before it's deleted\n"); 2691 2692 break; 2693 } 2694 2695 if (!lockedDesktop) { 2696 // only lock it once 2697 fDesktop->LockSingleWindow(); 2698 lockedDesktop = true; 2699 } 2700 2701 if (atomic_and(&fRedrawRequested, 0) != 0) { 2702 #ifdef PROFILE_MESSAGE_LOOP 2703 bigtime_t redrawStart = system_time(); 2704 #endif 2705 fWindowLayer->RedrawDirtyRegion(); 2706 #ifdef PROFILE_MESSAGE_LOOP 2707 diff = system_time() - redrawStart; 2708 atomic_add(&sRedrawProcessingTime.count, 1); 2709 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2710 atomic_add64(&sRedrawProcessingTime.time, diff); 2711 # else 2712 sRedrawProcessingTime.time += diff; 2713 # endif 2714 #endif 2715 } 2716 2717 2718 2719 #ifdef PROFILE_MESSAGE_LOOP 2720 bigtime_t dispatchStart = system_time(); 2721 #endif 2722 _DispatchMessage(code, receiver); 2723 2724 #ifdef PROFILE_MESSAGE_LOOP 2725 if (code >= 0 && code < AS_LAST_CODE) { 2726 diff = system_time() - dispatchStart; 2727 atomic_add(&sMessageProfile[code].count, 1); 2728 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 2729 atomic_add64(&sMessageProfile[code].time, diff); 2730 #else 2731 sMessageProfile[code].time += diff; 2732 #endif 2733 if (diff > 10000) 2734 printf("ServerWindow %s: message %ld took %Ld usecs\n", Title(), code, diff); 2735 } 2736 #endif 2737 2738 // only process up to 70 waiting messages at once (we have the Desktop locked) 2739 if (!receiver.HasMessages() || ++messagesProcessed > 70) { 2740 fDesktop->UnlockSingleWindow(); 2741 break; 2742 } 2743 2744 // next message 2745 status_t status = receiver.GetNextMessage(code); 2746 if (status < B_OK) { 2747 // that shouldn't happen, it's our port 2748 printf("Someone deleted our message port!\n"); 2749 fDesktop->UnlockSingleWindow(); 2750 2751 // try to let our client die happily 2752 NotifyQuitRequested(); 2753 break; 2754 } 2755 } 2756 2757 Unlock(); 2758 } 2759 2760 // we were asked to quit the message loop - either on request or because of an error 2761 Quit(); 2762 // does not return 2763 } 2764 2765 2766 status_t 2767 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const 2768 { 2769 if (target == B_NULL_TOKEN) 2770 target = fClientToken; 2771 2772 BMessenger reply; 2773 BMessage::Private messagePrivate((BMessage *)msg); 2774 return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target, 2775 0, false, reply); 2776 } 2777 2778 2779 WindowLayer* 2780 ServerWindow::MakeWindowLayer(BRect frame, const char* name, 2781 window_look look, window_feel feel, uint32 flags, uint32 workspace) 2782 { 2783 // The non-offscreen ServerWindow uses the DrawingEngine instance from the desktop. 2784 return new (nothrow) WindowLayer(frame, name, look, feel, flags, 2785 // workspace, this, fDesktop->GetDrawingEngine()); 2786 workspace, this, new DrawingEngine(fDesktop->HWInterface())); 2787 } 2788 2789 2790 status_t 2791 ServerWindow::_EnableDirectWindowMode() 2792 { 2793 if (fDirectWindowData != NULL) { 2794 // already in direct window mode 2795 return B_ERROR; 2796 } 2797 2798 fDirectWindowData = new (nothrow) direct_window_data; 2799 if (fDirectWindowData == NULL) 2800 return B_NO_MEMORY; 2801 2802 status_t status = fDirectWindowData->InitCheck(); 2803 if (status < B_OK) { 2804 delete fDirectWindowData; 2805 fDirectWindowData = NULL; 2806 2807 return status; 2808 } 2809 2810 return B_OK; 2811 } 2812 2813 2814 void 2815 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState) 2816 { 2817 STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n", 2818 bufferState, driverState)); 2819 2820 if (fDirectWindowData == NULL 2821 || (!fDirectWindowData->started 2822 && (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START)) 2823 return; 2824 2825 // If the direct connection is stopped, only continue if a start notification is received. 2826 // But save the "reason" of the call (B_BUFFER_RESIZED, B_CLIPPING_MODIFIED, etc) 2827 if ((fDirectWindowData->buffer_info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP 2828 && (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START) { 2829 fDirectWindowData->next_buffer_state |= bufferState & ~B_DIRECT_MODE_MASK; 2830 return; 2831 } 2832 2833 fDirectWindowData->started = true; 2834 2835 fDirectWindowData->buffer_info->buffer_state = 2836 (direct_buffer_state)(bufferState | fDirectWindowData->next_buffer_state); 2837 fDirectWindowData->next_buffer_state = 0; 2838 2839 if (driverState != -1) 2840 fDirectWindowData->buffer_info->driver_state = (direct_driver_state)driverState; 2841 2842 if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) { 2843 // TODO: Locking ? 2844 RenderingBuffer *buffer = fDesktop->HWInterface()->FrontBuffer(); 2845 fDirectWindowData->buffer_info->bits = buffer->Bits(); 2846 fDirectWindowData->buffer_info->pci_bits = NULL; // TODO 2847 fDirectWindowData->buffer_info->bytes_per_row = buffer->BytesPerRow(); 2848 switch (buffer->ColorSpace()) { 2849 case B_RGB32: 2850 case B_RGBA32: 2851 case B_RGB32_BIG: 2852 case B_RGBA32_BIG: 2853 fDirectWindowData->buffer_info->bits_per_pixel = 32; 2854 break; 2855 case B_RGB24: 2856 case B_RGB24_BIG: 2857 fDirectWindowData->buffer_info->bits_per_pixel = 24; 2858 break; 2859 case B_RGB16: 2860 case B_RGB16_BIG: 2861 case B_RGB15: 2862 case B_RGB15_BIG: 2863 fDirectWindowData->buffer_info->bits_per_pixel = 16; 2864 break; 2865 case B_CMAP8: 2866 fDirectWindowData->buffer_info->bits_per_pixel = 8; 2867 break; 2868 default: 2869 fprintf(stderr, "unkown colorspace in HandleDirectConnection()!\n"); 2870 fDirectWindowData->buffer_info->bits_per_pixel = 0; 2871 break; 2872 } 2873 fDirectWindowData->buffer_info->pixel_format = buffer->ColorSpace(); 2874 fDirectWindowData->buffer_info->layout = B_BUFFER_NONINTERLEAVED; 2875 fDirectWindowData->buffer_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO 2876 fDirectWindowData->buffer_info->window_bounds = to_clipping_rect(fWindowLayer->Frame()); 2877 2878 // TODO: Review this 2879 const int32 kMaxClipRectsCount = (B_PAGE_SIZE - sizeof(direct_buffer_info)) 2880 / sizeof(clipping_rect); 2881 2882 // We just want the region inside the window, border excluded. 2883 BRegion clipRegion = fWindowLayer->VisibleContentRegion(); 2884 2885 fDirectWindowData->buffer_info->clip_list_count = min_c(clipRegion.CountRects(), 2886 kMaxClipRectsCount); 2887 fDirectWindowData->buffer_info->clip_bounds = clipRegion.FrameInt(); 2888 2889 for (uint32 i = 0; i < fDirectWindowData->buffer_info->clip_list_count; i++) 2890 fDirectWindowData->buffer_info->clip_list[i] = clipRegion.RectAtInt(i); 2891 } 2892 2893 // Releasing this sem causes the client to call BDirectWindow::DirectConnected() 2894 release_sem(fDirectWindowData->sem); 2895 2896 // TODO: Waiting half a second in the ServerWindow thread is not a problem, 2897 // but since we are called from the Desktop's thread too, very bad things could happen. 2898 // Find some way to call this method only within ServerWindow's thread (messaging ?) 2899 status_t status; 2900 do { 2901 // TODO: The timeout is 3000000 usecs (3 seconds) on beos. 2902 // Test, but I think half a second is enough. 2903 status = acquire_sem_etc(fDirectWindowData->sem_ack, 1, B_TIMEOUT, 500000); 2904 } while (status == B_INTERRUPTED); 2905 2906 if (status < B_OK) { 2907 // The client application didn't release the semaphore 2908 // within the given timeout. Or something else went wrong. 2909 // Deleting this member should make it crash. 2910 delete fDirectWindowData; 2911 fDirectWindowData = NULL; 2912 } 2913 } 2914 2915 2916 void 2917 ServerWindow::_SetCurrentLayer(ViewLayer* layer) 2918 { 2919 if (fCurrentLayer == layer) 2920 return; 2921 2922 fCurrentLayer = layer; 2923 fCurrentDrawingRegionValid = false; 2924 _UpdateDrawState(fCurrentLayer); 2925 2926 #if 0 2927 #if DELAYED_BACKGROUND_CLEARING 2928 if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty() 2929 && fWindowLayer->InUpdate()) { 2930 DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine(); 2931 if (drawingEngine->LockParallelAccess()) { 2932 2933 fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion); 2934 fCurrentDrawingRegionValid = true; 2935 BRegion dirty(fCurrentDrawingRegion); 2936 2937 BRegion content; 2938 fWindowLayer->GetContentRegion(&content); 2939 2940 fCurrentLayer->Draw(drawingEngine, &dirty, &content, false); 2941 2942 drawingEngine->UnlockParallelAccess(); 2943 } 2944 } 2945 #endif 2946 #endif // 0 2947 } 2948 2949 2950 void 2951 ServerWindow::_UpdateDrawState(ViewLayer* layer) 2952 { 2953 // switch the drawing state 2954 // TODO: is it possible to scroll a view while it 2955 // is being drawn? probably not... otherwise the 2956 // "offsets" passed below would need to be updated again 2957 DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine(); 2958 if (layer && drawingEngine) { 2959 IntPoint p = layer->ScrollingOffset(); 2960 p += IntPoint(layer->CurrentState()->Origin()); 2961 drawingEngine->SetDrawState(layer->CurrentState(), p.x, p.y); 2962 } 2963 } 2964 2965 2966 status_t 2967 ServerWindow::PictureToRegion(ServerPicture *picture, BRegion ®ion, 2968 bool inverse, BPoint where) 2969 { 2970 fprintf(stderr, "ServerWindow::PictureToRegion() not implemented\n"); 2971 region.MakeEmpty(); 2972 return B_ERROR; 2973 } 2974