1 /* 2 * Copyright (c) 2001-2008, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Adi Oanca <adioanca@gmail.com> 8 * Axel Dörfler, axeld@pinc-software.de 9 * Stephan Aßmus <superstippi@gmx.de> 10 * Marcus Overhagen <marcus@overhagen.de> 11 */ 12 13 14 #include "View.h" 15 16 #include "BitmapManager.h" 17 #include "Desktop.h" 18 #include "DrawingEngine.h" 19 #include "Overlay.h" 20 #include "ServerApp.h" 21 #include "ServerBitmap.h" 22 #include "ServerCursor.h" 23 #include "ServerPicture.h" 24 #include "ServerWindow.h" 25 #include "Window.h" 26 27 #include "drawing_support.h" 28 29 #include <List.h> 30 #include <Message.h> 31 #include <PortLink.h> 32 #include <View.h> // for resize modes 33 #include <WindowPrivate.h> 34 35 #include <stdio.h> 36 37 #include <new> 38 39 using std::nothrow; 40 41 42 void 43 resize_frame(IntRect& frame, uint32 resizingMode, int32 x, int32 y) 44 { 45 // follow with left side 46 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 47 frame.left += x; 48 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 49 frame.left += x / 2; 50 51 // follow with right side 52 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 53 frame.right += x; 54 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 55 frame.right += x / 2; 56 57 // follow with top side 58 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 59 frame.top += y; 60 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 61 frame.top += y / 2; 62 63 // follow with bottom side 64 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 65 frame.bottom += y; 66 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 67 frame.bottom += y / 2; 68 } 69 70 71 // #pragma mark - 72 73 74 View::View(IntRect frame, IntPoint scrollingOffset, const char* name, 75 int32 token, uint32 resizeMode, uint32 flags) 76 : 77 fName(name), 78 fToken(token), 79 80 fFrame(frame), 81 fScrollingOffset(scrollingOffset), 82 83 fViewColor((rgb_color){ 255, 255, 255, 255 }), 84 fDrawState(new (nothrow) DrawState), 85 fViewBitmap(NULL), 86 87 fResizeMode(resizeMode), 88 fFlags(flags), 89 90 // Views start visible by default 91 fHidden(false), 92 fVisible(true), 93 fBackgroundDirty(true), 94 fIsDesktopBackground(false), 95 96 fEventMask(0), 97 fEventOptions(0), 98 99 fWindow(NULL), 100 fParent(NULL), 101 102 fFirstChild(NULL), 103 fPreviousSibling(NULL), 104 fNextSibling(NULL), 105 fLastChild(NULL), 106 107 fCursor(NULL), 108 fPicture(NULL), 109 110 fLocalClipping((BRect)Bounds()), 111 fScreenClipping(), 112 fScreenClippingValid(false) 113 { 114 if (fDrawState) 115 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 116 } 117 118 119 View::~View() 120 { 121 if (fViewBitmap != NULL) 122 gBitmapManager->DeleteBitmap(fViewBitmap); 123 124 delete fDrawState; 125 126 // if (fWindow && this == fWindow->TopView()) 127 // fWindow->SetTopView(NULL); 128 129 if (fCursor) 130 fCursor->Release(); 131 132 // iterate over children and delete each one 133 View* view = fFirstChild; 134 while (view) { 135 View* toast = view; 136 view = view->fNextSibling; 137 delete toast; 138 } 139 } 140 141 142 IntRect 143 View::Bounds() const 144 { 145 IntRect bounds(fScrollingOffset.x, fScrollingOffset.y, 146 fScrollingOffset.x + fFrame.Width(), 147 fScrollingOffset.y + fFrame.Height()); 148 return bounds; 149 } 150 151 152 void 153 View::ConvertToVisibleInTopView(IntRect* bounds) const 154 { 155 *bounds = *bounds & Bounds(); 156 // NOTE: this step is necessary even if we don't have a parent! 157 ConvertToParent(bounds); 158 159 if (fParent) 160 fParent->ConvertToVisibleInTopView(bounds); 161 } 162 163 164 void 165 View::AttachedToWindow(::Window* window) 166 { 167 fWindow = window; 168 169 // an ugly hack to detect the desktop background 170 if (window->Feel() == kDesktopWindowFeel && Parent() == TopView()) 171 fIsDesktopBackground = true; 172 173 // insert view into local token space 174 if (fWindow != NULL) { 175 fWindow->ServerWindow()->App()->ViewTokens().SetToken(fToken, 176 B_HANDLER_TOKEN, this); 177 } 178 179 // attach child views as well 180 for (View* child = FirstChild(); child; child = child->NextSibling()) 181 child->AttachedToWindow(window); 182 } 183 184 185 void 186 View::DetachedFromWindow() 187 { 188 // remove view from local token space 189 if (fWindow != NULL) 190 fWindow->ServerWindow()->App()->ViewTokens().RemoveToken(fToken); 191 192 fWindow = NULL; 193 // detach child views as well 194 for (View* child = FirstChild(); child; child = child->NextSibling()) 195 child->DetachedFromWindow(); 196 } 197 198 199 // #pragma mark - 200 201 202 void 203 View::AddChild(View* view) 204 { 205 if (view->fParent) { 206 printf("View::AddChild() - View already has a parent\n"); 207 return; 208 } 209 210 view->fParent = this; 211 212 if (!fLastChild) { 213 // no children yet 214 fFirstChild = view; 215 } else { 216 // append view to formerly last child 217 fLastChild->fNextSibling = view; 218 view->fPreviousSibling = fLastChild; 219 } 220 fLastChild = view; 221 222 view->UpdateVisibleDeep(fVisible); 223 224 if (view->IsVisible()) 225 RebuildClipping(false); 226 227 if (fWindow) { 228 view->AttachedToWindow(fWindow); 229 230 if (view->IsVisible()) { 231 // trigger redraw 232 IntRect clippedFrame = view->Frame(); 233 ConvertToVisibleInTopView(&clippedFrame); 234 BRegion* dirty = fWindow->GetRegion(); 235 if (dirty) { 236 dirty->Set((clipping_rect)clippedFrame); 237 fWindow->MarkContentDirtyAsync(*dirty); 238 fWindow->RecycleRegion(dirty); 239 } 240 } 241 } 242 } 243 244 245 bool 246 View::RemoveChild(View* view) 247 { 248 if (view->fParent != this) { 249 printf("View::RemoveChild(%p - %s) - View is not child of " 250 "this (%p) view!\n", view, view ? view->Name() : NULL, this); 251 return false; 252 } 253 254 view->fParent = NULL; 255 256 if (fLastChild == view) 257 fLastChild = view->fPreviousSibling; 258 // view->fNextSibling would be NULL 259 260 if (fFirstChild == view ) 261 fFirstChild = view->fNextSibling; 262 // view->fPreviousSibling would be NULL 263 264 // connect child before and after view 265 if (view->fPreviousSibling) 266 view->fPreviousSibling->fNextSibling = view->fNextSibling; 267 268 if (view->fNextSibling) 269 view->fNextSibling->fPreviousSibling = view->fPreviousSibling; 270 271 // view has no siblings anymore 272 view->fPreviousSibling = NULL; 273 view->fNextSibling = NULL; 274 275 if (view->IsVisible()) { 276 Overlay* overlay = view->_Overlay(); 277 if (overlay != NULL) 278 overlay->Hide(); 279 280 RebuildClipping(false); 281 } 282 283 if (fWindow) { 284 view->DetachedFromWindow(); 285 286 if (fVisible && view->IsVisible()) { 287 // trigger redraw 288 IntRect clippedFrame = view->Frame(); 289 ConvertToVisibleInTopView(&clippedFrame); 290 BRegion* dirty = fWindow->GetRegion(); 291 if (dirty) { 292 dirty->Set((clipping_rect)clippedFrame); 293 fWindow->MarkContentDirtyAsync(*dirty); 294 fWindow->RecycleRegion(dirty); 295 } 296 } 297 } 298 299 return true; 300 } 301 302 303 View* 304 View::TopView() 305 { 306 // returns the top level view of the hirarchy, 307 // it doesn't have to be the top level of a window 308 309 if (fParent) 310 return fParent->TopView(); 311 312 return this; 313 } 314 315 316 uint32 317 View::CountChildren(bool deep) const 318 { 319 uint32 count = 0; 320 for (View* child = FirstChild(); child; child = child->NextSibling()) { 321 count++; 322 if (deep) { 323 count += child->CountChildren(deep); 324 } 325 } 326 return count; 327 } 328 329 330 void 331 View::CollectTokensForChildren(BList* tokenMap) const 332 { 333 for (View* child = FirstChild(); child; child = child->NextSibling()) { 334 tokenMap->AddItem((void*)child); 335 child->CollectTokensForChildren(tokenMap); 336 } 337 } 338 339 340 #if 0 341 bool 342 View::MarkAt(DrawingEngine* engine, const BPoint& where, int32 level) 343 { 344 BRect rect(fFrame.left, fFrame.top, fFrame.right, fFrame.bottom); 345 346 if (Parent() != NULL) { 347 Parent()->ConvertToScreen(&rect); 348 if (!rect.Contains(where)) 349 return false; 350 351 engine->StrokeRect(rect, (rgb_color){level * 30, level * 30, level * 30}); 352 } 353 354 355 bool found = false; 356 for (View* child = FirstChild(); child; child = child->NextSibling()) { 357 found |= child->MarkAt(engine, where, level + 1); 358 } 359 360 if (!found) { 361 rgb_color color = {0}; 362 switch (level % 2) { 363 case 0: color.green = rand() % 256; break; 364 case 1: color.blue = rand() % 256; break; 365 } 366 367 rect.InsetBy(1, 1); 368 //engine->FillRegion(fLocalClipping, (rgb_color){255, 255, 0, 10}); 369 engine->StrokeRect(rect, color); 370 rect.InsetBy(1, 1); 371 engine->StrokeRect(rect, color); 372 } 373 374 return true; 375 } 376 #endif 377 378 379 void 380 View::FindViews(uint32 flags, BObjectList<View>& list, int32& left) 381 { 382 if ((Flags() & flags) == flags) { 383 list.AddItem(this); 384 left--; 385 return; 386 } 387 388 for (View* child = FirstChild(); child; child = child->NextSibling()) { 389 child->FindViews(flags, list, left); 390 if (left == 0) 391 break; 392 } 393 } 394 395 396 View* 397 View::ViewAt(const BPoint& where) 398 { 399 if (!fVisible) 400 return NULL; 401 402 IntRect frame = Frame(); 403 if (Parent() != NULL) 404 Parent()->ConvertToScreen(&frame); 405 406 if (!frame.Contains(where)) 407 return NULL; 408 409 for (View* child = FirstChild(); child; child = child->NextSibling()) { 410 View* view = child->ViewAt(where); 411 if (view != NULL) 412 return view; 413 } 414 415 return this; 416 } 417 418 419 // #pragma mark - 420 421 422 void 423 View::SetName(const char* string) 424 { 425 fName.SetTo(string); 426 } 427 428 429 void 430 View::SetFlags(uint32 flags) 431 { 432 fFlags = flags; 433 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 434 } 435 436 437 void 438 View::SetDrawingOrigin(BPoint origin) 439 { 440 fDrawState->SetOrigin(origin); 441 442 // rebuild clipping 443 if (fDrawState->HasClipping()) 444 RebuildClipping(false); 445 } 446 447 448 BPoint 449 View::DrawingOrigin() const 450 { 451 BPoint origin(fDrawState->Origin()); 452 float scale = Scale(); 453 454 origin.x *= scale; 455 origin.y *= scale; 456 457 return origin; 458 } 459 460 461 void 462 View::SetScale(float scale) 463 { 464 fDrawState->SetScale(scale); 465 466 // rebuild clipping 467 if (fDrawState->HasClipping()) 468 RebuildClipping(false); 469 } 470 471 472 float 473 View::Scale() const 474 { 475 return CurrentState()->Scale(); 476 } 477 478 479 void 480 View::SetUserClipping(const BRegion* region) 481 { 482 fDrawState->SetClippingRegion(region); 483 484 // rebuild clipping (for just this view) 485 RebuildClipping(false); 486 } 487 488 489 void 490 View::SetViewBitmap(ServerBitmap* bitmap, IntRect sourceRect, 491 IntRect destRect, int32 resizingMode, int32 options) 492 { 493 if (fViewBitmap != NULL) { 494 Overlay* overlay = _Overlay(); 495 496 if (bitmap != NULL) { 497 // take over overlay token from current overlay (if it has any) 498 Overlay* newOverlay = bitmap->Overlay(); 499 500 if (overlay != NULL && newOverlay != NULL) 501 newOverlay->TakeOverToken(overlay); 502 } else if (overlay != NULL) 503 overlay->Hide(); 504 505 gBitmapManager->DeleteBitmap(fViewBitmap); 506 } 507 508 // the caller is allowed to delete the bitmap after setting the background 509 if (bitmap != NULL) 510 bitmap->Acquire(); 511 512 fViewBitmap = bitmap; 513 fBitmapSource = sourceRect; 514 fBitmapDestination = destRect; 515 fBitmapResizingMode = resizingMode; 516 fBitmapOptions = options; 517 518 _UpdateOverlayView(); 519 } 520 521 522 ::Overlay* 523 View::_Overlay() const 524 { 525 if (fViewBitmap == NULL) 526 return NULL; 527 528 return fViewBitmap->Overlay(); 529 } 530 531 532 void 533 View::_UpdateOverlayView() const 534 { 535 Overlay* overlay = _Overlay(); 536 if (overlay == NULL) 537 return; 538 539 IntRect destination = fBitmapDestination; 540 ConvertToScreen(&destination); 541 542 overlay->Configure(fBitmapSource, destination); 543 } 544 545 546 /*! 547 This method is called whenever the window is resized or moved - would 548 be nice to have a better solution for this, though. 549 */ 550 void 551 View::UpdateOverlay() 552 { 553 if (!IsVisible()) 554 return; 555 556 if (_Overlay() != NULL) { 557 _UpdateOverlayView(); 558 } else { 559 // recursively ask children of this view 560 561 for (View* child = FirstChild(); child; child = child->NextSibling()) { 562 child->UpdateOverlay(); 563 } 564 } 565 } 566 567 568 // #pragma mark - 569 570 571 void 572 View::ConvertToParent(BPoint* point) const 573 { 574 // remove scrolling offset and convert to parent coordinate space 575 point->x += fFrame.left - fScrollingOffset.x; 576 point->y += fFrame.top - fScrollingOffset.y; 577 } 578 579 580 void 581 View::ConvertToParent(IntPoint* point) const 582 { 583 // remove scrolling offset and convert to parent coordinate space 584 point->x += fFrame.left - fScrollingOffset.x; 585 point->y += fFrame.top - fScrollingOffset.y; 586 } 587 588 589 void 590 View::ConvertToParent(BRect* rect) const 591 { 592 // remove scrolling offset and convert to parent coordinate space 593 rect->OffsetBy(fFrame.left - fScrollingOffset.x, 594 fFrame.top - fScrollingOffset.y); 595 } 596 597 598 void 599 View::ConvertToParent(IntRect* rect) const 600 { 601 // remove scrolling offset and convert to parent coordinate space 602 rect->OffsetBy(fFrame.left - fScrollingOffset.x, 603 fFrame.top - fScrollingOffset.y); 604 } 605 606 607 void 608 View::ConvertToParent(BRegion* region) const 609 { 610 // remove scrolling offset and convert to parent coordinate space 611 region->OffsetBy(fFrame.left - fScrollingOffset.x, 612 fFrame.top - fScrollingOffset.y); 613 } 614 615 616 void 617 View::ConvertFromParent(BPoint* point) const 618 { 619 // convert from parent coordinate space amd add scrolling offset 620 point->x += fScrollingOffset.x - fFrame.left; 621 point->y += fScrollingOffset.y - fFrame.top; 622 } 623 624 625 void 626 View::ConvertFromParent(IntPoint* point) const 627 { 628 // convert from parent coordinate space amd add scrolling offset 629 point->x += fScrollingOffset.x - fFrame.left; 630 point->y += fScrollingOffset.y - fFrame.top; 631 } 632 633 634 void 635 View::ConvertFromParent(BRect* rect) const 636 { 637 // convert from parent coordinate space amd add scrolling offset 638 rect->OffsetBy(fScrollingOffset.x - fFrame.left, 639 fScrollingOffset.y - fFrame.top); 640 } 641 642 643 void 644 View::ConvertFromParent(IntRect* rect) const 645 { 646 // convert from parent coordinate space amd add scrolling offset 647 rect->OffsetBy(fScrollingOffset.x - fFrame.left, 648 fScrollingOffset.y - fFrame.top); 649 } 650 651 652 void 653 View::ConvertFromParent(BRegion* region) const 654 { 655 // convert from parent coordinate space amd add scrolling offset 656 region->OffsetBy(fScrollingOffset.x - fFrame.left, 657 fScrollingOffset.y - fFrame.top); 658 } 659 660 //! converts a point from local to screen coordinate system 661 void 662 View::ConvertToScreen(BPoint* pt) const 663 { 664 ConvertToParent(pt); 665 666 if (fParent) 667 fParent->ConvertToScreen(pt); 668 } 669 670 671 //! converts a point from local to screen coordinate system 672 void 673 View::ConvertToScreen(IntPoint* pt) const 674 { 675 ConvertToParent(pt); 676 677 if (fParent) 678 fParent->ConvertToScreen(pt); 679 } 680 681 682 //! converts a rect from local to screen coordinate system 683 void 684 View::ConvertToScreen(BRect* rect) const 685 { 686 BPoint offset(0.0, 0.0); 687 ConvertToScreen(&offset); 688 689 rect->OffsetBy(offset); 690 } 691 692 693 //! converts a rect from local to screen coordinate system 694 void 695 View::ConvertToScreen(IntRect* rect) const 696 { 697 BPoint offset(0.0, 0.0); 698 ConvertToScreen(&offset); 699 700 rect->OffsetBy(offset); 701 } 702 703 704 //! converts a region from local to screen coordinate system 705 void 706 View::ConvertToScreen(BRegion* region) const 707 { 708 BPoint offset(0.0, 0.0); 709 ConvertToScreen(&offset); 710 711 region->OffsetBy((int)offset.x, (int)offset.y); 712 } 713 714 715 //! converts a point from screen to local coordinate system 716 void 717 View::ConvertFromScreen(BPoint* pt) const 718 { 719 ConvertFromParent(pt); 720 721 if (fParent) 722 fParent->ConvertFromScreen(pt); 723 } 724 725 726 //! converts a point from screen to local coordinate system 727 void 728 View::ConvertFromScreen(IntPoint* pt) const 729 { 730 ConvertFromParent(pt); 731 732 if (fParent) 733 fParent->ConvertFromScreen(pt); 734 } 735 736 737 //! converts a rect from screen to local coordinate system 738 void 739 View::ConvertFromScreen(BRect* rect) const 740 { 741 BPoint offset(0.0, 0.0); 742 ConvertFromScreen(&offset); 743 744 rect->OffsetBy(offset.x, offset.y); 745 } 746 747 748 //! converts a rect from screen to local coordinate system 749 void 750 View::ConvertFromScreen(IntRect* rect) const 751 { 752 BPoint offset(0.0, 0.0); 753 ConvertFromScreen(&offset); 754 755 rect->OffsetBy((int)offset.x, (int)offset.y); 756 } 757 758 759 //! converts a region from screen to local coordinate system 760 void 761 View::ConvertFromScreen(BRegion* region) const 762 { 763 BPoint offset(0.0, 0.0); 764 ConvertFromScreen(&offset); 765 766 region->OffsetBy((int)offset.x, (int)offset.y); 767 } 768 769 770 //! converts a point from local *drawing* to screen coordinate system 771 void 772 View::ConvertToScreenForDrawing(BPoint* point) const 773 { 774 fDrawState->Transform(point); 775 // NOTE: from here on, don't use the 776 // "*ForDrawing()" versions of the parent! 777 ConvertToScreen(point); 778 } 779 780 781 //! converts a rect from local *drawing* to screen coordinate system 782 void 783 View::ConvertToScreenForDrawing(BRect* rect) const 784 { 785 fDrawState->Transform(rect); 786 // NOTE: from here on, don't use the 787 // "*ForDrawing()" versions of the parent! 788 ConvertToScreen(rect); 789 } 790 791 792 //! converts a region from local *drawing* to screen coordinate system 793 void 794 View::ConvertToScreenForDrawing(BRegion* region) const 795 { 796 fDrawState->Transform(region); 797 // NOTE: from here on, don't use the 798 // "*ForDrawing()" versions of the parent! 799 ConvertToScreen(region); 800 } 801 802 803 //! converts points from local *drawing* to screen coordinate system 804 void 805 View::ConvertToScreenForDrawing(BPoint* dst, const BPoint* src, int32 num) const 806 { 807 // TODO: optimize this, it should be smarter 808 while (num--) { 809 *dst = *src; 810 fDrawState->Transform(dst); 811 // NOTE: from here on, don't use the 812 // "*ForDrawing()" versions of the parent! 813 ConvertToScreen(dst); 814 src++; 815 dst++; 816 } 817 } 818 819 820 //! converts rects from local *drawing* to screen coordinate system 821 void 822 View::ConvertToScreenForDrawing(BRect* dst, const BRect* src, int32 num) const 823 { 824 // TODO: optimize this, it should be smarter 825 while (num--) { 826 *dst = *src; 827 fDrawState->Transform(dst); 828 // NOTE: from here on, don't use the 829 // "*ForDrawing()" versions of the parent! 830 ConvertToScreen(dst); 831 src++; 832 dst++; 833 } 834 } 835 836 837 //! converts regions from local *drawing* to screen coordinate system 838 void 839 View::ConvertToScreenForDrawing(BRegion* dst, const BRegion* src, int32 num) const 840 { 841 // TODO: optimize this, it should be smarter 842 while (num--) { 843 *dst = *src; 844 fDrawState->Transform(dst); 845 // NOTE: from here on, don't use the 846 // "*ForDrawing()" versions of the parent! 847 ConvertToScreen(dst); 848 src++; 849 dst++; 850 } 851 } 852 853 854 //! converts a point from screen to local coordinate system 855 void 856 View::ConvertFromScreenForDrawing(BPoint* point) const 857 { 858 ConvertFromScreen(point); 859 fDrawState->InverseTransform(point); 860 } 861 862 863 // #pragma mark - 864 865 866 void 867 View::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) 868 { 869 if (x == 0 && y == 0) 870 return; 871 872 fFrame.OffsetBy(x, y); 873 874 // to move on screen, we must not be hidden and we must have a parent 875 if (fVisible && fParent && dirtyRegion) { 876 #if 1 877 // based on redraw on new location 878 // the place were we are now visible 879 IntRect newVisibleBounds(Bounds()); 880 // we can use the frame of the old 881 // local clipping to see which parts need invalidation 882 IntRect oldVisibleBounds(newVisibleBounds); 883 oldVisibleBounds.OffsetBy(-x, -y); 884 ConvertToScreen(&oldVisibleBounds); 885 886 ConvertToVisibleInTopView(&newVisibleBounds); 887 888 dirtyRegion->Include((clipping_rect)oldVisibleBounds); 889 // newVisibleBounds already is in screen coords 890 dirtyRegion->Include((clipping_rect)newVisibleBounds); 891 #else 892 // blitting version, invalidates 893 // old contents 894 IntRect oldVisibleBounds(Bounds()); 895 IntRect newVisibleBounds(oldVisibleBounds); 896 oldVisibleBounds.OffsetBy(-x, -y); 897 ConvertToScreen(&oldVisibleBounds); 898 899 // NOTE: using ConvertToVisibleInTopView() 900 // instead of ConvertToScreen()! see below 901 ConvertToVisibleInTopView(&newVisibleBounds); 902 903 newVisibleBounds.OffsetBy(-x, -y); 904 905 // clipping oldVisibleBounds to newVisibleBounds 906 // makes sure we don't copy parts hidden under 907 // parent views 908 BRegion* region = fWindow->GetRegion(); 909 if (region) { 910 region->Set(oldVisibleBounds & newVisibleBounds); 911 fWindow->CopyContents(region, x, y); 912 913 region->Set(oldVisibleBounds); 914 newVisibleBounds.OffsetBy(x, y); 915 region->Exclude((clipping_rect)newVisibleBounds); 916 dirtyRegion->Include(dirty); 917 918 fWindow->RecycleRegion(region); 919 } 920 921 #endif 922 } 923 924 if (!fParent) { 925 // the top view's screen clipping does not change, 926 // because no parts are clipped away from parent 927 // views 928 _MoveScreenClipping(x, y, true); 929 } else { 930 // parts might have been revealed from underneath 931 // the parent, or might now be hidden underneath 932 // the parent, this is taken care of when building 933 // the screen clipping 934 InvalidateScreenClipping(); 935 } 936 } 937 938 939 void 940 View::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) 941 { 942 if (x == 0 && y == 0) 943 return; 944 945 fFrame.right += x; 946 fFrame.bottom += y; 947 948 if (fVisible && dirtyRegion) { 949 IntRect oldBounds(Bounds()); 950 oldBounds.right -= x; 951 oldBounds.bottom -= y; 952 953 BRegion* dirty = fWindow->GetRegion(); 954 if (!dirty) 955 return; 956 957 dirty->Set((clipping_rect)Bounds()); 958 dirty->Include((clipping_rect)oldBounds); 959 960 if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) { 961 // the dirty region is just the difference of 962 // old and new bounds 963 dirty->Exclude((clipping_rect)(oldBounds & Bounds())); 964 } 965 966 InvalidateScreenClipping(); 967 968 if (dirty->CountRects() > 0) { 969 if ((fFlags & B_DRAW_ON_CHILDREN) == 0) { 970 // exclude children, they are expected to 971 // include their own dirty regions in ParentResized() 972 for (View* child = FirstChild(); child; 973 child = child->NextSibling()) { 974 if (!child->IsVisible()) 975 continue; 976 IntRect previousChildVisible( 977 child->Frame() & oldBounds & Bounds()); 978 if (dirty->Frame().Intersects(previousChildVisible)) { 979 dirty->Exclude((clipping_rect)previousChildVisible); 980 } 981 } 982 } 983 984 ConvertToScreen(dirty); 985 dirtyRegion->Include(dirty); 986 } 987 fWindow->RecycleRegion(dirty); 988 } 989 990 // layout the children 991 for (View* child = FirstChild(); child; child = child->NextSibling()) 992 child->ParentResized(x, y, dirtyRegion); 993 994 // view bitmap 995 996 resize_frame(fBitmapDestination, fBitmapResizingMode, x, y); 997 998 // at this point, children are at their new locations, 999 // so we can rebuild the clipping 1000 // TODO: when the implementation of Hide() and Show() is 1001 // complete, see if this should be avoided 1002 RebuildClipping(false); 1003 } 1004 1005 1006 void 1007 View::ParentResized(int32 x, int32 y, BRegion* dirtyRegion) 1008 { 1009 IntRect newFrame = fFrame; 1010 resize_frame(newFrame, fResizeMode & 0x0000ffff, x, y); 1011 1012 if (newFrame != fFrame) { 1013 // careful, MoveBy will change fFrame 1014 int32 widthDiff = (int32)(newFrame.Width() - fFrame.Width()); 1015 int32 heightDiff = (int32)(newFrame.Height() - fFrame.Height()); 1016 1017 MoveBy(newFrame.left - fFrame.left, 1018 newFrame.top - fFrame.top, dirtyRegion); 1019 1020 ResizeBy(widthDiff, heightDiff, dirtyRegion); 1021 } else { 1022 // TODO: this covers the fact that our screen clipping might change 1023 // when the parent changes its size, even though our frame stays 1024 // the same - there might be a way to test for this, but axeld doesn't 1025 // know, stippi should look into this when he's back :) 1026 InvalidateScreenClipping(); 1027 } 1028 } 1029 1030 1031 void 1032 View::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion) 1033 { 1034 if (!fVisible || !fWindow) { 1035 fScrollingOffset.x += x; 1036 fScrollingOffset.y += y; 1037 return; 1038 } 1039 1040 // blitting version, invalidates 1041 // old contents 1042 1043 // remember old bounds for tracking dirty region 1044 IntRect oldBounds(Bounds()); 1045 1046 // NOTE: using ConvertToVisibleInTopView() 1047 // instead of ConvertToScreen(), this makes 1048 // sure we don't try to move or invalidate an 1049 // area hidden underneath the parent view 1050 ConvertToVisibleInTopView(&oldBounds); 1051 1052 // find the area of the view that can be scrolled, 1053 // contents are shifted in the opposite direction from scrolling 1054 IntRect stillVisibleBounds(oldBounds); 1055 stillVisibleBounds.OffsetBy(x, y); 1056 stillVisibleBounds = stillVisibleBounds & oldBounds; 1057 1058 fScrollingOffset.x += x; 1059 fScrollingOffset.y += y; 1060 1061 // do the blit, this will make sure 1062 // that other more complex dirty regions 1063 // are taken care of 1064 BRegion* copyRegion = fWindow->GetRegion(); 1065 if (!copyRegion) 1066 return; 1067 copyRegion->Set((clipping_rect)stillVisibleBounds); 1068 fWindow->CopyContents(copyRegion, -x, -y); 1069 1070 // find the dirty region as far as we are 1071 // concerned 1072 BRegion* dirty = copyRegion; 1073 // reuse copyRegion and call it dirty 1074 1075 dirty->Set((clipping_rect)oldBounds); 1076 stillVisibleBounds.OffsetBy(-x, -y); 1077 dirty->Exclude((clipping_rect)stillVisibleBounds); 1078 dirtyRegion->Include(dirty); 1079 1080 fWindow->RecycleRegion(dirty); 1081 1082 // the screen clipping of this view and it's 1083 // childs is no longer valid 1084 InvalidateScreenClipping(); 1085 RebuildClipping(false); 1086 } 1087 1088 1089 void 1090 View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping) 1091 { 1092 if (!fVisible || !fWindow) 1093 return; 1094 1095 // TODO: confirm that in R5 this call is affected by origin and scale 1096 1097 // blitting version 1098 1099 int32 xOffset = dst.left - src.left; 1100 int32 yOffset = dst.top - src.top; 1101 1102 // figure out which part can be blittet 1103 IntRect visibleSrc(src); 1104 ConvertToVisibleInTopView(&visibleSrc); 1105 1106 IntRect visibleSrcAtDest(src); 1107 visibleSrcAtDest.OffsetBy(xOffset, yOffset); 1108 ConvertToVisibleInTopView(&visibleSrcAtDest); 1109 1110 // clip src to visible at dest 1111 visibleSrcAtDest.OffsetBy(-xOffset, -yOffset); 1112 visibleSrc = visibleSrc & visibleSrcAtDest; 1113 1114 // do the blit, this will make sure 1115 // that other more complex dirty regions 1116 // are taken care of 1117 BRegion* copyRegion = fWindow->GetRegion(); 1118 if (!copyRegion) 1119 return; 1120 1121 // move src rect to destination here for efficiency reasons 1122 visibleSrc.OffsetBy(xOffset, yOffset); 1123 1124 // we need to interstect the copyRegion too times, onces 1125 // at the source and once at the destination (here done 1126 // the other way arround but it doesn't matter) 1127 // the reason for this is that we are not supposed to visually 1128 // copy children in the source rect and neither to copy onto 1129 // children in the destination rect... 1130 copyRegion->Set((clipping_rect)visibleSrc); 1131 copyRegion->IntersectWith(&ScreenClipping(&windowContentClipping)); 1132 // note that fScreenClipping is used directly from hereon 1133 // because it is now up to date 1134 1135 copyRegion->OffsetBy(-xOffset, -yOffset); 1136 copyRegion->IntersectWith(&fScreenClipping); 1137 1138 // do the actual blit 1139 fWindow->CopyContents(copyRegion, xOffset, yOffset); 1140 1141 // find the dirty region as far as we are concerned 1142 IntRect dirtyDst(dst); 1143 ConvertToVisibleInTopView(&dirtyDst); 1144 1145 BRegion* dirty = fWindow->GetRegion(); 1146 if (!dirty) { 1147 fWindow->RecycleRegion(copyRegion); 1148 return; 1149 } 1150 1151 // offset copyRegion to destination again 1152 copyRegion->OffsetBy(xOffset, yOffset); 1153 // start with destination given by user 1154 dirty->Set((clipping_rect)dirtyDst); 1155 // exclude the part that we could copy 1156 dirty->Exclude(copyRegion); 1157 1158 dirty->IntersectWith(&fScreenClipping); 1159 fWindow->MarkContentDirty(*dirty); 1160 1161 fWindow->RecycleRegion(dirty); 1162 fWindow->RecycleRegion(copyRegion); 1163 } 1164 1165 1166 // #pragma mark - 1167 1168 1169 void 1170 View::PushState() 1171 { 1172 DrawState* newState = fDrawState->PushState(); 1173 if (newState) { 1174 fDrawState = newState; 1175 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 1176 } 1177 } 1178 1179 1180 void 1181 View::PopState() 1182 { 1183 if (fDrawState->PreviousState() == NULL) { 1184 fprintf(stderr, "WARNING: User called BView(%s)::PopState(), " 1185 "but there is NO state on stack!\n", Name()); 1186 return; 1187 } 1188 1189 bool rebuildClipping = true; //fDrawState->ClippingRegion() != NULL; 1190 1191 fDrawState = fDrawState->PopState(); 1192 fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 1193 1194 // rebuild clipping 1195 // (the clipping from the popped state is not effective anymore) 1196 if (rebuildClipping) 1197 RebuildClipping(false); 1198 } 1199 1200 1201 void 1202 View::SetEventMask(uint32 eventMask, uint32 options) 1203 { 1204 fEventMask = eventMask; 1205 fEventOptions = options; 1206 } 1207 1208 1209 void 1210 View::SetCursor(ServerCursor *cursor) 1211 { 1212 if (cursor == fCursor) 1213 return; 1214 1215 if (fCursor) 1216 fCursor->Release(); 1217 1218 fCursor = cursor; 1219 1220 if (fCursor) { 1221 fCursor->Acquire(); 1222 fCursor->SetPendingViewCursor(false); 1223 } 1224 } 1225 1226 1227 void 1228 View::SetPicture(ServerPicture *picture) 1229 { 1230 fPicture = picture; 1231 } 1232 1233 1234 void 1235 View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, 1236 BRegion* windowContentClipping, bool deep) 1237 { 1238 if (!fVisible) { 1239 // child views cannot be visible either 1240 return; 1241 } 1242 1243 if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) { 1244 // we can only draw within our own area 1245 BRegion* redraw = fWindow->GetRegion(ScreenClipping(windowContentClipping)); 1246 if (!redraw) 1247 return; 1248 // add the current clipping 1249 redraw->IntersectWith(effectiveClipping); 1250 1251 Overlay* overlayCookie = _Overlay(); 1252 1253 if (fViewBitmap != NULL && overlayCookie == NULL) { 1254 // draw view bitmap 1255 // TODO: support other options! 1256 BRect rect = fBitmapDestination; 1257 ConvertToScreenForDrawing(&rect); 1258 1259 align_rect_to_pixels(&rect); 1260 1261 if (fBitmapOptions & B_TILE_BITMAP_Y) { 1262 // move rect up as much as needed 1263 while (rect.top > redraw->Frame().top) 1264 rect.OffsetBy(0.0, -(rect.Height() + 1)); 1265 } 1266 if (fBitmapOptions & B_TILE_BITMAP_X) { 1267 // move rect left as much as needed 1268 while (rect.left > redraw->Frame().left) 1269 rect.OffsetBy(-(rect.Width() + 1), 0.0); 1270 } 1271 1272 // XXX: locking removed because the Window keeps the engine locked 1273 // because it keeps track of syncing right now 1274 1275 // lock the drawing engine for as long as we need the clipping 1276 // to be valid 1277 if (rect.IsValid()/* && drawingEngine->Lock()*/) { 1278 drawingEngine->ConstrainClippingRegion(redraw); 1279 1280 if (fBitmapOptions & B_TILE_BITMAP) { 1281 // tile across entire view 1282 1283 float start = rect.left; 1284 while (rect.top < redraw->Frame().bottom) { 1285 while (rect.left < redraw->Frame().right) { 1286 drawingEngine->DrawBitmap(fViewBitmap, 1287 fBitmapSource, rect); 1288 rect.OffsetBy(rect.Width() + 1, 0.0); 1289 } 1290 rect.OffsetBy(start - rect.left, rect.Height() + 1); 1291 } 1292 // nothing left to be drawn 1293 redraw->MakeEmpty(); 1294 } else if (fBitmapOptions & B_TILE_BITMAP_X) { 1295 // tile in x direction 1296 1297 while (rect.left < redraw->Frame().right) { 1298 drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource, 1299 rect); 1300 rect.OffsetBy(rect.Width() + 1, 0.0); 1301 } 1302 // remove horizontal stripe from clipping 1303 rect.left = redraw->Frame().left; 1304 rect.right = redraw->Frame().right; 1305 redraw->Exclude(rect); 1306 } else if (fBitmapOptions & B_TILE_BITMAP_Y) { 1307 // tile in y direction 1308 1309 while (rect.top < redraw->Frame().bottom) { 1310 drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource, 1311 rect); 1312 rect.OffsetBy(0.0, rect.Height() + 1); 1313 } 1314 // remove vertical stripe from clipping 1315 rect.top = redraw->Frame().top; 1316 rect.bottom = redraw->Frame().bottom; 1317 redraw->Exclude(rect); 1318 } else { 1319 // no tiling at all 1320 1321 drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource, 1322 rect); 1323 redraw->Exclude(rect); 1324 } 1325 1326 // NOTE: It is ok not to reset the clipping, that 1327 // would only waste time 1328 // drawingEngine->Unlock(); 1329 } 1330 1331 } 1332 1333 if (fViewColor != B_TRANSPARENT_COLOR) { 1334 // fill visible region with view color, 1335 // this version of FillRegion ignores any 1336 // clipping, that's why "redraw" needs to 1337 // be correct 1338 // see #634 1339 // if (redraw->Frame().left < 0 || redraw->Frame().top < 0) { 1340 // char message[1024]; 1341 // BRect c = effectiveClipping->Frame(); 1342 // BRect w = windowContentClipping->Frame(); 1343 // BRect r = redraw->Frame(); 1344 // sprintf(message, "invalid background: current clipping: (%d, %d)->(%d, %d), " 1345 // "window content: (%d, %d)->(%d, %d), redraw: (%d, %d)->(%d, %d)", 1346 // (int)c.left, (int)c.top, (int)c.right, (int)c.bottom, 1347 // (int)w.left, (int)w.top, (int)w.right, (int)w.bottom, 1348 // (int)r.left, (int)r.top, (int)r.right, (int)r.bottom); 1349 // debugger(message); 1350 // } 1351 1352 drawingEngine->FillRegion(*redraw, overlayCookie != NULL 1353 ? overlayCookie->Color() : fViewColor); 1354 } 1355 1356 fWindow->RecycleRegion(redraw); 1357 } 1358 1359 fBackgroundDirty = false; 1360 1361 // let children draw 1362 if (deep) { 1363 for (View* child = FirstChild(); child; child = child->NextSibling()) { 1364 child->Draw(drawingEngine, effectiveClipping, 1365 windowContentClipping, deep); 1366 } 1367 } 1368 } 1369 1370 1371 // #pragma mark - 1372 1373 1374 void 1375 View::MouseDown(BMessage* message, BPoint where) 1376 { 1377 // empty hook method 1378 } 1379 1380 1381 void 1382 View::MouseUp(BMessage* message, BPoint where) 1383 { 1384 // empty hook method 1385 } 1386 1387 1388 void 1389 View::MouseMoved(BMessage* message, BPoint where) 1390 { 1391 // empty hook method 1392 } 1393 1394 1395 // #pragma mark - 1396 1397 1398 void 1399 View::SetHidden(bool hidden) 1400 { 1401 if (fHidden != hidden) { 1402 fHidden = hidden; 1403 1404 // recurse into children and update their visible flag 1405 bool oldVisible = fVisible; 1406 UpdateVisibleDeep(fParent ? fParent->IsVisible() : !fHidden); 1407 if (oldVisible != fVisible) { 1408 // Include or exclude us from the parent area, and update the 1409 // children's clipping as well when the view will be visible 1410 if (fParent) 1411 fParent->RebuildClipping(fVisible); 1412 else 1413 RebuildClipping(fVisible); 1414 1415 if (fWindow) { 1416 // trigger a redraw 1417 IntRect clippedBounds = Bounds(); 1418 ConvertToVisibleInTopView(&clippedBounds); 1419 BRegion* dirty = fWindow->GetRegion(); 1420 if (!dirty) 1421 return; 1422 dirty->Set((clipping_rect)clippedBounds); 1423 fWindow->MarkContentDirty(*dirty); 1424 fWindow->RecycleRegion(dirty); 1425 } 1426 } 1427 } 1428 } 1429 1430 1431 bool 1432 View::IsHidden() const 1433 { 1434 return fHidden; 1435 } 1436 1437 1438 void 1439 View::UpdateVisibleDeep(bool parentVisible) 1440 { 1441 bool wasVisible = fVisible; 1442 1443 fVisible = parentVisible && !fHidden; 1444 for (View* child = FirstChild(); child; child = child->NextSibling()) 1445 child->UpdateVisibleDeep(fVisible); 1446 1447 // overlay handling 1448 1449 Overlay* overlay = _Overlay(); 1450 if (overlay == NULL) 1451 return; 1452 1453 if (fVisible && !wasVisible) 1454 _UpdateOverlayView(); 1455 else if (!fVisible && wasVisible) 1456 overlay->Hide(); 1457 } 1458 1459 1460 // #pragma mark - 1461 1462 1463 void 1464 View::MarkBackgroundDirty() 1465 { 1466 if (fBackgroundDirty) 1467 return; 1468 fBackgroundDirty = true; 1469 for (View* child = FirstChild(); child; child = child->NextSibling()) 1470 child->MarkBackgroundDirty(); 1471 } 1472 1473 1474 void 1475 View::AddTokensForViewsInRegion(BMessage* message, BRegion& region, 1476 BRegion* windowContentClipping) 1477 { 1478 if (!fVisible) 1479 return; 1480 1481 if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) 1482 message->AddInt32("_token", fToken); 1483 1484 for (View* child = FirstChild(); child; child = child->NextSibling()) { 1485 child->AddTokensForViewsInRegion(message, region, 1486 windowContentClipping); 1487 } 1488 } 1489 1490 1491 void 1492 View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region, 1493 BRegion* windowContentClipping) 1494 { 1495 if (!fVisible) 1496 return; 1497 1498 IntRect screenBounds(Bounds()); 1499 ConvertToScreen(&screenBounds); 1500 if (!region.Intersects((clipping_rect)screenBounds)) 1501 return; 1502 1503 if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) 1504 link.Attach<int32>(fToken); 1505 1506 for (View* child = FirstChild(); child; child = child->NextSibling()) { 1507 child->AddTokensForViewsInRegion(link, region, windowContentClipping); 1508 } 1509 } 1510 1511 1512 void 1513 View::PrintToStream() const 1514 { 1515 printf("View: %s\n", Name()); 1516 printf(" fToken: %ld\n", fToken); 1517 printf(" fFrame: IntRect(%ld, %ld, %ld, %ld)\n", fFrame.left, fFrame.top, fFrame.right, fFrame.bottom); 1518 printf(" fScrollingOffset: IntPoint(%ld, %ld)\n", fScrollingOffset.x, fScrollingOffset.y); 1519 printf(" fHidden: %d\n", fHidden); 1520 printf(" fVisible: %d\n", fVisible); 1521 printf(" fWindow: %p\n", fWindow); 1522 printf(" fParent: %p\n", fParent); 1523 printf(" fLocalClipping:\n"); 1524 fLocalClipping.PrintToStream(); 1525 printf(" fScreenClipping:\n"); 1526 fScreenClipping.PrintToStream(); 1527 printf(" valid: %d\n", fScreenClippingValid); 1528 printf(" state:\n"); 1529 printf(" user clipping: %d\n", fDrawState->HasClipping()); 1530 BPoint origin = fDrawState->CombinedOrigin(); 1531 printf(" origin: BPoint(%.1f, %.1f)\n", origin.x, origin.y); 1532 printf(" scale: %.2f\n", fDrawState->CombinedScale()); 1533 printf("\n"); 1534 } 1535 1536 1537 void 1538 View::RebuildClipping(bool deep) 1539 { 1540 // the clipping spans over the bounds area 1541 fLocalClipping.Set((clipping_rect)Bounds()); 1542 1543 if (View* child = FirstChild()) { 1544 // if this view does not draw over children, 1545 // exclude all children from the clipping 1546 if ((fFlags & B_DRAW_ON_CHILDREN) == 0) { 1547 BRegion* childrenRegion = fWindow->GetRegion(); 1548 if (!childrenRegion) 1549 return; 1550 1551 for (; child; child = child->NextSibling()) { 1552 if (child->IsVisible()) 1553 childrenRegion->Include((clipping_rect)child->Frame()); 1554 } 1555 1556 fLocalClipping.Exclude(childrenRegion); 1557 fWindow->RecycleRegion(childrenRegion); 1558 } 1559 // if the operation is "deep", make children rebuild their 1560 // clipping too 1561 if (deep) { 1562 for (child = FirstChild(); child; child = child->NextSibling()) 1563 child->RebuildClipping(true); 1564 } 1565 } 1566 1567 // add the user clipping in case there is one 1568 if (fDrawState->HasClipping()) { 1569 // NOTE: in case the user sets a user defined clipping region, 1570 // rebuilding the clipping is a bit more expensive because there 1571 // is no separate "drawing region"... on the other 1572 // hand, views for which this feature is actually used will 1573 // probably not have any children, so it is not that expensive 1574 // after all 1575 BRegion* screenUserClipping = fWindow->GetRegion(); 1576 if (!screenUserClipping) 1577 return; 1578 fDrawState->GetCombinedClippingRegion(screenUserClipping); 1579 fLocalClipping.IntersectWith(screenUserClipping); 1580 fWindow->RecycleRegion(screenUserClipping); 1581 } 1582 1583 fScreenClippingValid = false; 1584 } 1585 1586 1587 BRegion& 1588 View::ScreenClipping(BRegion* windowContentClipping, bool force) const 1589 { 1590 if (!fScreenClippingValid || force) { 1591 fScreenClipping = fLocalClipping; 1592 ConvertToScreen(&fScreenClipping); 1593 1594 // see if parts of our bounds are hidden underneath 1595 // the parent, the local clipping does not account for this 1596 IntRect clippedBounds = Bounds(); 1597 ConvertToVisibleInTopView(&clippedBounds); 1598 if (clippedBounds.Width() < fScreenClipping.Frame().Width() 1599 || clippedBounds.Height() < fScreenClipping.Frame().Height()) { 1600 BRegion* temp = fWindow->GetRegion(); 1601 if (temp) { 1602 temp->Set((clipping_rect)clippedBounds); 1603 fScreenClipping.IntersectWith(temp); 1604 fWindow->RecycleRegion(temp); 1605 } 1606 } 1607 1608 fScreenClipping.IntersectWith(windowContentClipping); 1609 fScreenClippingValid = true; 1610 } 1611 //printf("###View(%s)::ScreenClipping():\n", Name()); 1612 //fScreenClipping.PrintToStream(); 1613 return fScreenClipping; 1614 } 1615 1616 1617 void 1618 View::InvalidateScreenClipping() 1619 { 1620 // TODO: appearantly, we are calling ScreenClipping() on 1621 // views who's parents don't have a valid screen clipping yet, 1622 // this messes up the logic that for any given view with 1623 // fScreenClippingValid == false, all children have 1624 // fScreenClippingValid == false too. If this could be made the 1625 // case, we could save some performance here with the commented 1626 // out check, since InvalidateScreenClipping() might be called 1627 // frequently. 1628 // TODO: investigate, if InvalidateScreenClipping() could be 1629 // called in "deep" and "non-deep" mode, ie. see if there are 1630 // any cases where the children would still have valid screen 1631 // clipping, even though the parent's screen clipping becomes 1632 // invalid. 1633 // if (!fScreenClippingValid) 1634 // return; 1635 1636 fScreenClippingValid = false; 1637 // invalidate the childrens screen clipping as well 1638 for (View* child = FirstChild(); child; child = child->NextSibling()) { 1639 child->InvalidateScreenClipping(); 1640 } 1641 } 1642 1643 1644 void 1645 View::_MoveScreenClipping(int32 x, int32 y, bool deep) 1646 { 1647 if (fScreenClippingValid) 1648 fScreenClipping.OffsetBy(x, y); 1649 1650 if (deep) { 1651 // move the childrens screen clipping as well 1652 for (View* child = FirstChild(); child; child = child->NextSibling()) { 1653 child->_MoveScreenClipping(x, y, deep); 1654 } 1655 } 1656 } 1657 1658