1 /* 2 * Copyright 2001-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Adrian Oanca <adioanca@cotty.iren.ro> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Ingo Weinhold <ingo_weinhold@gmx.de> 10 */ 11 12 13 #include <View.h> 14 15 #include <new> 16 17 #include <math.h> 18 #include <stdio.h> 19 20 #include <Application.h> 21 #include <Bitmap.h> 22 #include <Button.h> 23 #include <Cursor.h> 24 #include <File.h> 25 #include <GradientLinear.h> 26 #include <GradientRadial.h> 27 #include <GradientRadialFocus.h> 28 #include <GradientDiamond.h> 29 #include <GradientConic.h> 30 #include <InterfaceDefs.h> 31 #include <Layout.h> 32 #include <LayoutContext.h> 33 #include <LayoutUtils.h> 34 #include <MenuBar.h> 35 #include <Message.h> 36 #include <MessageQueue.h> 37 #include <Picture.h> 38 #include <Point.h> 39 #include <Polygon.h> 40 #include <PropertyInfo.h> 41 #include <Region.h> 42 #include <ScrollBar.h> 43 #include <Shape.h> 44 #include <Shelf.h> 45 #include <String.h> 46 #include <Window.h> 47 48 #include <AppMisc.h> 49 #include <AppServerLink.h> 50 #include <binary_compatibility/Interface.h> 51 #include <MessagePrivate.h> 52 #include <MessageUtils.h> 53 #include <PortLink.h> 54 #include <ServerProtocol.h> 55 #include <ServerProtocolStructs.h> 56 #include <ShapePrivate.h> 57 #include <ToolTip.h> 58 #include <ToolTipManager.h> 59 #include <TokenSpace.h> 60 #include <ViewPrivate.h> 61 62 63 using std::nothrow; 64 65 //#define DEBUG_BVIEW 66 #ifdef DEBUG_BVIEW 67 # include <stdio.h> 68 # define STRACE(x) printf x 69 # define BVTRACE _PrintToStream() 70 #else 71 # define STRACE(x) ; 72 # define BVTRACE ; 73 #endif 74 75 76 static property_info sViewPropInfo[] = { 77 { "Frame", { B_GET_PROPERTY, B_SET_PROPERTY }, 78 { B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0, 79 { B_RECT_TYPE } 80 }, 81 { "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY }, 82 { B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.", 83 0, { B_BOOL_TYPE } 84 }, 85 { "Shelf", { 0 }, 86 { B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the " 87 "shelf.", 0 88 }, 89 { "View", { B_COUNT_PROPERTIES, 0 }, 90 { B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0, 91 { B_INT32_TYPE } 92 }, 93 { "View", { 0 }, 94 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 }, 95 "Directs the scripting message to the specified view.", 0 96 }, 97 98 { 0, { 0 }, { 0 }, 0, 0 } 99 }; 100 101 102 // #pragma mark - 103 104 105 static inline uint32 106 get_uint32_color(rgb_color color) 107 { 108 return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color); 109 // rgb_color is always in rgba format, no matter what endian; 110 // we always return the int32 value in host endian. 111 } 112 113 114 static inline rgb_color 115 get_rgb_color(uint32 value) 116 { 117 value = B_HOST_TO_BENDIAN_INT32(value); 118 return *(rgb_color*)&value; 119 } 120 121 122 // #pragma mark - 123 124 125 namespace BPrivate { 126 127 ViewState::ViewState() 128 { 129 pen_location.Set(0, 0); 130 pen_size = 1.0; 131 132 // NOTE: the clipping_region is empty 133 // on construction but it is not used yet, 134 // we avoid having to keep track of it via 135 // this flag 136 clipping_region_used = false; 137 138 high_color = (rgb_color){ 0, 0, 0, 255 }; 139 low_color = (rgb_color){ 255, 255, 255, 255 }; 140 view_color = low_color; 141 142 pattern = B_SOLID_HIGH; 143 drawing_mode = B_OP_COPY; 144 145 origin.Set(0, 0); 146 147 line_join = B_MITER_JOIN; 148 line_cap = B_BUTT_CAP; 149 miter_limit = B_DEFAULT_MITER_LIMIT; 150 151 alpha_source_mode = B_PIXEL_ALPHA; 152 alpha_function_mode = B_ALPHA_OVERLAY; 153 154 scale = 1.0; 155 156 font = *be_plain_font; 157 font_flags = font.Flags(); 158 font_aliasing = false; 159 160 // We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated, 161 // because we should get the clipping region from app_server. 162 // The other flags do not need to be included because the data they 163 // represent is already in sync with app_server - app_server uses the 164 // same init (default) values. 165 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 166 167 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT; 168 } 169 170 171 void 172 ViewState::UpdateServerFontState(BPrivate::PortLink &link) 173 { 174 link.StartMessage(AS_VIEW_SET_FONT_STATE); 175 link.Attach<uint16>(font_flags); 176 // always present 177 178 if (font_flags & B_FONT_FAMILY_AND_STYLE) 179 link.Attach<uint32>(font.FamilyAndStyle()); 180 181 if (font_flags & B_FONT_SIZE) 182 link.Attach<float>(font.Size()); 183 184 if (font_flags & B_FONT_SHEAR) 185 link.Attach<float>(font.Shear()); 186 187 if (font_flags & B_FONT_ROTATION) 188 link.Attach<float>(font.Rotation()); 189 190 if (font_flags & B_FONT_FALSE_BOLD_WIDTH) 191 link.Attach<float>(font.FalseBoldWidth()); 192 193 if (font_flags & B_FONT_SPACING) 194 link.Attach<uint8>(font.Spacing()); 195 196 if (font_flags & B_FONT_ENCODING) 197 link.Attach<uint8>(font.Encoding()); 198 199 if (font_flags & B_FONT_FACE) 200 link.Attach<uint16>(font.Face()); 201 202 if (font_flags & B_FONT_FLAGS) 203 link.Attach<uint32>(font.Flags()); 204 } 205 206 207 void 208 ViewState::UpdateServerState(BPrivate::PortLink &link) 209 { 210 UpdateServerFontState(link); 211 212 link.StartMessage(AS_VIEW_SET_STATE); 213 214 ViewSetStateInfo info; 215 info.penLocation = pen_location; 216 info.penSize = pen_size; 217 info.highColor = high_color; 218 info.lowColor = low_color; 219 info.pattern = pattern; 220 info.drawingMode = drawing_mode; 221 info.origin = origin; 222 info.scale = scale; 223 info.lineJoin = line_join; 224 info.lineCap = line_cap; 225 info.miterLimit = miter_limit; 226 info.alphaSourceMode = alpha_source_mode; 227 info.alphaFunctionMode = alpha_function_mode; 228 info.fontAntialiasing = font_aliasing; 229 link.Attach<ViewSetStateInfo>(info); 230 231 // we send the 'local' clipping region... if we have one... 232 // TODO: Could be optimized, but is low prio, since most views won't 233 // have a custom clipping region. 234 if (clipping_region_used) { 235 int32 count = clipping_region.CountRects(); 236 link.Attach<int32>(count); 237 for (int32 i = 0; i < count; i++) 238 link.Attach<BRect>(clipping_region.RectAt(i)); 239 } else { 240 // no clipping region 241 link.Attach<int32>(-1); 242 } 243 244 // Although we might have a 'local' clipping region, when we call 245 // BView::GetClippingRegion() we ask for the 'global' one and it 246 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag 247 248 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 249 } 250 251 252 void 253 ViewState::UpdateFrom(BPrivate::PortLink &link) 254 { 255 link.StartMessage(AS_VIEW_GET_STATE); 256 257 int32 code; 258 if (link.FlushWithReply(code) != B_OK 259 || code != B_OK) 260 return; 261 262 ViewGetStateInfo info; 263 link.Read<ViewGetStateInfo>(&info); 264 265 // set view's font state 266 font_flags = B_FONT_ALL; 267 font.SetFamilyAndStyle(info.fontID); 268 font.SetSize(info.fontSize); 269 font.SetShear(info.fontShear); 270 font.SetRotation(info.fontRotation); 271 font.SetFalseBoldWidth(info.fontFalseBoldWidth); 272 font.SetSpacing(info.fontSpacing); 273 font.SetEncoding(info.fontEncoding); 274 font.SetFace(info.fontFace); 275 font.SetFlags(info.fontFlags); 276 277 // set view's state 278 pen_location = info.viewStateInfo.penLocation; 279 pen_size = info.viewStateInfo.penSize; 280 high_color = info.viewStateInfo.highColor; 281 low_color = info.viewStateInfo.lowColor; 282 pattern = info.viewStateInfo.pattern; 283 drawing_mode = info.viewStateInfo.drawingMode; 284 origin = info.viewStateInfo.origin; 285 scale = info.viewStateInfo.scale; 286 line_join = info.viewStateInfo.lineJoin; 287 line_cap = info.viewStateInfo.lineCap; 288 miter_limit = info.viewStateInfo.miterLimit; 289 alpha_source_mode = info.viewStateInfo.alphaSourceMode; 290 alpha_function_mode = info.viewStateInfo.alphaFunctionMode; 291 font_aliasing = info.viewStateInfo.fontAntialiasing; 292 293 // read the user clipping 294 // (that's NOT the current View visible clipping but the additional 295 // user specified clipping!) 296 int32 clippingRectCount; 297 link.Read<int32>(&clippingRectCount); 298 if (clippingRectCount >= 0) { 299 clipping_region.MakeEmpty(); 300 for (int32 i = 0; i < clippingRectCount; i++) { 301 BRect rect; 302 link.Read<BRect>(&rect); 303 clipping_region.Include(rect); 304 } 305 } else { 306 // no user clipping used 307 clipping_region_used = false; 308 } 309 310 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 311 } 312 313 } // namespace BPrivate 314 315 316 // #pragma mark - 317 318 319 struct BView::LayoutData { 320 LayoutData() 321 : 322 fMinSize(), 323 fMaxSize(), 324 fPreferredSize(), 325 fAlignment(), 326 fLayoutInvalidationDisabled(0), 327 fLayout(NULL), 328 fLayoutContext(NULL), 329 fLayoutValid(true), // TODO: Rethink these initial values! 330 fMinMaxValid(true), // 331 fLayoutInProgress(false), 332 fNeedsRelayout(true) 333 { 334 } 335 336 BSize fMinSize; 337 BSize fMaxSize; 338 BSize fPreferredSize; 339 BAlignment fAlignment; 340 int fLayoutInvalidationDisabled; 341 BLayout* fLayout; 342 BLayoutContext* fLayoutContext; 343 bool fLayoutValid; 344 bool fMinMaxValid; 345 bool fLayoutInProgress; 346 bool fNeedsRelayout; 347 }; 348 349 350 BView::BView(const char* name, uint32 flags, BLayout* layout) 351 : 352 BHandler(name) 353 { 354 _InitData(BRect(0, 0, 0, 0), name, B_FOLLOW_NONE, 355 flags | B_SUPPORTS_LAYOUT); 356 SetLayout(layout); 357 } 358 359 360 BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags) 361 : 362 BHandler(name) 363 { 364 _InitData(frame, name, resizingMode, flags); 365 } 366 367 368 BView::BView(BMessage* archive) 369 : 370 BHandler(archive) 371 { 372 BRect frame; 373 archive->FindRect("_frame", &frame); 374 375 uint32 resizingMode; 376 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK) 377 resizingMode = 0; 378 379 uint32 flags; 380 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK) 381 flags = 0; 382 383 _InitData(frame, Name(), resizingMode, flags); 384 385 font_family family; 386 font_style style; 387 if (archive->FindString("_fname", 0, (const char**)&family) == B_OK 388 && archive->FindString("_fname", 1, (const char**)&style) == B_OK) { 389 BFont font; 390 font.SetFamilyAndStyle(family, style); 391 392 float size; 393 if (archive->FindFloat("_fflt", 0, &size) == B_OK) 394 font.SetSize(size); 395 396 float shear; 397 if (archive->FindFloat("_fflt", 1, &shear) == B_OK 398 && shear >= 45.0 && shear <= 135.0) 399 font.SetShear(shear); 400 401 float rotation; 402 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK 403 && rotation >=0 && rotation <= 360) 404 font.SetRotation(rotation); 405 406 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE 407 | B_FONT_SHEAR | B_FONT_ROTATION); 408 } 409 410 int32 color; 411 if (archive->FindInt32("_color", 0, &color) == B_OK) 412 SetHighColor(get_rgb_color(color)); 413 if (archive->FindInt32("_color", 1, &color) == B_OK) 414 SetLowColor(get_rgb_color(color)); 415 if (archive->FindInt32("_color", 2, &color) == B_OK) 416 SetViewColor(get_rgb_color(color)); 417 418 uint32 evMask; 419 uint32 options; 420 if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK 421 && archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK) 422 SetEventMask(evMask, options); 423 424 BPoint origin; 425 if (archive->FindPoint("_origin", &origin) == B_OK) 426 SetOrigin(origin); 427 428 float penSize; 429 if (archive->FindFloat("_psize", &penSize) == B_OK) 430 SetPenSize(penSize); 431 432 BPoint penLocation; 433 if (archive->FindPoint("_ploc", &penLocation) == B_OK) 434 MovePenTo(penLocation); 435 436 int16 lineCap; 437 int16 lineJoin; 438 float lineMiter; 439 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK 440 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK 441 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK) 442 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter); 443 444 int16 alphaBlend; 445 int16 modeBlend; 446 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK 447 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK) 448 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend); 449 450 uint32 drawingMode; 451 if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK) 452 SetDrawingMode((drawing_mode)drawingMode); 453 454 BMessage msg; 455 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK; i++) { 456 BArchivable* object = instantiate_object(&msg); 457 if (BView* child = dynamic_cast<BView*>(object)) 458 AddChild(child); 459 } 460 } 461 462 463 BArchivable* 464 BView::Instantiate(BMessage* data) 465 { 466 if (!validate_instantiation(data , "BView")) 467 return NULL; 468 469 return new(std::nothrow) BView(data); 470 } 471 472 473 status_t 474 BView::Archive(BMessage* data, bool deep) const 475 { 476 status_t ret = BHandler::Archive(data, deep); 477 if (ret != B_OK) 478 return ret; 479 480 if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0) 481 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset)); 482 483 if (ret == B_OK) 484 ret = data->AddInt32("_resize_mode", ResizingMode()); 485 486 if (ret == B_OK) 487 ret = data->AddInt32("_flags", Flags()); 488 489 if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) { 490 ret = data->AddInt32("_evmask", fEventMask); 491 if (ret == B_OK) 492 ret = data->AddInt32("_evmask", fEventOptions); 493 } 494 495 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) { 496 BFont font; 497 GetFont(&font); 498 499 font_family family; 500 font_style style; 501 font.GetFamilyAndStyle(&family, &style); 502 ret = data->AddString("_fname", family); 503 if (ret == B_OK) 504 ret = data->AddString("_fname", style); 505 if (ret == B_OK) 506 ret = data->AddFloat("_fflt", font.Size()); 507 if (ret == B_OK) 508 ret = data->AddFloat("_fflt", font.Shear()); 509 if (ret == B_OK) 510 ret = data->AddFloat("_fflt", font.Rotation()); 511 } 512 513 // colors 514 if (ret == B_OK) 515 ret = data->AddInt32("_color", get_uint32_color(HighColor())); 516 if (ret == B_OK) 517 ret = data->AddInt32("_color", get_uint32_color(LowColor())); 518 if (ret == B_OK) 519 ret = data->AddInt32("_color", get_uint32_color(ViewColor())); 520 521 // NOTE: we do not use this flag any more 522 // if ( 1 ){ 523 // ret = data->AddInt32("_dbuf", 1); 524 // } 525 526 if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0) 527 ret = data->AddPoint("_origin", Origin()); 528 529 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0) 530 ret = data->AddFloat("_psize", PenSize()); 531 532 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0) 533 ret = data->AddPoint("_ploc", PenLocation()); 534 535 if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) { 536 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode()); 537 if (ret == B_OK) 538 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode()); 539 if (ret == B_OK) 540 ret = data->AddFloat("_lmmiter", LineMiterLimit()); 541 } 542 543 if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) { 544 source_alpha alphaSourceMode; 545 alpha_function alphaFunctionMode; 546 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode); 547 548 ret = data->AddInt16("_blend", (int16)alphaSourceMode); 549 if (ret == B_OK) 550 ret = data->AddInt16("_blend", (int16)alphaFunctionMode); 551 } 552 553 if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0) 554 ret = data->AddInt32("_dmod", DrawingMode()); 555 556 if (deep) { 557 int32 i = 0; 558 BView* child; 559 560 while (ret == B_OK && (child = ChildAt(i++)) != NULL) { 561 BMessage childArchive; 562 563 ret = child->Archive(&childArchive, deep); 564 if (ret == B_OK) 565 ret = data->AddMessage("_views", &childArchive); 566 } 567 } 568 569 return ret; 570 } 571 572 573 BView::~BView() 574 { 575 STRACE(("BView(%s)::~BView()\n", this->Name())); 576 577 if (fOwner) { 578 debugger("Trying to delete a view that belongs to a window. " 579 "Call RemoveSelf first."); 580 } 581 582 RemoveSelf(); 583 584 if (fToolTip != NULL) 585 fToolTip->ReleaseReference(); 586 587 // TODO: see about BShelf! must I delete it here? is it deleted by 588 // the window? 589 590 // we also delete all our children 591 592 BView* child = fFirstChild; 593 while (child) { 594 BView* nextChild = child->fNextSibling; 595 596 delete child; 597 child = nextChild; 598 } 599 600 // delete the layout and the layout data 601 delete fLayoutData->fLayout; 602 delete fLayoutData; 603 604 if (fVerScroller) 605 fVerScroller->SetTarget((BView*)NULL); 606 if (fHorScroller) 607 fHorScroller->SetTarget((BView*)NULL); 608 609 SetName(NULL); 610 611 _RemoveCommArray(); 612 delete fState; 613 } 614 615 616 BRect 617 BView::Bounds() const 618 { 619 _CheckLock(); 620 621 if (fIsPrinting) 622 return fState->print_rect; 623 624 return fBounds; 625 } 626 627 628 void 629 BView::_ConvertToParent(BPoint* point, bool checkLock) const 630 { 631 if (!fParent) 632 return; 633 634 if (checkLock) 635 _CheckLock(); 636 637 // - our scrolling offset 638 // + our bounds location within the parent 639 point->x += -fBounds.left + fParentOffset.x; 640 point->y += -fBounds.top + fParentOffset.y; 641 } 642 643 644 void 645 BView::ConvertToParent(BPoint* point) const 646 { 647 _ConvertToParent(point, true); 648 } 649 650 651 BPoint 652 BView::ConvertToParent(BPoint point) const 653 { 654 ConvertToParent(&point); 655 656 return point; 657 } 658 659 660 void 661 BView::_ConvertFromParent(BPoint* point, bool checkLock) const 662 { 663 if (!fParent) 664 return; 665 666 if (checkLock) 667 _CheckLock(); 668 669 // - our bounds location within the parent 670 // + our scrolling offset 671 point->x += -fParentOffset.x + fBounds.left; 672 point->y += -fParentOffset.y + fBounds.top; 673 } 674 675 676 void 677 BView::ConvertFromParent(BPoint* point) const 678 { 679 _ConvertFromParent(point, true); 680 } 681 682 683 BPoint 684 BView::ConvertFromParent(BPoint point) const 685 { 686 ConvertFromParent(&point); 687 688 return point; 689 } 690 691 692 void 693 BView::ConvertToParent(BRect* rect) const 694 { 695 if (!fParent) 696 return; 697 698 _CheckLock(); 699 700 // - our scrolling offset 701 // + our bounds location within the parent 702 rect->OffsetBy(-fBounds.left + fParentOffset.x, 703 -fBounds.top + fParentOffset.y); 704 } 705 706 707 BRect 708 BView::ConvertToParent(BRect rect) const 709 { 710 ConvertToParent(&rect); 711 712 return rect; 713 } 714 715 716 void 717 BView::ConvertFromParent(BRect* rect) const 718 { 719 if (!fParent) 720 return; 721 722 _CheckLock(); 723 724 // - our bounds location within the parent 725 // + our scrolling offset 726 rect->OffsetBy(-fParentOffset.x + fBounds.left, 727 -fParentOffset.y + fBounds.top); 728 } 729 730 731 BRect 732 BView::ConvertFromParent(BRect rect) const 733 { 734 ConvertFromParent(&rect); 735 736 return rect; 737 } 738 739 740 void 741 BView::_ConvertToScreen(BPoint* pt, bool checkLock) const 742 { 743 if (!fParent) { 744 if (fOwner) 745 fOwner->ConvertToScreen(pt); 746 747 return; 748 } 749 750 if (checkLock) 751 _CheckOwnerLock(); 752 753 _ConvertToParent(pt, false); 754 fParent->_ConvertToScreen(pt, false); 755 } 756 757 758 void 759 BView::ConvertToScreen(BPoint* pt) const 760 { 761 _ConvertToScreen(pt, true); 762 } 763 764 765 BPoint 766 BView::ConvertToScreen(BPoint pt) const 767 { 768 ConvertToScreen(&pt); 769 770 return pt; 771 } 772 773 774 void 775 BView::_ConvertFromScreen(BPoint* pt, bool checkLock) const 776 { 777 if (!fParent) { 778 if (fOwner) 779 fOwner->ConvertFromScreen(pt); 780 781 return; 782 } 783 784 if (checkLock) 785 _CheckOwnerLock(); 786 787 _ConvertFromParent(pt, false); 788 fParent->_ConvertFromScreen(pt, false); 789 } 790 791 792 void 793 BView::ConvertFromScreen(BPoint* pt) const 794 { 795 _ConvertFromScreen(pt, true); 796 } 797 798 799 BPoint 800 BView::ConvertFromScreen(BPoint pt) const 801 { 802 ConvertFromScreen(&pt); 803 804 return pt; 805 } 806 807 808 void 809 BView::ConvertToScreen(BRect* rect) const 810 { 811 BPoint offset(0.0, 0.0); 812 ConvertToScreen(&offset); 813 rect->OffsetBy(offset); 814 } 815 816 817 BRect 818 BView::ConvertToScreen(BRect rect) const 819 { 820 ConvertToScreen(&rect); 821 822 return rect; 823 } 824 825 826 void 827 BView::ConvertFromScreen(BRect* rect) const 828 { 829 BPoint offset(0.0, 0.0); 830 ConvertFromScreen(&offset); 831 rect->OffsetBy(offset); 832 } 833 834 835 BRect 836 BView::ConvertFromScreen(BRect rect) const 837 { 838 ConvertFromScreen(&rect); 839 840 return rect; 841 } 842 843 844 uint32 845 BView::Flags() const 846 { 847 _CheckLock(); 848 return fFlags & ~_RESIZE_MASK_; 849 } 850 851 852 void 853 BView::SetFlags(uint32 flags) 854 { 855 if (Flags() == flags) 856 return; 857 858 if (fOwner) { 859 if (flags & B_PULSE_NEEDED) { 860 _CheckLock(); 861 if (fOwner->fPulseRunner == NULL) 862 fOwner->SetPulseRate(fOwner->PulseRate()); 863 } 864 865 if (flags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 866 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) { 867 _CheckLockAndSwitchCurrent(); 868 869 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS); 870 fOwner->fLink->Attach<uint32>(flags); 871 fOwner->fLink->Flush(); 872 } 873 } 874 875 /* Some useful info: 876 fFlags is a unsigned long (32 bits) 877 * bits 1-16 are used for BView's flags 878 * bits 17-32 are used for BView' resize mask 879 * _RESIZE_MASK_ is used for that. Look into View.h to see how 880 it's defined 881 */ 882 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_); 883 884 fState->archiving_flags |= B_VIEW_FLAGS_BIT; 885 } 886 887 888 BRect 889 BView::Frame() const 890 { 891 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y); 892 } 893 894 895 void 896 BView::Hide() 897 { 898 if (fOwner && fShowLevel == 0) { 899 _CheckLockAndSwitchCurrent(); 900 fOwner->fLink->StartMessage(AS_VIEW_HIDE); 901 fOwner->fLink->Flush(); 902 } 903 fShowLevel++; 904 905 if (fShowLevel == 1 && fParent) 906 fParent->InvalidateLayout(); 907 } 908 909 910 void 911 BView::Show() 912 { 913 fShowLevel--; 914 if (fOwner && fShowLevel == 0) { 915 _CheckLockAndSwitchCurrent(); 916 fOwner->fLink->StartMessage(AS_VIEW_SHOW); 917 fOwner->fLink->Flush(); 918 } 919 920 if (fShowLevel == 0 && fParent) 921 fParent->InvalidateLayout(); 922 } 923 924 925 bool 926 BView::IsFocus() const 927 { 928 if (fOwner) { 929 _CheckLock(); 930 return fOwner->CurrentFocus() == this; 931 } else 932 return false; 933 } 934 935 936 bool 937 BView::IsHidden(const BView* lookingFrom) const 938 { 939 if (fShowLevel > 0) 940 return true; 941 942 // may we be egocentric? 943 if (lookingFrom == this) 944 return false; 945 946 // we have the same visibility state as our 947 // parent, if there is one 948 if (fParent) 949 return fParent->IsHidden(lookingFrom); 950 951 // if we're the top view, and we're interested 952 // in the "global" view, we're inheriting the 953 // state of the window's visibility 954 if (fOwner && lookingFrom == NULL) 955 return fOwner->IsHidden(); 956 957 return false; 958 } 959 960 961 bool 962 BView::IsHidden() const 963 { 964 return IsHidden(NULL); 965 } 966 967 968 bool 969 BView::IsPrinting() const 970 { 971 return fIsPrinting; 972 } 973 974 975 BPoint 976 BView::LeftTop() const 977 { 978 return Bounds().LeftTop(); 979 } 980 981 982 void 983 BView::SetResizingMode(uint32 mode) 984 { 985 if (fOwner) { 986 _CheckLockAndSwitchCurrent(); 987 988 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE); 989 fOwner->fLink->Attach<uint32>(mode); 990 } 991 992 // look at SetFlags() for more info on the below line 993 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_); 994 } 995 996 997 uint32 998 BView::ResizingMode() const 999 { 1000 return fFlags & _RESIZE_MASK_; 1001 } 1002 1003 1004 void 1005 BView::SetViewCursor(const BCursor* cursor, bool sync) 1006 { 1007 if (cursor == NULL || fOwner == NULL) 1008 return; 1009 1010 _CheckLock(); 1011 1012 ViewSetViewCursorInfo info; 1013 info.cursorToken = cursor->fServerToken; 1014 info.viewToken = _get_object_token_(this); 1015 info.sync = sync; 1016 1017 BPrivate::AppServerLink link; 1018 link.StartMessage(AS_SET_VIEW_CURSOR); 1019 link.Attach<ViewSetViewCursorInfo>(info); 1020 1021 if (sync) { 1022 // Make sure the server has processed the message. 1023 int32 code; 1024 link.FlushWithReply(code); 1025 } 1026 } 1027 1028 1029 void 1030 BView::Flush() const 1031 { 1032 if (fOwner) 1033 fOwner->Flush(); 1034 } 1035 1036 1037 void 1038 BView::Sync() const 1039 { 1040 _CheckOwnerLock(); 1041 if (fOwner) 1042 fOwner->Sync(); 1043 } 1044 1045 1046 BWindow* 1047 BView::Window() const 1048 { 1049 return fOwner; 1050 } 1051 1052 1053 // #pragma mark - Hook Functions 1054 1055 1056 void 1057 BView::AttachedToWindow() 1058 { 1059 // Hook function 1060 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name())); 1061 } 1062 1063 1064 void 1065 BView::AllAttached() 1066 { 1067 // Hook function 1068 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name())); 1069 } 1070 1071 1072 void 1073 BView::DetachedFromWindow() 1074 { 1075 // Hook function 1076 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name())); 1077 } 1078 1079 1080 void 1081 BView::AllDetached() 1082 { 1083 // Hook function 1084 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name())); 1085 } 1086 1087 1088 void 1089 BView::Draw(BRect updateRect) 1090 { 1091 // Hook function 1092 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name())); 1093 } 1094 1095 1096 void 1097 BView::DrawAfterChildren(BRect r) 1098 { 1099 // Hook function 1100 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name())); 1101 } 1102 1103 1104 void 1105 BView::FrameMoved(BPoint newPosition) 1106 { 1107 // Hook function 1108 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name())); 1109 } 1110 1111 1112 void 1113 BView::FrameResized(float newWidth, float newHeight) 1114 { 1115 // Hook function 1116 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name())); 1117 } 1118 1119 1120 void 1121 BView::GetPreferredSize(float* _width, float* _height) 1122 { 1123 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name())); 1124 1125 if (_width != NULL) 1126 *_width = fBounds.Width(); 1127 if (_height != NULL) 1128 *_height = fBounds.Height(); 1129 } 1130 1131 1132 void 1133 BView::ResizeToPreferred() 1134 { 1135 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name())); 1136 1137 float width; 1138 float height; 1139 GetPreferredSize(&width, &height); 1140 1141 ResizeTo(width, height); 1142 } 1143 1144 1145 void 1146 BView::KeyDown(const char* bytes, int32 numBytes) 1147 { 1148 // Hook function 1149 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name())); 1150 1151 if (Window()) 1152 Window()->_KeyboardNavigation(); 1153 } 1154 1155 1156 void 1157 BView::KeyUp(const char* bytes, int32 numBytes) 1158 { 1159 // Hook function 1160 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name())); 1161 } 1162 1163 1164 void 1165 BView::MouseDown(BPoint where) 1166 { 1167 // Hook function 1168 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name())); 1169 } 1170 1171 1172 void 1173 BView::MouseUp(BPoint where) 1174 { 1175 // Hook function 1176 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name())); 1177 } 1178 1179 1180 void 1181 BView::MouseMoved(BPoint where, uint32 code, const BMessage* a_message) 1182 { 1183 // Hook function 1184 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name())); 1185 } 1186 1187 1188 void 1189 BView::Pulse() 1190 { 1191 // Hook function 1192 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name())); 1193 } 1194 1195 1196 void 1197 BView::TargetedByScrollView(BScrollView* scroll_view) 1198 { 1199 // Hook function 1200 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name())); 1201 } 1202 1203 1204 void 1205 BView::WindowActivated(bool state) 1206 { 1207 // Hook function 1208 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name())); 1209 } 1210 1211 1212 // #pragma mark - Input Functions 1213 1214 1215 void 1216 BView::BeginRectTracking(BRect startRect, uint32 style) 1217 { 1218 if (_CheckOwnerLockAndSwitchCurrent()) { 1219 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK); 1220 fOwner->fLink->Attach<BRect>(startRect); 1221 fOwner->fLink->Attach<uint32>(style); 1222 fOwner->fLink->Flush(); 1223 } 1224 } 1225 1226 1227 void 1228 BView::EndRectTracking() 1229 { 1230 if (_CheckOwnerLockAndSwitchCurrent()) { 1231 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK); 1232 fOwner->fLink->Flush(); 1233 } 1234 } 1235 1236 1237 void 1238 BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo) 1239 { 1240 if (!message) 1241 return; 1242 1243 _CheckOwnerLock(); 1244 1245 // calculate the offset 1246 BPoint offset; 1247 uint32 buttons; 1248 BMessage* current = fOwner->CurrentMessage(); 1249 if (!current || current->FindPoint("be:view_where", &offset) != B_OK) 1250 GetMouse(&offset, &buttons, false); 1251 offset -= dragRect.LeftTop(); 1252 1253 if (!dragRect.IsValid()) { 1254 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo); 1255 return; 1256 } 1257 1258 // TODO: that's not really what should happen - the app_server should take 1259 // the chance *NOT* to need to drag a whole bitmap around but just a frame. 1260 1261 // create a drag bitmap for the rect 1262 BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32); 1263 if (bitmap == NULL) 1264 return; 1265 1266 uint32* bits = (uint32*)bitmap->Bits(); 1267 uint32 bytesPerRow = bitmap->BytesPerRow(); 1268 uint32 width = dragRect.IntegerWidth() + 1; 1269 uint32 height = dragRect.IntegerHeight() + 1; 1270 uint32 lastRow = (height - 1) * width; 1271 1272 memset(bits, 0x00, height * bytesPerRow); 1273 1274 // top 1275 for (uint32 i = 0; i < width; i += 2) 1276 bits[i] = 0xff000000; 1277 1278 // bottom 1279 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2) 1280 bits[lastRow + i] = 0xff000000; 1281 1282 // left 1283 for (uint32 i = 0; i < lastRow; i += width * 2) 1284 bits[i] = 0xff000000; 1285 1286 // right 1287 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2) 1288 bits[width - 1 + i] = 0xff000000; 1289 1290 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo); 1291 } 1292 1293 1294 void 1295 BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset, 1296 BHandler* replyTo) 1297 { 1298 DragMessage(message, image, B_OP_COPY, offset, replyTo); 1299 } 1300 1301 1302 void 1303 BView::DragMessage(BMessage* message, BBitmap* image, 1304 drawing_mode dragMode, BPoint offset, BHandler* replyTo) 1305 { 1306 if (message == NULL) 1307 return; 1308 1309 if (image == NULL) { 1310 // TODO: workaround for drags without a bitmap - should not be necessary if 1311 // we move the rectangle dragging into the app_server 1312 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32); 1313 if (image == NULL) 1314 return; 1315 } 1316 1317 if (replyTo == NULL) 1318 replyTo = this; 1319 1320 if (replyTo->Looper() == NULL) 1321 debugger("DragMessage: warning - the Handler needs a looper"); 1322 1323 _CheckOwnerLock(); 1324 1325 if (!message->HasInt32("buttons")) { 1326 BMessage* msg = fOwner->CurrentMessage(); 1327 uint32 buttons; 1328 1329 if (msg == NULL 1330 || msg->FindInt32("buttons", (int32*)&buttons) != B_OK) { 1331 BPoint point; 1332 GetMouse(&point, &buttons, false); 1333 } 1334 1335 message->AddInt32("buttons", buttons); 1336 } 1337 1338 BMessage::Private privateMessage(message); 1339 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper())); 1340 1341 // TODO: create area and flatten message into that area! 1342 // send area info over port, not the actual message! 1343 int32 bufferSize = message->FlattenedSize(); 1344 char* buffer = new(std::nothrow) char[bufferSize]; 1345 if (buffer != NULL) { 1346 message->Flatten(buffer, bufferSize); 1347 1348 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE); 1349 fOwner->fLink->Attach<int32>(image->_ServerToken()); 1350 fOwner->fLink->Attach<int32>((int32)dragMode); 1351 fOwner->fLink->Attach<BPoint>(offset); 1352 fOwner->fLink->Attach<int32>(bufferSize); 1353 fOwner->fLink->Attach(buffer, bufferSize); 1354 1355 // we need to wait for the server 1356 // to actually process this message 1357 // before we can delete the bitmap 1358 int32 code; 1359 fOwner->fLink->FlushWithReply(code); 1360 1361 delete [] buffer; 1362 } else { 1363 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag " 1364 "message\n"); 1365 } 1366 1367 delete image; 1368 } 1369 1370 1371 void 1372 BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue) 1373 { 1374 if (_location == NULL && _buttons == NULL) 1375 return; 1376 1377 _CheckOwnerLockAndSwitchCurrent(); 1378 1379 uint32 eventOptions = fEventOptions | fMouseEventOptions; 1380 bool noHistory = eventOptions & B_NO_POINTER_HISTORY; 1381 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY; 1382 1383 if (checkMessageQueue && !noHistory) { 1384 Window()->UpdateIfNeeded(); 1385 BMessageQueue* queue = Window()->MessageQueue(); 1386 queue->Lock(); 1387 1388 // Look out for mouse update messages 1389 1390 BMessage* message; 1391 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) { 1392 switch (message->what) { 1393 case B_MOUSE_MOVED: 1394 case B_MOUSE_UP: 1395 case B_MOUSE_DOWN: 1396 bool deleteMessage; 1397 if (!Window()->_StealMouseMessage(message, deleteMessage)) 1398 continue; 1399 1400 if (!fullHistory && message->what == B_MOUSE_MOVED) { 1401 // Check if the message is too old. Some applications 1402 // check the message queue in such a way that mouse 1403 // messages *must* pile up. This check makes them work 1404 // as intended, although these applications could simply 1405 // use the version of BView::GetMouse() that does not 1406 // check the history. Also note that it isn't a problem 1407 // to delete the message in case there is not a newer 1408 // one. If we don't find a message in the queue, we will 1409 // just fall back to asking the app_sever directly. So 1410 // the imposed delay will not be a problem on slower 1411 // computers. This check also prevents another problem, 1412 // when the message that we use is *not* removed from 1413 // the queue. Subsequent calls to GetMouse() would find 1414 // this message over and over! 1415 bigtime_t eventTime; 1416 if (message->FindInt64("when", &eventTime) == B_OK 1417 && system_time() - eventTime > 10000) { 1418 // just discard the message 1419 if (deleteMessage) 1420 delete message; 1421 continue; 1422 } 1423 } 1424 message->FindPoint("screen_where", _location); 1425 message->FindInt32("buttons", (int32*)_buttons); 1426 queue->Unlock(); 1427 // we need to hold the queue lock until here, because 1428 // the message might still be used for something else 1429 1430 if (_location != NULL) 1431 ConvertFromScreen(_location); 1432 1433 if (deleteMessage) 1434 delete message; 1435 1436 return; 1437 } 1438 } 1439 queue->Unlock(); 1440 } 1441 1442 // If no mouse update message has been found in the message queue, 1443 // we get the current mouse location and buttons from the app_server 1444 1445 fOwner->fLink->StartMessage(AS_GET_MOUSE); 1446 1447 int32 code; 1448 if (fOwner->fLink->FlushWithReply(code) == B_OK 1449 && code == B_OK) { 1450 BPoint location; 1451 uint32 buttons; 1452 fOwner->fLink->Read<BPoint>(&location); 1453 fOwner->fLink->Read<uint32>(&buttons); 1454 // TODO: ServerWindow replies with an int32 here 1455 1456 ConvertFromScreen(&location); 1457 // TODO: in beos R5, location is already converted to the view 1458 // local coordinate system, so if an app checks the window message 1459 // queue by itself, it might not find what it expects. 1460 // NOTE: the fact that we have mouse coords in screen space in our 1461 // queue avoids the problem that messages already in the queue will 1462 // be outdated as soon as a window or even the view moves. The 1463 // second situation being quite common actually, also with regards 1464 // to scrolling. An app reading these messages would have to know 1465 // the locations of the window and view for each message... 1466 // otherwise it is potentially broken anyways. 1467 if (_location != NULL) 1468 *_location = location; 1469 if (_buttons != NULL) 1470 *_buttons = buttons; 1471 } else { 1472 if (_location != NULL) 1473 _location->Set(0, 0); 1474 if (_buttons != NULL) 1475 *_buttons = 0; 1476 } 1477 } 1478 1479 1480 void 1481 BView::MakeFocus(bool focusState) 1482 { 1483 if (fOwner) { 1484 // TODO: If this view has focus and focusState==false, 1485 // will there really be no other view with focus? No 1486 // cycling to the next one? 1487 BView* focus = fOwner->CurrentFocus(); 1488 if (focusState) { 1489 // Unfocus a previous focus view 1490 if (focus && focus != this) 1491 focus->MakeFocus(false); 1492 // if we want to make this view the current focus view 1493 fOwner->_SetFocus(this, true); 1494 } else { 1495 // we want to unfocus this view, but only if it actually has focus 1496 if (focus == this) { 1497 fOwner->_SetFocus(NULL, true); 1498 } 1499 } 1500 } 1501 } 1502 1503 1504 BScrollBar* 1505 BView::ScrollBar(orientation posture) const 1506 { 1507 switch (posture) { 1508 case B_VERTICAL: 1509 return fVerScroller; 1510 1511 case B_HORIZONTAL: 1512 return fHorScroller; 1513 1514 default: 1515 return NULL; 1516 } 1517 } 1518 1519 1520 void 1521 BView::ScrollBy(float deltaX, float deltaY) 1522 { 1523 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY)); 1524 } 1525 1526 1527 void 1528 BView::ScrollTo(BPoint where) 1529 { 1530 // scrolling by fractional values is not supported 1531 where.x = roundf(where.x); 1532 where.y = roundf(where.y); 1533 1534 // no reason to process this further if no scroll is intended. 1535 if (where.x == fBounds.left && where.y == fBounds.top) 1536 return; 1537 1538 // make sure scrolling is within valid bounds 1539 if (fHorScroller) { 1540 float min, max; 1541 fHorScroller->GetRange(&min, &max); 1542 1543 if (where.x < min) 1544 where.x = min; 1545 else if (where.x > max) 1546 where.x = max; 1547 } 1548 if (fVerScroller) { 1549 float min, max; 1550 fVerScroller->GetRange(&min, &max); 1551 1552 if (where.y < min) 1553 where.y = min; 1554 else if (where.y > max) 1555 where.y = max; 1556 } 1557 1558 _CheckLockAndSwitchCurrent(); 1559 1560 float xDiff = where.x - fBounds.left; 1561 float yDiff = where.y - fBounds.top; 1562 1563 // if we're attached to a window tell app_server about this change 1564 if (fOwner) { 1565 fOwner->fLink->StartMessage(AS_VIEW_SCROLL); 1566 fOwner->fLink->Attach<float>(xDiff); 1567 fOwner->fLink->Attach<float>(yDiff); 1568 1569 fOwner->fLink->Flush(); 1570 1571 // fState->valid_flags &= ~B_VIEW_FRAME_BIT; 1572 } 1573 1574 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver. 1575 fBounds.OffsetTo(where.x, where.y); 1576 1577 // then set the new values of the scrollbars 1578 if (fHorScroller && xDiff != 0.0) 1579 fHorScroller->SetValue(fBounds.left); 1580 if (fVerScroller && yDiff != 0.0) 1581 fVerScroller->SetValue(fBounds.top); 1582 1583 } 1584 1585 1586 status_t 1587 BView::SetEventMask(uint32 mask, uint32 options) 1588 { 1589 if (fEventMask == mask && fEventOptions == options) 1590 return B_OK; 1591 1592 // don't change the mask if it's zero and we've got options 1593 if (mask != 0 || options == 0) 1594 fEventMask = mask | (fEventMask & 0xffff0000); 1595 fEventOptions = options; 1596 1597 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT; 1598 1599 if (fOwner) { 1600 _CheckLockAndSwitchCurrent(); 1601 1602 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK); 1603 fOwner->fLink->Attach<uint32>(mask); 1604 fOwner->fLink->Attach<uint32>(options); 1605 fOwner->fLink->Flush(); 1606 } 1607 1608 return B_OK; 1609 } 1610 1611 1612 uint32 1613 BView::EventMask() 1614 { 1615 return fEventMask; 1616 } 1617 1618 1619 status_t 1620 BView::SetMouseEventMask(uint32 mask, uint32 options) 1621 { 1622 // Just don't do anything if the view is not yet attached 1623 // or we were called outside of BView::MouseDown() 1624 if (fOwner != NULL 1625 && fOwner->CurrentMessage() != NULL 1626 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) { 1627 _CheckLockAndSwitchCurrent(); 1628 fMouseEventOptions = options; 1629 1630 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK); 1631 fOwner->fLink->Attach<uint32>(mask); 1632 fOwner->fLink->Attach<uint32>(options); 1633 fOwner->fLink->Flush(); 1634 return B_OK; 1635 } 1636 1637 return B_ERROR; 1638 } 1639 1640 1641 // #pragma mark - Graphic State Functions 1642 1643 1644 void 1645 BView::PushState() 1646 { 1647 _CheckOwnerLockAndSwitchCurrent(); 1648 1649 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE); 1650 1651 // initialize origin and scale 1652 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT; 1653 fState->scale = 1.0f; 1654 fState->origin.Set(0, 0); 1655 } 1656 1657 1658 void 1659 BView::PopState() 1660 { 1661 _CheckOwnerLockAndSwitchCurrent(); 1662 1663 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE); 1664 _FlushIfNotInTransaction(); 1665 1666 // invalidate all flags (except those that are not part of pop/push) 1667 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT; 1668 } 1669 1670 1671 void 1672 BView::SetOrigin(BPoint pt) 1673 { 1674 SetOrigin(pt.x, pt.y); 1675 } 1676 1677 1678 void 1679 BView::SetOrigin(float x, float y) 1680 { 1681 if (fState->IsValid(B_VIEW_ORIGIN_BIT) 1682 && x == fState->origin.x && y == fState->origin.y) 1683 return; 1684 1685 fState->origin.x = x; 1686 fState->origin.y = y; 1687 1688 if (_CheckOwnerLockAndSwitchCurrent()) { 1689 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN); 1690 fOwner->fLink->Attach<float>(x); 1691 fOwner->fLink->Attach<float>(y); 1692 1693 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1694 } 1695 1696 // our local coord system origin has changed, so when archiving we'll add 1697 // this too 1698 fState->archiving_flags |= B_VIEW_ORIGIN_BIT; 1699 } 1700 1701 1702 BPoint 1703 BView::Origin() const 1704 { 1705 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) { 1706 // we don't keep graphics state information, therefor 1707 // we need to ask the server for the origin after PopState() 1708 _CheckOwnerLockAndSwitchCurrent(); 1709 1710 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN); 1711 1712 int32 code; 1713 if (fOwner->fLink->FlushWithReply(code) == B_OK 1714 && code == B_OK) { 1715 fOwner->fLink->Read<BPoint>(&fState->origin); 1716 1717 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1718 } 1719 } 1720 1721 return fState->origin; 1722 } 1723 1724 1725 void 1726 BView::SetScale(float scale) const 1727 { 1728 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale) 1729 return; 1730 1731 if (fOwner) { 1732 _CheckLockAndSwitchCurrent(); 1733 1734 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE); 1735 fOwner->fLink->Attach<float>(scale); 1736 1737 fState->valid_flags |= B_VIEW_SCALE_BIT; 1738 } 1739 1740 fState->scale = scale; 1741 fState->archiving_flags |= B_VIEW_SCALE_BIT; 1742 } 1743 1744 1745 float 1746 BView::Scale() const 1747 { 1748 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) { 1749 _CheckLockAndSwitchCurrent(); 1750 1751 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE); 1752 1753 int32 code; 1754 if (fOwner->fLink->FlushWithReply(code) == B_OK 1755 && code == B_OK) 1756 fOwner->fLink->Read<float>(&fState->scale); 1757 1758 fState->valid_flags |= B_VIEW_SCALE_BIT; 1759 } 1760 1761 return fState->scale; 1762 } 1763 1764 1765 void 1766 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) 1767 { 1768 if (fState->IsValid(B_VIEW_LINE_MODES_BIT) 1769 && lineCap == fState->line_cap && lineJoin == fState->line_join 1770 && miterLimit == fState->miter_limit) 1771 return; 1772 1773 if (fOwner) { 1774 _CheckLockAndSwitchCurrent(); 1775 1776 ViewSetLineModeInfo info; 1777 info.lineJoin = lineJoin; 1778 info.lineCap = lineCap; 1779 info.miterLimit = miterLimit; 1780 1781 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE); 1782 fOwner->fLink->Attach<ViewSetLineModeInfo>(info); 1783 1784 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1785 } 1786 1787 fState->line_cap = lineCap; 1788 fState->line_join = lineJoin; 1789 fState->miter_limit = miterLimit; 1790 1791 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT; 1792 } 1793 1794 1795 join_mode 1796 BView::LineJoinMode() const 1797 { 1798 // This will update the current state, if necessary 1799 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1800 LineMiterLimit(); 1801 1802 return fState->line_join; 1803 } 1804 1805 1806 cap_mode 1807 BView::LineCapMode() const 1808 { 1809 // This will update the current state, if necessary 1810 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1811 LineMiterLimit(); 1812 1813 return fState->line_cap; 1814 } 1815 1816 1817 float 1818 BView::LineMiterLimit() const 1819 { 1820 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) { 1821 _CheckLockAndSwitchCurrent(); 1822 1823 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE); 1824 1825 int32 code; 1826 if (fOwner->fLink->FlushWithReply(code) == B_OK 1827 && code == B_OK) { 1828 1829 ViewSetLineModeInfo info; 1830 fOwner->fLink->Read<ViewSetLineModeInfo>(&info); 1831 1832 fState->line_cap = info.lineCap; 1833 fState->line_join = info.lineJoin; 1834 fState->miter_limit = info.miterLimit; 1835 } 1836 1837 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1838 } 1839 1840 return fState->miter_limit; 1841 } 1842 1843 1844 void 1845 BView::SetDrawingMode(drawing_mode mode) 1846 { 1847 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT) 1848 && mode == fState->drawing_mode) 1849 return; 1850 1851 if (fOwner) { 1852 _CheckLockAndSwitchCurrent(); 1853 1854 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE); 1855 fOwner->fLink->Attach<int8>((int8)mode); 1856 1857 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1858 } 1859 1860 fState->drawing_mode = mode; 1861 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT; 1862 } 1863 1864 1865 drawing_mode 1866 BView::DrawingMode() const 1867 { 1868 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) { 1869 _CheckLockAndSwitchCurrent(); 1870 1871 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE); 1872 1873 int32 code; 1874 if (fOwner->fLink->FlushWithReply(code) == B_OK 1875 && code == B_OK) { 1876 int8 drawingMode; 1877 fOwner->fLink->Read<int8>(&drawingMode); 1878 1879 fState->drawing_mode = (drawing_mode)drawingMode; 1880 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1881 } 1882 } 1883 1884 return fState->drawing_mode; 1885 } 1886 1887 1888 void 1889 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction) 1890 { 1891 if (fState->IsValid(B_VIEW_BLENDING_BIT) 1892 && sourceAlpha == fState->alpha_source_mode 1893 && alphaFunction == fState->alpha_function_mode) 1894 return; 1895 1896 if (fOwner) { 1897 _CheckLockAndSwitchCurrent(); 1898 1899 ViewBlendingModeInfo info; 1900 info.sourceAlpha = sourceAlpha; 1901 info.alphaFunction = alphaFunction; 1902 1903 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE); 1904 fOwner->fLink->Attach<ViewBlendingModeInfo>(info); 1905 1906 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1907 } 1908 1909 fState->alpha_source_mode = sourceAlpha; 1910 fState->alpha_function_mode = alphaFunction; 1911 1912 fState->archiving_flags |= B_VIEW_BLENDING_BIT; 1913 } 1914 1915 1916 void 1917 BView::GetBlendingMode(source_alpha* _sourceAlpha, 1918 alpha_function* _alphaFunction) const 1919 { 1920 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) { 1921 _CheckLockAndSwitchCurrent(); 1922 1923 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE); 1924 1925 int32 code; 1926 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 1927 ViewBlendingModeInfo info; 1928 fOwner->fLink->Read<ViewBlendingModeInfo>(&info); 1929 1930 fState->alpha_source_mode = info.sourceAlpha; 1931 fState->alpha_function_mode = info.alphaFunction; 1932 1933 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1934 } 1935 } 1936 1937 if (_sourceAlpha) 1938 *_sourceAlpha = fState->alpha_source_mode; 1939 1940 if (_alphaFunction) 1941 *_alphaFunction = fState->alpha_function_mode; 1942 } 1943 1944 1945 void 1946 BView::MovePenTo(BPoint point) 1947 { 1948 MovePenTo(point.x, point.y); 1949 } 1950 1951 1952 void 1953 BView::MovePenTo(float x, float y) 1954 { 1955 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT) 1956 && x == fState->pen_location.x && y == fState->pen_location.y) 1957 return; 1958 1959 if (fOwner) { 1960 _CheckLockAndSwitchCurrent(); 1961 1962 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC); 1963 fOwner->fLink->Attach<BPoint>(BPoint(x, y)); 1964 1965 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 1966 } 1967 1968 fState->pen_location.x = x; 1969 fState->pen_location.y = y; 1970 1971 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT; 1972 } 1973 1974 1975 void 1976 BView::MovePenBy(float x, float y) 1977 { 1978 // this will update the pen location if necessary 1979 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT)) 1980 PenLocation(); 1981 1982 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y); 1983 } 1984 1985 1986 BPoint 1987 BView::PenLocation() const 1988 { 1989 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) { 1990 _CheckLockAndSwitchCurrent(); 1991 1992 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC); 1993 1994 int32 code; 1995 if (fOwner->fLink->FlushWithReply(code) == B_OK 1996 && code == B_OK) { 1997 fOwner->fLink->Read<BPoint>(&fState->pen_location); 1998 1999 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 2000 } 2001 } 2002 2003 return fState->pen_location; 2004 } 2005 2006 2007 void 2008 BView::SetPenSize(float size) 2009 { 2010 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size) 2011 return; 2012 2013 if (fOwner) { 2014 _CheckLockAndSwitchCurrent(); 2015 2016 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE); 2017 fOwner->fLink->Attach<float>(size); 2018 2019 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2020 } 2021 2022 fState->pen_size = size; 2023 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT; 2024 } 2025 2026 2027 float 2028 BView::PenSize() const 2029 { 2030 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) { 2031 _CheckLockAndSwitchCurrent(); 2032 2033 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE); 2034 2035 int32 code; 2036 if (fOwner->fLink->FlushWithReply(code) == B_OK 2037 && code == B_OK) { 2038 fOwner->fLink->Read<float>(&fState->pen_size); 2039 2040 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2041 } 2042 } 2043 2044 return fState->pen_size; 2045 } 2046 2047 2048 void 2049 BView::SetHighColor(rgb_color color) 2050 { 2051 // are we up-to-date already? 2052 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT) 2053 && fState->high_color == color) 2054 return; 2055 2056 if (fOwner) { 2057 _CheckLockAndSwitchCurrent(); 2058 2059 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR); 2060 fOwner->fLink->Attach<rgb_color>(color); 2061 2062 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2063 } 2064 2065 fState->high_color = color; 2066 2067 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT; 2068 } 2069 2070 2071 rgb_color 2072 BView::HighColor() const 2073 { 2074 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) { 2075 _CheckLockAndSwitchCurrent(); 2076 2077 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR); 2078 2079 int32 code; 2080 if (fOwner->fLink->FlushWithReply(code) == B_OK 2081 && code == B_OK) { 2082 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2083 2084 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2085 } 2086 } 2087 2088 return fState->high_color; 2089 } 2090 2091 2092 void 2093 BView::SetLowColor(rgb_color color) 2094 { 2095 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT) 2096 && fState->low_color == color) 2097 return; 2098 2099 if (fOwner) { 2100 _CheckLockAndSwitchCurrent(); 2101 2102 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR); 2103 fOwner->fLink->Attach<rgb_color>(color); 2104 2105 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2106 } 2107 2108 fState->low_color = color; 2109 2110 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT; 2111 } 2112 2113 2114 rgb_color 2115 BView::LowColor() const 2116 { 2117 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) { 2118 _CheckLockAndSwitchCurrent(); 2119 2120 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR); 2121 2122 int32 code; 2123 if (fOwner->fLink->FlushWithReply(code) == B_OK 2124 && code == B_OK) { 2125 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2126 2127 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2128 } 2129 } 2130 2131 return fState->low_color; 2132 } 2133 2134 2135 void 2136 BView::SetViewColor(rgb_color color) 2137 { 2138 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color) 2139 return; 2140 2141 if (fOwner) { 2142 _CheckLockAndSwitchCurrent(); 2143 2144 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR); 2145 fOwner->fLink->Attach<rgb_color>(color); 2146 fOwner->fLink->Flush(); 2147 2148 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2149 } 2150 2151 fState->view_color = color; 2152 2153 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT; 2154 } 2155 2156 2157 rgb_color 2158 BView::ViewColor() const 2159 { 2160 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) { 2161 _CheckLockAndSwitchCurrent(); 2162 2163 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR); 2164 2165 int32 code; 2166 if (fOwner->fLink->FlushWithReply(code) == B_OK 2167 && code == B_OK) { 2168 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2169 2170 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2171 } 2172 } 2173 2174 return fState->view_color; 2175 } 2176 2177 2178 void 2179 BView::ForceFontAliasing(bool enable) 2180 { 2181 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) 2182 && enable == fState->font_aliasing) 2183 return; 2184 2185 if (fOwner) { 2186 _CheckLockAndSwitchCurrent(); 2187 2188 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING); 2189 fOwner->fLink->Attach<bool>(enable); 2190 2191 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT; 2192 } 2193 2194 fState->font_aliasing = enable; 2195 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT; 2196 } 2197 2198 2199 void 2200 BView::SetFont(const BFont* font, uint32 mask) 2201 { 2202 if (!font || mask == 0) 2203 return; 2204 2205 if (mask == B_FONT_ALL) { 2206 fState->font = *font; 2207 } else { 2208 // TODO: move this into a BFont method 2209 if (mask & B_FONT_FAMILY_AND_STYLE) 2210 fState->font.SetFamilyAndStyle(font->FamilyAndStyle()); 2211 2212 if (mask & B_FONT_SIZE) 2213 fState->font.SetSize(font->Size()); 2214 2215 if (mask & B_FONT_SHEAR) 2216 fState->font.SetShear(font->Shear()); 2217 2218 if (mask & B_FONT_ROTATION) 2219 fState->font.SetRotation(font->Rotation()); 2220 2221 if (mask & B_FONT_FALSE_BOLD_WIDTH) 2222 fState->font.SetFalseBoldWidth(font->FalseBoldWidth()); 2223 2224 if (mask & B_FONT_SPACING) 2225 fState->font.SetSpacing(font->Spacing()); 2226 2227 if (mask & B_FONT_ENCODING) 2228 fState->font.SetEncoding(font->Encoding()); 2229 2230 if (mask & B_FONT_FACE) 2231 fState->font.SetFace(font->Face()); 2232 2233 if (mask & B_FONT_FLAGS) 2234 fState->font.SetFlags(font->Flags()); 2235 } 2236 2237 fState->font_flags |= mask; 2238 2239 if (fOwner) { 2240 _CheckLockAndSwitchCurrent(); 2241 2242 fState->UpdateServerFontState(*fOwner->fLink); 2243 fState->valid_flags |= B_VIEW_FONT_BIT; 2244 } 2245 2246 fState->archiving_flags |= B_VIEW_FONT_BIT; 2247 // TODO: InvalidateLayout() here for convenience? 2248 } 2249 2250 2251 void 2252 BView::GetFont(BFont* font) const 2253 { 2254 if (!fState->IsValid(B_VIEW_FONT_BIT)) { 2255 // we don't keep graphics state information, therefor 2256 // we need to ask the server for the origin after PopState() 2257 _CheckOwnerLockAndSwitchCurrent(); 2258 2259 // TODO: add a font getter! 2260 fState->UpdateFrom(*fOwner->fLink); 2261 } 2262 2263 *font = fState->font; 2264 } 2265 2266 2267 void 2268 BView::GetFontHeight(font_height* height) const 2269 { 2270 fState->font.GetHeight(height); 2271 } 2272 2273 2274 void 2275 BView::SetFontSize(float size) 2276 { 2277 BFont font; 2278 font.SetSize(size); 2279 2280 SetFont(&font, B_FONT_SIZE); 2281 } 2282 2283 2284 float 2285 BView::StringWidth(const char* string) const 2286 { 2287 return fState->font.StringWidth(string); 2288 } 2289 2290 2291 float 2292 BView::StringWidth(const char* string, int32 length) const 2293 { 2294 return fState->font.StringWidth(string, length); 2295 } 2296 2297 2298 void 2299 BView::GetStringWidths(char* stringArray[], int32 lengthArray[], 2300 int32 numStrings, float widthArray[]) const 2301 { 2302 fState->font.GetStringWidths(const_cast<const char**>(stringArray), 2303 const_cast<const int32*>(lengthArray), numStrings, widthArray); 2304 } 2305 2306 2307 void 2308 BView::TruncateString(BString* string, uint32 mode, float width) const 2309 { 2310 fState->font.TruncateString(string, mode, width); 2311 } 2312 2313 2314 void 2315 BView::ClipToPicture(BPicture* picture, BPoint where, bool sync) 2316 { 2317 _ClipToPicture(picture, where, false, sync); 2318 } 2319 2320 2321 void 2322 BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync) 2323 { 2324 _ClipToPicture(picture, where, true, sync); 2325 } 2326 2327 2328 void 2329 BView::GetClippingRegion(BRegion* region) const 2330 { 2331 if (!region) 2332 return; 2333 2334 // NOTE: the client has no idea when the clipping in the server 2335 // changed, so it is always read from the server 2336 region->MakeEmpty(); 2337 2338 2339 if (fOwner) { 2340 if (fIsPrinting && _CheckOwnerLock()) { 2341 region->Set(fState->print_rect); 2342 return; 2343 } 2344 2345 _CheckLockAndSwitchCurrent(); 2346 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION); 2347 2348 int32 code; 2349 if (fOwner->fLink->FlushWithReply(code) == B_OK 2350 && code == B_OK) { 2351 fOwner->fLink->ReadRegion(region); 2352 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT; 2353 } 2354 } 2355 } 2356 2357 2358 void 2359 BView::ConstrainClippingRegion(BRegion* region) 2360 { 2361 if (_CheckOwnerLockAndSwitchCurrent()) { 2362 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION); 2363 2364 if (region) { 2365 int32 count = region->CountRects(); 2366 fOwner->fLink->Attach<int32>(count); 2367 if (count > 0) 2368 fOwner->fLink->AttachRegion(*region); 2369 } else { 2370 fOwner->fLink->Attach<int32>(-1); 2371 // '-1' means that in the app_server, there won't be any 'local' 2372 // clipping region (it will be NULL) 2373 } 2374 2375 _FlushIfNotInTransaction(); 2376 2377 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 2378 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 2379 } 2380 } 2381 2382 2383 // #pragma mark - Drawing Functions 2384 2385 2386 void 2387 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 2388 uint32 options) 2389 { 2390 if (bitmap == NULL || fOwner == NULL 2391 || !bitmapRect.IsValid() || !viewRect.IsValid()) 2392 return; 2393 2394 _CheckLockAndSwitchCurrent(); 2395 2396 ViewDrawBitmapInfo info; 2397 info.bitmapToken = bitmap->_ServerToken(); 2398 info.options = options; 2399 info.viewRect = viewRect; 2400 info.bitmapRect = bitmapRect; 2401 2402 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 2403 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 2404 2405 _FlushIfNotInTransaction(); 2406 } 2407 2408 2409 void 2410 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 2411 { 2412 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 2413 } 2414 2415 2416 void 2417 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect) 2418 { 2419 if (bitmap && fOwner) { 2420 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), 2421 viewRect, 0); 2422 } 2423 } 2424 2425 2426 void 2427 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where) 2428 { 2429 if (bitmap == NULL || fOwner == NULL) 2430 return; 2431 2432 _CheckLockAndSwitchCurrent(); 2433 2434 ViewDrawBitmapInfo info; 2435 info.bitmapToken = bitmap->_ServerToken(); 2436 info.options = 0; 2437 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN); 2438 info.viewRect = info.bitmapRect.OffsetToCopy(where); 2439 2440 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 2441 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 2442 2443 _FlushIfNotInTransaction(); 2444 } 2445 2446 2447 void 2448 BView::DrawBitmapAsync(const BBitmap* bitmap) 2449 { 2450 DrawBitmapAsync(bitmap, PenLocation()); 2451 } 2452 2453 2454 void 2455 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 2456 uint32 options) 2457 { 2458 if (fOwner) { 2459 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options); 2460 Sync(); 2461 } 2462 } 2463 2464 2465 void 2466 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 2467 { 2468 if (fOwner) { 2469 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 2470 Sync(); 2471 } 2472 } 2473 2474 2475 void 2476 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect) 2477 { 2478 if (bitmap && fOwner) { 2479 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect, 2480 0); 2481 } 2482 } 2483 2484 2485 void 2486 BView::DrawBitmap(const BBitmap* bitmap, BPoint where) 2487 { 2488 if (fOwner) { 2489 DrawBitmapAsync(bitmap, where); 2490 Sync(); 2491 } 2492 } 2493 2494 2495 void 2496 BView::DrawBitmap(const BBitmap* bitmap) 2497 { 2498 DrawBitmap(bitmap, PenLocation()); 2499 } 2500 2501 2502 void 2503 BView::DrawChar(char c) 2504 { 2505 DrawString(&c, 1, PenLocation()); 2506 } 2507 2508 2509 void 2510 BView::DrawChar(char c, BPoint location) 2511 { 2512 DrawString(&c, 1, location); 2513 } 2514 2515 2516 void 2517 BView::DrawString(const char* string, escapement_delta* delta) 2518 { 2519 if (string == NULL) 2520 return; 2521 2522 DrawString(string, strlen(string), PenLocation(), delta); 2523 } 2524 2525 2526 void 2527 BView::DrawString(const char* string, BPoint location, escapement_delta* delta) 2528 { 2529 if (string == NULL) 2530 return; 2531 2532 DrawString(string, strlen(string), location, delta); 2533 } 2534 2535 2536 void 2537 BView::DrawString(const char* string, int32 length, escapement_delta* delta) 2538 { 2539 DrawString(string, length, PenLocation(), delta); 2540 } 2541 2542 2543 void 2544 BView::DrawString(const char* string, int32 length, BPoint location, 2545 escapement_delta* delta) 2546 { 2547 if (fOwner == NULL || string == NULL || length < 1) 2548 return; 2549 2550 _CheckLockAndSwitchCurrent(); 2551 2552 ViewDrawStringInfo info; 2553 info.stringLength = length; 2554 info.location = location; 2555 if (delta != NULL) 2556 info.delta = *delta; 2557 2558 // quite often delta will be NULL 2559 if (delta) 2560 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA); 2561 else 2562 fOwner->fLink->StartMessage(AS_DRAW_STRING); 2563 2564 fOwner->fLink->Attach<ViewDrawStringInfo>(info); 2565 fOwner->fLink->Attach(string, length); 2566 2567 _FlushIfNotInTransaction(); 2568 2569 // this modifies our pen location, so we invalidate the flag. 2570 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 2571 } 2572 2573 2574 void 2575 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, 2576 ::pattern pattern) 2577 { 2578 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, 2579 center.x + xRadius, center.y + yRadius), pattern); 2580 } 2581 2582 2583 void 2584 BView::StrokeEllipse(BRect rect, ::pattern pattern) 2585 { 2586 if (fOwner == NULL) 2587 return; 2588 2589 _CheckLockAndSwitchCurrent(); 2590 _UpdatePattern(pattern); 2591 2592 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE); 2593 fOwner->fLink->Attach<BRect>(rect); 2594 2595 _FlushIfNotInTransaction(); 2596 } 2597 2598 2599 void 2600 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2601 ::pattern pattern) 2602 { 2603 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2604 center.x + xRadius, center.y + yRadius), pattern); 2605 } 2606 2607 2608 void 2609 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2610 const BGradient& gradient) 2611 { 2612 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2613 center.x + xRadius, center.y + yRadius), gradient); 2614 } 2615 2616 2617 void 2618 BView::FillEllipse(BRect rect, ::pattern pattern) 2619 { 2620 if (fOwner == NULL) 2621 return; 2622 2623 _CheckLockAndSwitchCurrent(); 2624 _UpdatePattern(pattern); 2625 2626 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE); 2627 fOwner->fLink->Attach<BRect>(rect); 2628 2629 _FlushIfNotInTransaction(); 2630 } 2631 2632 2633 void 2634 BView::FillEllipse(BRect rect, const BGradient& gradient) 2635 { 2636 if (fOwner == NULL) 2637 return; 2638 2639 _CheckLockAndSwitchCurrent(); 2640 2641 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT); 2642 fOwner->fLink->Attach<BRect>(rect); 2643 fOwner->fLink->AttachGradient(gradient); 2644 2645 _FlushIfNotInTransaction(); 2646 } 2647 2648 2649 void 2650 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle, 2651 float arcAngle, ::pattern pattern) 2652 { 2653 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2654 center.y + yRadius), startAngle, arcAngle, pattern); 2655 } 2656 2657 2658 void 2659 BView::StrokeArc(BRect rect, float startAngle, float arcAngle, 2660 ::pattern pattern) 2661 { 2662 if (fOwner == NULL) 2663 return; 2664 2665 _CheckLockAndSwitchCurrent(); 2666 _UpdatePattern(pattern); 2667 2668 fOwner->fLink->StartMessage(AS_STROKE_ARC); 2669 fOwner->fLink->Attach<BRect>(rect); 2670 fOwner->fLink->Attach<float>(startAngle); 2671 fOwner->fLink->Attach<float>(arcAngle); 2672 2673 _FlushIfNotInTransaction(); 2674 } 2675 2676 2677 void 2678 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 2679 float arcAngle, ::pattern pattern) 2680 { 2681 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2682 center.y + yRadius), startAngle, arcAngle, pattern); 2683 } 2684 2685 2686 void 2687 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 2688 float arcAngle, const BGradient& gradient) 2689 { 2690 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2691 center.y + yRadius), startAngle, arcAngle, gradient); 2692 } 2693 2694 2695 void 2696 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2697 ::pattern pattern) 2698 { 2699 if (fOwner == NULL) 2700 return; 2701 2702 _CheckLockAndSwitchCurrent(); 2703 _UpdatePattern(pattern); 2704 2705 fOwner->fLink->StartMessage(AS_FILL_ARC); 2706 fOwner->fLink->Attach<BRect>(rect); 2707 fOwner->fLink->Attach<float>(startAngle); 2708 fOwner->fLink->Attach<float>(arcAngle); 2709 2710 _FlushIfNotInTransaction(); 2711 } 2712 2713 2714 void 2715 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2716 const BGradient& gradient) 2717 { 2718 if (fOwner == NULL) 2719 return; 2720 2721 _CheckLockAndSwitchCurrent(); 2722 2723 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT); 2724 fOwner->fLink->Attach<BRect>(rect); 2725 fOwner->fLink->Attach<float>(startAngle); 2726 fOwner->fLink->Attach<float>(arcAngle); 2727 fOwner->fLink->AttachGradient(gradient); 2728 2729 _FlushIfNotInTransaction(); 2730 } 2731 2732 2733 void 2734 BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern) 2735 { 2736 if (fOwner == NULL) 2737 return; 2738 2739 _CheckLockAndSwitchCurrent(); 2740 _UpdatePattern(pattern); 2741 2742 fOwner->fLink->StartMessage(AS_STROKE_BEZIER); 2743 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2744 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2745 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2746 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2747 2748 _FlushIfNotInTransaction(); 2749 } 2750 2751 2752 void 2753 BView::FillBezier(BPoint* controlPoints, ::pattern pattern) 2754 { 2755 if (fOwner == NULL) 2756 return; 2757 2758 _CheckLockAndSwitchCurrent(); 2759 _UpdatePattern(pattern); 2760 2761 fOwner->fLink->StartMessage(AS_FILL_BEZIER); 2762 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2763 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2764 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2765 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2766 2767 _FlushIfNotInTransaction(); 2768 } 2769 2770 2771 void 2772 BView::FillBezier(BPoint* controlPoints, const BGradient& gradient) 2773 { 2774 if (fOwner == NULL) 2775 return; 2776 2777 _CheckLockAndSwitchCurrent(); 2778 2779 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT); 2780 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2781 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2782 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2783 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2784 fOwner->fLink->AttachGradient(gradient); 2785 2786 _FlushIfNotInTransaction(); 2787 } 2788 2789 2790 void 2791 BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern) 2792 { 2793 if (!polygon) 2794 return; 2795 2796 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, 2797 pattern); 2798 } 2799 2800 2801 void 2802 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed, 2803 ::pattern pattern) 2804 { 2805 BPolygon polygon(pointArray, numPoints); 2806 2807 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, 2808 pattern); 2809 } 2810 2811 2812 void 2813 BView::StrokePolygon(const BPoint* ptArray, int32 numPoints, BRect bounds, 2814 bool closed, ::pattern pattern) 2815 { 2816 if (!ptArray 2817 || numPoints <= 1 2818 || fOwner == NULL) 2819 return; 2820 2821 _CheckLockAndSwitchCurrent(); 2822 _UpdatePattern(pattern); 2823 2824 BPolygon polygon(ptArray, numPoints); 2825 polygon.MapTo(polygon.Frame(), bounds); 2826 2827 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON, 2828 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) 2829 + sizeof(int32)) == B_OK) { 2830 fOwner->fLink->Attach<BRect>(polygon.Frame()); 2831 fOwner->fLink->Attach<bool>(closed); 2832 fOwner->fLink->Attach<int32>(polygon.fCount); 2833 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint)); 2834 2835 _FlushIfNotInTransaction(); 2836 } else { 2837 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2838 } 2839 } 2840 2841 2842 void 2843 BView::FillPolygon(const BPolygon* polygon, ::pattern pattern) 2844 { 2845 if (polygon == NULL 2846 || polygon->fCount <= 2 2847 || fOwner == NULL) 2848 return; 2849 2850 _CheckLockAndSwitchCurrent(); 2851 _UpdatePattern(pattern); 2852 2853 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON, 2854 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 2855 == B_OK) { 2856 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2857 fOwner->fLink->Attach<int32>(polygon->fCount); 2858 fOwner->fLink->Attach(polygon->fPoints, 2859 polygon->fCount * sizeof(BPoint)); 2860 2861 _FlushIfNotInTransaction(); 2862 } else { 2863 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2864 } 2865 } 2866 2867 2868 void 2869 BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient) 2870 { 2871 if (polygon == NULL 2872 || polygon->fCount <= 2 2873 || fOwner == NULL) 2874 return; 2875 2876 _CheckLockAndSwitchCurrent(); 2877 2878 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT, 2879 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 2880 == B_OK) { 2881 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2882 fOwner->fLink->Attach<int32>(polygon->fCount); 2883 fOwner->fLink->Attach(polygon->fPoints, 2884 polygon->fCount * sizeof(BPoint)); 2885 fOwner->fLink->AttachGradient(gradient); 2886 2887 _FlushIfNotInTransaction(); 2888 } else { 2889 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2890 } 2891 } 2892 2893 2894 void 2895 BView::FillPolygon(const BPoint* ptArray, int32 numPts, ::pattern pattern) 2896 { 2897 if (!ptArray) 2898 return; 2899 2900 BPolygon polygon(ptArray, numPts); 2901 FillPolygon(&polygon, pattern); 2902 } 2903 2904 2905 void 2906 BView::FillPolygon(const BPoint* ptArray, int32 numPts, 2907 const BGradient& gradient) 2908 { 2909 if (!ptArray) 2910 return; 2911 2912 BPolygon polygon(ptArray, numPts); 2913 FillPolygon(&polygon, gradient); 2914 } 2915 2916 2917 void 2918 BView::FillPolygon(const BPoint* ptArray, int32 numPts, BRect bounds, 2919 pattern p) 2920 { 2921 if (!ptArray) 2922 return; 2923 2924 BPolygon polygon(ptArray, numPts); 2925 2926 polygon.MapTo(polygon.Frame(), bounds); 2927 FillPolygon(&polygon, p); 2928 } 2929 2930 2931 void 2932 BView::FillPolygon(const BPoint* ptArray, int32 numPts, BRect bounds, 2933 const BGradient& gradient) 2934 { 2935 if (!ptArray) 2936 return; 2937 2938 BPolygon polygon(ptArray, numPts); 2939 2940 polygon.MapTo(polygon.Frame(), bounds); 2941 FillPolygon(&polygon, gradient); 2942 } 2943 2944 2945 void 2946 BView::StrokeRect(BRect rect, ::pattern pattern) 2947 { 2948 if (fOwner == NULL) 2949 return; 2950 2951 _CheckLockAndSwitchCurrent(); 2952 _UpdatePattern(pattern); 2953 2954 fOwner->fLink->StartMessage(AS_STROKE_RECT); 2955 fOwner->fLink->Attach<BRect>(rect); 2956 2957 _FlushIfNotInTransaction(); 2958 } 2959 2960 2961 void 2962 BView::FillRect(BRect rect, ::pattern pattern) 2963 { 2964 if (fOwner == NULL) 2965 return; 2966 2967 // NOTE: ensuring compatibility with R5, 2968 // invalid rects are not filled, they are stroked though! 2969 if (!rect.IsValid()) 2970 return; 2971 2972 _CheckLockAndSwitchCurrent(); 2973 _UpdatePattern(pattern); 2974 2975 fOwner->fLink->StartMessage(AS_FILL_RECT); 2976 fOwner->fLink->Attach<BRect>(rect); 2977 2978 _FlushIfNotInTransaction(); 2979 } 2980 2981 2982 void 2983 BView::FillRect(BRect rect, const BGradient& gradient) 2984 { 2985 if (fOwner == NULL) 2986 return; 2987 2988 // NOTE: ensuring compatibility with R5, 2989 // invalid rects are not filled, they are stroked though! 2990 if (!rect.IsValid()) 2991 return; 2992 2993 _CheckLockAndSwitchCurrent(); 2994 2995 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT); 2996 fOwner->fLink->Attach<BRect>(rect); 2997 fOwner->fLink->AttachGradient(gradient); 2998 2999 _FlushIfNotInTransaction(); 3000 } 3001 3002 3003 void 3004 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius, 3005 ::pattern pattern) 3006 { 3007 if (fOwner == NULL) 3008 return; 3009 3010 _CheckLockAndSwitchCurrent(); 3011 _UpdatePattern(pattern); 3012 3013 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT); 3014 fOwner->fLink->Attach<BRect>(rect); 3015 fOwner->fLink->Attach<float>(xRadius); 3016 fOwner->fLink->Attach<float>(yRadius); 3017 3018 _FlushIfNotInTransaction(); 3019 } 3020 3021 3022 void 3023 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3024 ::pattern pattern) 3025 { 3026 if (fOwner == NULL) 3027 return; 3028 3029 _CheckLockAndSwitchCurrent(); 3030 3031 _UpdatePattern(pattern); 3032 3033 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT); 3034 fOwner->fLink->Attach<BRect>(rect); 3035 fOwner->fLink->Attach<float>(xRadius); 3036 fOwner->fLink->Attach<float>(yRadius); 3037 3038 _FlushIfNotInTransaction(); 3039 } 3040 3041 3042 void 3043 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3044 const BGradient& gradient) 3045 { 3046 if (fOwner == NULL) 3047 return; 3048 3049 _CheckLockAndSwitchCurrent(); 3050 3051 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT); 3052 fOwner->fLink->Attach<BRect>(rect); 3053 fOwner->fLink->Attach<float>(xRadius); 3054 fOwner->fLink->Attach<float>(yRadius); 3055 fOwner->fLink->AttachGradient(gradient); 3056 3057 _FlushIfNotInTransaction(); 3058 } 3059 3060 3061 void 3062 BView::FillRegion(BRegion* region, ::pattern pattern) 3063 { 3064 if (region == NULL || fOwner == NULL) 3065 return; 3066 3067 _CheckLockAndSwitchCurrent(); 3068 3069 _UpdatePattern(pattern); 3070 3071 fOwner->fLink->StartMessage(AS_FILL_REGION); 3072 fOwner->fLink->AttachRegion(*region); 3073 3074 _FlushIfNotInTransaction(); 3075 } 3076 3077 3078 void 3079 BView::FillRegion(BRegion* region, const BGradient& gradient) 3080 { 3081 if (region == NULL || fOwner == NULL) 3082 return; 3083 3084 _CheckLockAndSwitchCurrent(); 3085 3086 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT); 3087 fOwner->fLink->AttachRegion(*region); 3088 fOwner->fLink->AttachGradient(gradient); 3089 3090 _FlushIfNotInTransaction(); 3091 } 3092 3093 3094 void 3095 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds, 3096 ::pattern pattern) 3097 { 3098 if (fOwner == NULL) 3099 return; 3100 3101 _CheckLockAndSwitchCurrent(); 3102 3103 _UpdatePattern(pattern); 3104 3105 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE); 3106 fOwner->fLink->Attach<BPoint>(pt1); 3107 fOwner->fLink->Attach<BPoint>(pt2); 3108 fOwner->fLink->Attach<BPoint>(pt3); 3109 fOwner->fLink->Attach<BRect>(bounds); 3110 3111 _FlushIfNotInTransaction(); 3112 } 3113 3114 3115 void 3116 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 3117 { 3118 if (fOwner) { 3119 // we construct the smallest rectangle that contains the 3 points 3120 // for the 1st point 3121 BRect bounds(pt1, pt1); 3122 3123 // for the 2nd point 3124 if (pt2.x < bounds.left) 3125 bounds.left = pt2.x; 3126 3127 if (pt2.y < bounds.top) 3128 bounds.top = pt2.y; 3129 3130 if (pt2.x > bounds.right) 3131 bounds.right = pt2.x; 3132 3133 if (pt2.y > bounds.bottom) 3134 bounds.bottom = pt2.y; 3135 3136 // for the 3rd point 3137 if (pt3.x < bounds.left) 3138 bounds.left = pt3.x; 3139 3140 if (pt3.y < bounds.top) 3141 bounds.top = pt3.y; 3142 3143 if (pt3.x > bounds.right) 3144 bounds.right = pt3.x; 3145 3146 if (pt3.y > bounds.bottom) 3147 bounds.bottom = pt3.y; 3148 3149 StrokeTriangle(pt1, pt2, pt3, bounds, p); 3150 } 3151 } 3152 3153 3154 void 3155 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 3156 { 3157 if (fOwner) { 3158 // we construct the smallest rectangle that contains the 3 points 3159 // for the 1st point 3160 BRect bounds(pt1, pt1); 3161 3162 // for the 2nd point 3163 if (pt2.x < bounds.left) 3164 bounds.left = pt2.x; 3165 3166 if (pt2.y < bounds.top) 3167 bounds.top = pt2.y; 3168 3169 if (pt2.x > bounds.right) 3170 bounds.right = pt2.x; 3171 3172 if (pt2.y > bounds.bottom) 3173 bounds.bottom = pt2.y; 3174 3175 // for the 3rd point 3176 if (pt3.x < bounds.left) 3177 bounds.left = pt3.x; 3178 3179 if (pt3.y < bounds.top) 3180 bounds.top = pt3.y; 3181 3182 if (pt3.x > bounds.right) 3183 bounds.right = pt3.x; 3184 3185 if (pt3.y > bounds.bottom) 3186 bounds.bottom = pt3.y; 3187 3188 FillTriangle(pt1, pt2, pt3, bounds, p); 3189 } 3190 } 3191 3192 3193 void 3194 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3195 const BGradient& gradient) 3196 { 3197 if (fOwner) { 3198 // we construct the smallest rectangle that contains the 3 points 3199 // for the 1st point 3200 BRect bounds(pt1, pt1); 3201 3202 // for the 2nd point 3203 if (pt2.x < bounds.left) 3204 bounds.left = pt2.x; 3205 3206 if (pt2.y < bounds.top) 3207 bounds.top = pt2.y; 3208 3209 if (pt2.x > bounds.right) 3210 bounds.right = pt2.x; 3211 3212 if (pt2.y > bounds.bottom) 3213 bounds.bottom = pt2.y; 3214 3215 // for the 3rd point 3216 if (pt3.x < bounds.left) 3217 bounds.left = pt3.x; 3218 3219 if (pt3.y < bounds.top) 3220 bounds.top = pt3.y; 3221 3222 if (pt3.x > bounds.right) 3223 bounds.right = pt3.x; 3224 3225 if (pt3.y > bounds.bottom) 3226 bounds.bottom = pt3.y; 3227 3228 FillTriangle(pt1, pt2, pt3, bounds, gradient); 3229 } 3230 } 3231 3232 3233 void 3234 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3235 BRect bounds, ::pattern pattern) 3236 { 3237 if (fOwner == NULL) 3238 return; 3239 3240 _CheckLockAndSwitchCurrent(); 3241 _UpdatePattern(pattern); 3242 3243 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 3244 fOwner->fLink->Attach<BPoint>(pt1); 3245 fOwner->fLink->Attach<BPoint>(pt2); 3246 fOwner->fLink->Attach<BPoint>(pt3); 3247 fOwner->fLink->Attach<BRect>(bounds); 3248 3249 _FlushIfNotInTransaction(); 3250 } 3251 3252 3253 void 3254 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3255 BRect bounds, const BGradient& gradient) 3256 { 3257 if (fOwner == NULL) 3258 return; 3259 3260 _CheckLockAndSwitchCurrent(); 3261 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT); 3262 fOwner->fLink->Attach<BPoint>(pt1); 3263 fOwner->fLink->Attach<BPoint>(pt2); 3264 fOwner->fLink->Attach<BPoint>(pt3); 3265 fOwner->fLink->Attach<BRect>(bounds); 3266 fOwner->fLink->AttachGradient(gradient); 3267 3268 _FlushIfNotInTransaction(); 3269 } 3270 3271 3272 void 3273 BView::StrokeLine(BPoint toPt, pattern p) 3274 { 3275 StrokeLine(PenLocation(), toPt, p); 3276 } 3277 3278 3279 void 3280 BView::StrokeLine(BPoint pt0, BPoint pt1, ::pattern pattern) 3281 { 3282 if (fOwner == NULL) 3283 return; 3284 3285 _CheckLockAndSwitchCurrent(); 3286 _UpdatePattern(pattern); 3287 3288 ViewStrokeLineInfo info; 3289 info.startPoint = pt0; 3290 info.endPoint = pt1; 3291 3292 fOwner->fLink->StartMessage(AS_STROKE_LINE); 3293 fOwner->fLink->Attach<ViewStrokeLineInfo>(info); 3294 3295 _FlushIfNotInTransaction(); 3296 3297 // this modifies our pen location, so we invalidate the flag. 3298 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3299 } 3300 3301 3302 void 3303 BView::StrokeShape(BShape* shape, ::pattern pattern) 3304 { 3305 if (shape == NULL || fOwner == NULL) 3306 return; 3307 3308 shape_data* sd = (shape_data*)shape->fPrivateData; 3309 if (sd->opCount == 0 || sd->ptCount == 0) 3310 return; 3311 3312 _CheckLockAndSwitchCurrent(); 3313 _UpdatePattern(pattern); 3314 3315 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 3316 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3317 fOwner->fLink->Attach<int32>(sd->opCount); 3318 fOwner->fLink->Attach<int32>(sd->ptCount); 3319 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 3320 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3321 3322 _FlushIfNotInTransaction(); 3323 } 3324 3325 3326 void 3327 BView::FillShape(BShape* shape, ::pattern pattern) 3328 { 3329 if (shape == NULL || fOwner == NULL) 3330 return; 3331 3332 shape_data* sd = (shape_data*)(shape->fPrivateData); 3333 if (sd->opCount == 0 || sd->ptCount == 0) 3334 return; 3335 3336 _CheckLockAndSwitchCurrent(); 3337 _UpdatePattern(pattern); 3338 3339 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 3340 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3341 fOwner->fLink->Attach<int32>(sd->opCount); 3342 fOwner->fLink->Attach<int32>(sd->ptCount); 3343 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3344 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3345 3346 _FlushIfNotInTransaction(); 3347 } 3348 3349 3350 void 3351 BView::FillShape(BShape* shape, const BGradient& gradient) 3352 { 3353 if (shape == NULL || fOwner == NULL) 3354 return; 3355 3356 shape_data* sd = (shape_data*)(shape->fPrivateData); 3357 if (sd->opCount == 0 || sd->ptCount == 0) 3358 return; 3359 3360 _CheckLockAndSwitchCurrent(); 3361 3362 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT); 3363 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3364 fOwner->fLink->Attach<int32>(sd->opCount); 3365 fOwner->fLink->Attach<int32>(sd->ptCount); 3366 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3367 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3368 fOwner->fLink->AttachGradient(gradient); 3369 3370 _FlushIfNotInTransaction(); 3371 } 3372 3373 3374 void 3375 BView::BeginLineArray(int32 count) 3376 { 3377 if (fOwner == NULL) 3378 return; 3379 3380 if (count <= 0) 3381 debugger("Calling BeginLineArray with a count <= 0"); 3382 3383 _CheckLock(); 3384 3385 if (fCommArray) { 3386 debugger("Can't nest BeginLineArray calls"); 3387 // not fatal, but it helps during 3388 // development of your app and is in 3389 // line with R5... 3390 delete[] fCommArray->array; 3391 delete fCommArray; 3392 } 3393 3394 // TODO: since this method cannot return failure, and further AddLine() 3395 // calls with a NULL fCommArray would drop into the debugger anyway, 3396 // we allow the possible std::bad_alloc exceptions here... 3397 fCommArray = new _array_data_; 3398 fCommArray->maxCount = count; 3399 fCommArray->count = 0; 3400 fCommArray->array = new ViewLineArrayInfo[count]; 3401 } 3402 3403 3404 void 3405 BView::AddLine(BPoint pt0, BPoint pt1, rgb_color col) 3406 { 3407 if (fOwner == NULL) 3408 return; 3409 3410 if (!fCommArray) 3411 debugger("BeginLineArray must be called before using AddLine"); 3412 3413 _CheckLock(); 3414 3415 const uint32 &arrayCount = fCommArray->count; 3416 if (arrayCount < fCommArray->maxCount) { 3417 fCommArray->array[arrayCount].startPoint = pt0; 3418 fCommArray->array[arrayCount].endPoint = pt1; 3419 fCommArray->array[arrayCount].color = col; 3420 3421 fCommArray->count++; 3422 } 3423 } 3424 3425 3426 void 3427 BView::EndLineArray() 3428 { 3429 if (fOwner == NULL) 3430 return; 3431 3432 if (fCommArray == NULL) 3433 debugger("Can't call EndLineArray before BeginLineArray"); 3434 3435 _CheckLockAndSwitchCurrent(); 3436 3437 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 3438 fOwner->fLink->Attach<int32>(fCommArray->count); 3439 fOwner->fLink->Attach(fCommArray->array, 3440 fCommArray->count * sizeof(ViewLineArrayInfo)); 3441 3442 _FlushIfNotInTransaction(); 3443 3444 _RemoveCommArray(); 3445 } 3446 3447 3448 void 3449 BView::SetDiskMode(char* filename, long offset) 3450 { 3451 // TODO: implement 3452 // One BeBook version has this to say about SetDiskMode(): 3453 // 3454 // "Begins recording a picture to the file with the given filename 3455 // at the given offset. Subsequent drawing commands sent to the view 3456 // will be written to the file until EndPicture() is called. The 3457 // stored commands may be played from the file with DrawPicture()." 3458 } 3459 3460 3461 void 3462 BView::BeginPicture(BPicture* picture) 3463 { 3464 if (_CheckOwnerLockAndSwitchCurrent() 3465 && picture && picture->fUsurped == NULL) { 3466 picture->Usurp(fCurrentPicture); 3467 fCurrentPicture = picture; 3468 3469 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE); 3470 } 3471 } 3472 3473 3474 void 3475 BView::AppendToPicture(BPicture* picture) 3476 { 3477 _CheckLockAndSwitchCurrent(); 3478 3479 if (picture && picture->fUsurped == NULL) { 3480 int32 token = picture->Token(); 3481 3482 if (token == -1) { 3483 BeginPicture(picture); 3484 } else { 3485 picture->SetToken(-1); 3486 picture->Usurp(fCurrentPicture); 3487 fCurrentPicture = picture; 3488 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE); 3489 fOwner->fLink->Attach<int32>(token); 3490 } 3491 } 3492 } 3493 3494 3495 BPicture* 3496 BView::EndPicture() 3497 { 3498 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) { 3499 int32 token; 3500 3501 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE); 3502 3503 int32 code; 3504 if (fOwner->fLink->FlushWithReply(code) == B_OK 3505 && code == B_OK 3506 && fOwner->fLink->Read<int32>(&token) == B_OK) { 3507 BPicture* picture = fCurrentPicture; 3508 fCurrentPicture = picture->StepDown(); 3509 picture->SetToken(token); 3510 3511 return picture; 3512 } 3513 } 3514 3515 return NULL; 3516 } 3517 3518 3519 void 3520 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 3521 uint32 followFlags, uint32 options) 3522 { 3523 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 3524 } 3525 3526 3527 void 3528 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options) 3529 { 3530 BRect rect; 3531 if (bitmap) 3532 rect = bitmap->Bounds(); 3533 3534 rect.OffsetTo(B_ORIGIN); 3535 3536 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 3537 } 3538 3539 3540 void 3541 BView::ClearViewBitmap() 3542 { 3543 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3544 } 3545 3546 3547 status_t 3548 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect, 3549 rgb_color* colorKey, uint32 followFlags, uint32 options) 3550 { 3551 if ((overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 3552 return B_BAD_VALUE; 3553 3554 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 3555 options | AS_REQUEST_COLOR_KEY); 3556 if (status == B_OK) { 3557 // read the color that will be treated as transparent 3558 fOwner->fLink->Read<rgb_color>(colorKey); 3559 } 3560 3561 return status; 3562 } 3563 3564 3565 status_t 3566 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, 3567 uint32 followFlags, uint32 options) 3568 { 3569 BRect rect; 3570 if (overlay != NULL) { 3571 rect = overlay->Bounds(); 3572 rect.OffsetTo(B_ORIGIN); 3573 } 3574 3575 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 3576 } 3577 3578 3579 void 3580 BView::ClearViewOverlay() 3581 { 3582 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3583 } 3584 3585 3586 void 3587 BView::CopyBits(BRect src, BRect dst) 3588 { 3589 if (fOwner == NULL) 3590 return; 3591 3592 if (!src.IsValid() || !dst.IsValid()) 3593 return; 3594 3595 _CheckLockAndSwitchCurrent(); 3596 3597 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS); 3598 fOwner->fLink->Attach<BRect>(src); 3599 fOwner->fLink->Attach<BRect>(dst); 3600 3601 _FlushIfNotInTransaction(); 3602 } 3603 3604 3605 void 3606 BView::DrawPicture(const BPicture* picture) 3607 { 3608 if (picture == NULL) 3609 return; 3610 3611 DrawPictureAsync(picture, PenLocation()); 3612 Sync(); 3613 } 3614 3615 3616 void 3617 BView::DrawPicture(const BPicture* picture, BPoint where) 3618 { 3619 if (picture == NULL) 3620 return; 3621 3622 DrawPictureAsync(picture, where); 3623 Sync(); 3624 } 3625 3626 3627 void 3628 BView::DrawPicture(const char* filename, long offset, BPoint where) 3629 { 3630 if (!filename) 3631 return; 3632 3633 DrawPictureAsync(filename, offset, where); 3634 Sync(); 3635 } 3636 3637 3638 void 3639 BView::DrawPictureAsync(const BPicture* picture) 3640 { 3641 if (picture == NULL) 3642 return; 3643 3644 DrawPictureAsync(picture, PenLocation()); 3645 } 3646 3647 3648 void 3649 BView::DrawPictureAsync(const BPicture* picture, BPoint where) 3650 { 3651 if (picture == NULL) 3652 return; 3653 3654 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 3655 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE); 3656 fOwner->fLink->Attach<int32>(picture->Token()); 3657 fOwner->fLink->Attach<BPoint>(where); 3658 3659 _FlushIfNotInTransaction(); 3660 } 3661 } 3662 3663 3664 void 3665 BView::DrawPictureAsync(const char* filename, long offset, BPoint where) 3666 { 3667 if (!filename) 3668 return; 3669 3670 // TODO: Test 3671 BFile file(filename, B_READ_ONLY); 3672 if (file.InitCheck() < B_OK) 3673 return; 3674 3675 file.Seek(offset, SEEK_SET); 3676 3677 BPicture picture; 3678 if (picture.Unflatten(&file) < B_OK) 3679 return; 3680 3681 DrawPictureAsync(&picture, where); 3682 } 3683 3684 3685 void 3686 BView::Invalidate(BRect invalRect) 3687 { 3688 if (fOwner == NULL) 3689 return; 3690 3691 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 3692 // On the server side, the invalid rect will be converted to a BRegion, 3693 // which rounds in a different manner, so that it really includes the 3694 // fractional coordinates of a BRect (ie ceilf(rect.right) & 3695 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 3696 // different rounding here to stay compatible in both ways. 3697 invalRect.left = (int)invalRect.left; 3698 invalRect.top = (int)invalRect.top; 3699 invalRect.right = (int)invalRect.right; 3700 invalRect.bottom = (int)invalRect.bottom; 3701 if (!invalRect.IsValid()) 3702 return; 3703 3704 _CheckLockAndSwitchCurrent(); 3705 3706 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT); 3707 fOwner->fLink->Attach<BRect>(invalRect); 3708 3709 // TODO: determine why this check isn't working correctly. 3710 #if 0 3711 if (!fOwner->fUpdateRequested) { 3712 fOwner->fLink->Flush(); 3713 fOwner->fUpdateRequested = true; 3714 } 3715 #else 3716 fOwner->fLink->Flush(); 3717 #endif 3718 } 3719 3720 3721 void 3722 BView::Invalidate(const BRegion* region) 3723 { 3724 if (region == NULL || fOwner == NULL) 3725 return; 3726 3727 _CheckLockAndSwitchCurrent(); 3728 3729 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION); 3730 fOwner->fLink->AttachRegion(*region); 3731 3732 // TODO: See above. 3733 #if 0 3734 if (!fOwner->fUpdateRequested) { 3735 fOwner->fLink->Flush(); 3736 fOwner->fUpdateRequested = true; 3737 } 3738 #else 3739 fOwner->fLink->Flush(); 3740 #endif 3741 } 3742 3743 3744 void 3745 BView::Invalidate() 3746 { 3747 Invalidate(Bounds()); 3748 } 3749 3750 3751 void 3752 BView::InvertRect(BRect rect) 3753 { 3754 if (fOwner) { 3755 _CheckLockAndSwitchCurrent(); 3756 3757 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT); 3758 fOwner->fLink->Attach<BRect>(rect); 3759 3760 _FlushIfNotInTransaction(); 3761 } 3762 } 3763 3764 3765 // #pragma mark - View Hierarchy Functions 3766 3767 3768 void 3769 BView::AddChild(BView* child, BView* before) 3770 { 3771 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n", 3772 this->Name(), 3773 child != NULL && child->Name() ? child->Name() : "NULL", 3774 before != NULL && before->Name() ? before->Name() : "NULL")); 3775 3776 if (!_AddChild(child, before)) 3777 return; 3778 3779 if (fLayoutData->fLayout) 3780 fLayoutData->fLayout->AddView(child); 3781 } 3782 3783 3784 bool 3785 BView::AddChild(BLayoutItem* child) 3786 { 3787 if (!fLayoutData->fLayout) 3788 return false; 3789 return fLayoutData->fLayout->AddItem(child); 3790 } 3791 3792 3793 bool 3794 BView::_AddChild(BView* child, BView* before) 3795 { 3796 if (!child) 3797 return false; 3798 3799 if (child->fParent != NULL) { 3800 debugger("AddChild failed - the view already has a parent."); 3801 return false; 3802 } 3803 3804 bool lockedOwner = false; 3805 if (fOwner && !fOwner->IsLocked()) { 3806 fOwner->Lock(); 3807 lockedOwner = true; 3808 } 3809 3810 if (!_AddChildToList(child, before)) { 3811 debugger("AddChild failed!"); 3812 if (lockedOwner) 3813 fOwner->Unlock(); 3814 return false; 3815 } 3816 3817 if (fOwner) { 3818 _CheckLockAndSwitchCurrent(); 3819 3820 child->_SetOwner(fOwner); 3821 child->_CreateSelf(); 3822 child->_Attach(); 3823 3824 if (lockedOwner) 3825 fOwner->Unlock(); 3826 } 3827 3828 InvalidateLayout(); 3829 3830 return true; 3831 } 3832 3833 3834 bool 3835 BView::RemoveChild(BView* child) 3836 { 3837 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name())); 3838 3839 if (!child) 3840 return false; 3841 3842 if (child->fParent != this) 3843 return false; 3844 3845 return child->RemoveSelf(); 3846 } 3847 3848 int32 3849 BView::CountChildren() const 3850 { 3851 _CheckLock(); 3852 3853 uint32 count = 0; 3854 BView* child = fFirstChild; 3855 3856 while (child != NULL) { 3857 count++; 3858 child = child->fNextSibling; 3859 } 3860 3861 return count; 3862 } 3863 3864 3865 BView* 3866 BView::ChildAt(int32 index) const 3867 { 3868 _CheckLock(); 3869 3870 BView* child = fFirstChild; 3871 while (child != NULL && index-- > 0) { 3872 child = child->fNextSibling; 3873 } 3874 3875 return child; 3876 } 3877 3878 3879 BView* 3880 BView::NextSibling() const 3881 { 3882 return fNextSibling; 3883 } 3884 3885 3886 BView* 3887 BView::PreviousSibling() const 3888 { 3889 return fPreviousSibling; 3890 } 3891 3892 3893 bool 3894 BView::RemoveSelf() 3895 { 3896 if (fParent && fParent->fLayoutData->fLayout) 3897 return fParent->fLayoutData->fLayout->RemoveView(this); 3898 else 3899 return _RemoveSelf(); 3900 } 3901 3902 3903 bool 3904 BView::_RemoveSelf() 3905 { 3906 STRACE(("BView(%s)::RemoveSelf()\n", Name())); 3907 3908 // Remove this child from its parent 3909 3910 BWindow* owner = fOwner; 3911 _CheckLock(); 3912 3913 if (owner != NULL) { 3914 _UpdateStateForRemove(); 3915 _Detach(); 3916 } 3917 3918 BView* parent = fParent; 3919 if (!parent || !parent->_RemoveChildFromList(this)) 3920 return false; 3921 3922 if (owner != NULL && !fTopLevelView) { 3923 // the top level view is deleted by the app_server automatically 3924 owner->fLink->StartMessage(AS_VIEW_DELETE); 3925 owner->fLink->Attach<int32>(_get_object_token_(this)); 3926 } 3927 3928 parent->InvalidateLayout(); 3929 3930 STRACE(("DONE: BView(%s)::RemoveSelf()\n", Name())); 3931 3932 return true; 3933 } 3934 3935 3936 BView* 3937 BView::Parent() const 3938 { 3939 if (fParent && fParent->fTopLevelView) 3940 return NULL; 3941 3942 return fParent; 3943 } 3944 3945 3946 BView* 3947 BView::FindView(const char* name) const 3948 { 3949 if (name == NULL) 3950 return NULL; 3951 3952 if (Name() != NULL && !strcmp(Name(), name)) 3953 return const_cast<BView*>(this); 3954 3955 BView* child = fFirstChild; 3956 while (child != NULL) { 3957 BView* view = child->FindView(name); 3958 if (view != NULL) 3959 return view; 3960 3961 child = child->fNextSibling; 3962 } 3963 3964 return NULL; 3965 } 3966 3967 3968 void 3969 BView::MoveBy(float deltaX, float deltaY) 3970 { 3971 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY)); 3972 } 3973 3974 3975 void 3976 BView::MoveTo(BPoint where) 3977 { 3978 MoveTo(where.x, where.y); 3979 } 3980 3981 3982 void 3983 BView::MoveTo(float x, float y) 3984 { 3985 if (x == fParentOffset.x && y == fParentOffset.y) 3986 return; 3987 3988 // BeBook says we should do this. And it makes sense. 3989 x = roundf(x); 3990 y = roundf(y); 3991 3992 if (fOwner) { 3993 _CheckLockAndSwitchCurrent(); 3994 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO); 3995 fOwner->fLink->Attach<float>(x); 3996 fOwner->fLink->Attach<float>(y); 3997 3998 // fState->valid_flags |= B_VIEW_FRAME_BIT; 3999 4000 _FlushIfNotInTransaction(); 4001 } 4002 4003 _MoveTo((int32)x, (int32)y); 4004 } 4005 4006 4007 void 4008 BView::ResizeBy(float deltaWidth, float deltaHeight) 4009 { 4010 // BeBook says we should do this. And it makes sense. 4011 deltaWidth = roundf(deltaWidth); 4012 deltaHeight = roundf(deltaHeight); 4013 4014 if (deltaWidth == 0 && deltaHeight == 0) 4015 return; 4016 4017 if (fOwner) { 4018 _CheckLockAndSwitchCurrent(); 4019 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO); 4020 4021 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth); 4022 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight); 4023 4024 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4025 4026 _FlushIfNotInTransaction(); 4027 } 4028 4029 _ResizeBy((int32)deltaWidth, (int32)deltaHeight); 4030 } 4031 4032 4033 void 4034 BView::ResizeTo(float width, float height) 4035 { 4036 ResizeBy(width - fBounds.Width(), height - fBounds.Height()); 4037 } 4038 4039 4040 void 4041 BView::ResizeTo(BSize size) 4042 { 4043 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height()); 4044 } 4045 4046 4047 // #pragma mark - Inherited Methods (from BHandler) 4048 4049 4050 status_t 4051 BView::GetSupportedSuites(BMessage* data) 4052 { 4053 if (data == NULL) 4054 return B_BAD_VALUE; 4055 4056 status_t status = data->AddString("suites", "suite/vnd.Be-view"); 4057 BPropertyInfo propertyInfo(sViewPropInfo); 4058 if (status == B_OK) 4059 status = data->AddFlat("messages", &propertyInfo); 4060 if (status == B_OK) 4061 return BHandler::GetSupportedSuites(data); 4062 return status; 4063 } 4064 4065 4066 BHandler* 4067 BView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, 4068 int32 what, const char* property) 4069 { 4070 if (msg->what == B_WINDOW_MOVE_BY 4071 || msg->what == B_WINDOW_MOVE_TO) 4072 return this; 4073 4074 BPropertyInfo propertyInfo(sViewPropInfo); 4075 status_t err = B_BAD_SCRIPT_SYNTAX; 4076 BMessage replyMsg(B_REPLY); 4077 4078 switch (propertyInfo.FindMatch(msg, index, specifier, what, property)) { 4079 case 0: 4080 case 1: 4081 case 3: 4082 return this; 4083 4084 case 2: 4085 if (fShelf) { 4086 msg->PopSpecifier(); 4087 return fShelf; 4088 } 4089 4090 err = B_NAME_NOT_FOUND; 4091 replyMsg.AddString("message", "This window doesn't have a shelf"); 4092 break; 4093 4094 case 4: 4095 { 4096 if (!fFirstChild) { 4097 err = B_NAME_NOT_FOUND; 4098 replyMsg.AddString("message", "This window doesn't have " 4099 "children."); 4100 break; 4101 } 4102 BView* child = NULL; 4103 switch (what) { 4104 case B_INDEX_SPECIFIER: 4105 { 4106 int32 index; 4107 err = specifier->FindInt32("index", &index); 4108 if (err == B_OK) 4109 child = ChildAt(index); 4110 break; 4111 } 4112 case B_REVERSE_INDEX_SPECIFIER: 4113 { 4114 int32 rindex; 4115 err = specifier->FindInt32("index", &rindex); 4116 if (err == B_OK) 4117 child = ChildAt(CountChildren() - rindex); 4118 break; 4119 } 4120 case B_NAME_SPECIFIER: 4121 { 4122 const char* name; 4123 err = specifier->FindString("name", &name); 4124 if (err == B_OK) 4125 child = FindView(name); 4126 break; 4127 } 4128 } 4129 4130 if (child != NULL) { 4131 msg->PopSpecifier(); 4132 return child; 4133 } 4134 4135 if (err == B_OK) 4136 err = B_BAD_INDEX; 4137 4138 replyMsg.AddString("message", 4139 "Cannot find view at/with specified index/name."); 4140 break; 4141 } 4142 4143 default: 4144 return BHandler::ResolveSpecifier(msg, index, specifier, what, 4145 property); 4146 } 4147 4148 if (err < B_OK) { 4149 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4150 4151 if (err == B_BAD_SCRIPT_SYNTAX) 4152 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4153 else 4154 replyMsg.AddString("message", strerror(err)); 4155 } 4156 4157 replyMsg.AddInt32("error", err); 4158 msg->SendReply(&replyMsg); 4159 return NULL; 4160 } 4161 4162 4163 void 4164 BView::MessageReceived(BMessage* msg) 4165 { 4166 if (!msg->HasSpecifiers()) { 4167 switch (msg->what) { 4168 case B_VIEW_RESIZED: 4169 // By the time the message arrives, the bounds may have 4170 // changed already, that's why we don't use the values 4171 // in the message itself. 4172 FrameResized(fBounds.Width(), fBounds.Height()); 4173 break; 4174 4175 case B_VIEW_MOVED: 4176 FrameMoved(fParentOffset); 4177 break; 4178 4179 case B_MOUSE_IDLE: 4180 { 4181 BPoint where; 4182 if (msg->FindPoint("be:view_where", &where) != B_OK) 4183 break; 4184 4185 BToolTip* tip; 4186 if (GetToolTipAt(where, &tip)) 4187 ShowToolTip(tip); 4188 break; 4189 } 4190 4191 case B_MOUSE_WHEEL_CHANGED: 4192 { 4193 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL); 4194 BScrollBar* vertical = ScrollBar(B_VERTICAL); 4195 if (horizontal == NULL && vertical == NULL) { 4196 // Pass the message to the next handler 4197 BHandler::MessageReceived(msg); 4198 break; 4199 } 4200 4201 float deltaX = 0.0f, deltaY = 0.0f; 4202 if (horizontal != NULL) 4203 msg->FindFloat("be:wheel_delta_x", &deltaX); 4204 if (vertical != NULL) 4205 msg->FindFloat("be:wheel_delta_y", &deltaY); 4206 4207 if (deltaX == 0.0f && deltaY == 0.0f) 4208 break; 4209 4210 float smallStep, largeStep; 4211 if (horizontal != NULL) { 4212 horizontal->GetSteps(&smallStep, &largeStep); 4213 4214 // pressing the option/command/control key scrolls faster 4215 if (modifiers() 4216 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4217 deltaX *= largeStep; 4218 } else 4219 deltaX *= smallStep * 3; 4220 4221 horizontal->SetValue(horizontal->Value() + deltaX); 4222 } 4223 4224 if (vertical != NULL) { 4225 vertical->GetSteps(&smallStep, &largeStep); 4226 4227 // pressing the option/command/control key scrolls faster 4228 if (modifiers() 4229 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4230 deltaY *= largeStep; 4231 } else 4232 deltaY *= smallStep * 3; 4233 4234 vertical->SetValue(vertical->Value() + deltaY); 4235 } 4236 break; 4237 } 4238 4239 default: 4240 BHandler::MessageReceived(msg); 4241 break; 4242 } 4243 4244 return; 4245 } 4246 4247 // Scripting message 4248 4249 BMessage replyMsg(B_REPLY); 4250 status_t err = B_BAD_SCRIPT_SYNTAX; 4251 int32 index; 4252 BMessage specifier; 4253 int32 what; 4254 const char* property; 4255 4256 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &property) != B_OK) 4257 return BHandler::MessageReceived(msg); 4258 4259 BPropertyInfo propertyInfo(sViewPropInfo); 4260 switch (propertyInfo.FindMatch(msg, index, &specifier, what, property)) { 4261 case 0: 4262 if (msg->what == B_GET_PROPERTY) { 4263 err = replyMsg.AddRect("result", Frame()); 4264 } else if (msg->what == B_SET_PROPERTY) { 4265 BRect newFrame; 4266 err = msg->FindRect("data", &newFrame); 4267 if (err == B_OK) { 4268 MoveTo(newFrame.LeftTop()); 4269 ResizeTo(newFrame.Width(), newFrame.Height()); 4270 } 4271 } 4272 break; 4273 case 1: 4274 if (msg->what == B_GET_PROPERTY) { 4275 err = replyMsg.AddBool("result", IsHidden()); 4276 } else if (msg->what == B_SET_PROPERTY) { 4277 bool newHiddenState; 4278 err = msg->FindBool("data", &newHiddenState); 4279 if (err == B_OK) { 4280 if (newHiddenState == true) 4281 Hide(); 4282 else 4283 Show(); 4284 } 4285 } 4286 break; 4287 case 2: 4288 err = replyMsg.AddInt32("result", CountChildren()); 4289 break; 4290 default: 4291 return BHandler::MessageReceived(msg); 4292 } 4293 4294 if (err != B_OK) { 4295 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4296 4297 if (err == B_BAD_SCRIPT_SYNTAX) 4298 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4299 else 4300 replyMsg.AddString("message", strerror(err)); 4301 4302 replyMsg.AddInt32("error", err); 4303 } 4304 4305 msg->SendReply(&replyMsg); 4306 } 4307 4308 4309 status_t 4310 BView::Perform(perform_code code, void* _data) 4311 { 4312 switch (code) { 4313 case PERFORM_CODE_MIN_SIZE: 4314 ((perform_data_min_size*)_data)->return_value 4315 = BView::MinSize(); 4316 return B_OK; 4317 case PERFORM_CODE_MAX_SIZE: 4318 ((perform_data_max_size*)_data)->return_value 4319 = BView::MaxSize(); 4320 return B_OK; 4321 case PERFORM_CODE_PREFERRED_SIZE: 4322 ((perform_data_preferred_size*)_data)->return_value 4323 = BView::PreferredSize(); 4324 return B_OK; 4325 case PERFORM_CODE_LAYOUT_ALIGNMENT: 4326 ((perform_data_layout_alignment*)_data)->return_value 4327 = BView::LayoutAlignment(); 4328 return B_OK; 4329 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 4330 ((perform_data_has_height_for_width*)_data)->return_value 4331 = BView::HasHeightForWidth(); 4332 return B_OK; 4333 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 4334 { 4335 perform_data_get_height_for_width* data 4336 = (perform_data_get_height_for_width*)_data; 4337 BView::GetHeightForWidth(data->width, &data->min, &data->max, 4338 &data->preferred); 4339 return B_OK; 4340 } 4341 case PERFORM_CODE_SET_LAYOUT: 4342 { 4343 perform_data_set_layout* data = (perform_data_set_layout*)_data; 4344 BView::SetLayout(data->layout); 4345 return B_OK; 4346 } 4347 case PERFORM_CODE_INVALIDATE_LAYOUT: 4348 { 4349 perform_data_invalidate_layout* data 4350 = (perform_data_invalidate_layout*)_data; 4351 BView::InvalidateLayout(data->descendants); 4352 return B_OK; 4353 } 4354 case PERFORM_CODE_DO_LAYOUT: 4355 { 4356 BView::DoLayout(); 4357 return B_OK; 4358 } 4359 case PERFORM_CODE_GET_TOOL_TIP_AT: 4360 { 4361 perform_data_get_tool_tip_at* data 4362 = (perform_data_get_tool_tip_at*)_data; 4363 data->return_value 4364 = BView::GetToolTipAt(data->point, data->tool_tip); 4365 return B_OK; 4366 } 4367 } 4368 4369 return BHandler::Perform(code, _data); 4370 } 4371 4372 4373 // #pragma mark - Layout Functions 4374 4375 4376 BSize 4377 BView::MinSize() 4378 { 4379 // TODO: make sure this works correctly when some methods are overridden 4380 float width, height; 4381 GetPreferredSize(&width, &height); 4382 4383 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 4384 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 4385 : BSize(width, height))); 4386 } 4387 4388 4389 BSize 4390 BView::MaxSize() 4391 { 4392 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 4393 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 4394 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 4395 } 4396 4397 4398 BSize 4399 BView::PreferredSize() 4400 { 4401 // TODO: make sure this works correctly when some methods are overridden 4402 float width, height; 4403 GetPreferredSize(&width, &height); 4404 4405 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 4406 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 4407 : BSize(width, height))); 4408 } 4409 4410 4411 BAlignment 4412 BView::LayoutAlignment() 4413 { 4414 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 4415 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 4416 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 4417 } 4418 4419 4420 void 4421 BView::SetExplicitMinSize(BSize size) 4422 { 4423 fLayoutData->fMinSize = size; 4424 InvalidateLayout(); 4425 } 4426 4427 4428 void 4429 BView::SetExplicitMaxSize(BSize size) 4430 { 4431 fLayoutData->fMaxSize = size; 4432 InvalidateLayout(); 4433 } 4434 4435 4436 void 4437 BView::SetExplicitPreferredSize(BSize size) 4438 { 4439 fLayoutData->fPreferredSize = size; 4440 InvalidateLayout(); 4441 } 4442 4443 4444 void 4445 BView::SetExplicitAlignment(BAlignment alignment) 4446 { 4447 fLayoutData->fAlignment = alignment; 4448 InvalidateLayout(); 4449 } 4450 4451 4452 BSize 4453 BView::ExplicitMinSize() const 4454 { 4455 return fLayoutData->fMinSize; 4456 } 4457 4458 4459 BSize 4460 BView::ExplicitMaxSize() const 4461 { 4462 return fLayoutData->fMaxSize; 4463 } 4464 4465 4466 BSize 4467 BView::ExplicitPreferredSize() const 4468 { 4469 return fLayoutData->fPreferredSize; 4470 } 4471 4472 4473 BAlignment 4474 BView::ExplicitAlignment() const 4475 { 4476 return fLayoutData->fAlignment; 4477 } 4478 4479 4480 bool 4481 BView::HasHeightForWidth() 4482 { 4483 return (fLayoutData->fLayout 4484 ? fLayoutData->fLayout->HasHeightForWidth() : false); 4485 } 4486 4487 4488 void 4489 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 4490 { 4491 if (fLayoutData->fLayout) 4492 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 4493 } 4494 4495 4496 void 4497 BView::SetLayout(BLayout* layout) 4498 { 4499 if (layout == fLayoutData->fLayout) 4500 return; 4501 4502 fFlags |= B_SUPPORTS_LAYOUT; 4503 4504 // unset and delete the old layout 4505 if (fLayoutData->fLayout) { 4506 fLayoutData->fLayout->SetView(NULL); 4507 delete fLayoutData->fLayout; 4508 } 4509 4510 fLayoutData->fLayout = layout; 4511 4512 if (fLayoutData->fLayout) { 4513 fLayoutData->fLayout->SetView(this); 4514 4515 // add all children 4516 int count = CountChildren(); 4517 for (int i = 0; i < count; i++) 4518 fLayoutData->fLayout->AddView(ChildAt(i)); 4519 } 4520 4521 InvalidateLayout(); 4522 } 4523 4524 4525 BLayout* 4526 BView::GetLayout() const 4527 { 4528 return fLayoutData->fLayout; 4529 } 4530 4531 4532 void 4533 BView::InvalidateLayout(bool descendants) 4534 { 4535 if (fLayoutData->fMinMaxValid && !fLayoutData->fLayoutInProgress 4536 && fLayoutData->fLayoutInvalidationDisabled == 0) { 4537 if (fParent && fParent->fLayoutData->fMinMaxValid) 4538 fParent->InvalidateLayout(false); 4539 4540 fLayoutData->fLayoutValid = false; 4541 fLayoutData->fMinMaxValid = false; 4542 4543 if (fLayoutData->fLayout) 4544 fLayoutData->fLayout->InvalidateLayout(); 4545 4546 if (descendants) { 4547 int count = CountChildren(); 4548 for (int i = 0; i < count; i++) 4549 ChildAt(i)->InvalidateLayout(descendants); 4550 } 4551 4552 if (fTopLevelView) { 4553 // trigger layout process 4554 if (fOwner) 4555 fOwner->PostMessage(B_LAYOUT_WINDOW); 4556 } 4557 } 4558 } 4559 4560 4561 void 4562 BView::EnableLayoutInvalidation() 4563 { 4564 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4565 fLayoutData->fLayoutInvalidationDisabled--; 4566 } 4567 4568 4569 void 4570 BView::DisableLayoutInvalidation() 4571 { 4572 fLayoutData->fLayoutInvalidationDisabled++; 4573 } 4574 4575 4576 bool 4577 BView::IsLayoutValid() const 4578 { 4579 return fLayoutData->fLayoutValid; 4580 } 4581 4582 4583 /*! \brief Service call for BLayout derived classes reenabling 4584 InvalidateLayout() notifications. 4585 BView::InvalidateLayout() invokes InvalidateLayout() on its layout the first 4586 time, but suppresses further calls until Layout()/Relayout() has been 4587 invoked. This method will reenable the notification for the next call of 4588 BView::InvalidateLayout(). 4589 4590 If the layout caches internal layout information and updates those 4591 information also in methods other than LayoutView(), it has to invoke this 4592 method, when it has done so, since otherwise the information might become 4593 obsolete without the layout noticing. 4594 */ 4595 void 4596 BView::ResetLayoutInvalidation() 4597 { 4598 fLayoutData->fMinMaxValid = true; 4599 } 4600 4601 4602 BLayoutContext* 4603 BView::LayoutContext() const 4604 { 4605 return fLayoutData->fLayoutContext; 4606 } 4607 4608 4609 void 4610 BView::Layout(bool force) 4611 { 4612 BLayoutContext context; 4613 _Layout(force, &context); 4614 } 4615 4616 4617 void 4618 BView::Relayout() 4619 { 4620 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 4621 fLayoutData->fNeedsRelayout = true; 4622 4623 // Layout() is recursive, that is if the parent view is currently laid 4624 // out, we don't call layout() on this view, but wait for the parent's 4625 // Layout() to do that for us. 4626 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 4627 Layout(false); 4628 } 4629 } 4630 4631 4632 void 4633 BView::DoLayout() 4634 { 4635 if (fLayoutData->fLayout) 4636 fLayoutData->fLayout->LayoutView(); 4637 } 4638 4639 4640 void 4641 BView::SetToolTip(const char* text) 4642 { 4643 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip)) 4644 tip->SetText(text); 4645 else 4646 SetToolTip(new BTextToolTip(text)); 4647 } 4648 4649 4650 void 4651 BView::SetToolTip(BToolTip* tip) 4652 { 4653 if (fToolTip == tip) 4654 return; 4655 4656 if (fToolTip != NULL) 4657 fToolTip->ReleaseReference(); 4658 fToolTip = tip; 4659 if (fToolTip != NULL) 4660 fToolTip->AcquireReference(); 4661 } 4662 4663 4664 BToolTip* 4665 BView::ToolTip() const 4666 { 4667 return fToolTip; 4668 } 4669 4670 4671 void 4672 BView::ShowToolTip(BToolTip* tip) 4673 { 4674 if (tip == NULL) 4675 return; 4676 4677 fVisibleToolTip = tip; 4678 4679 BPoint where; 4680 GetMouse(&where, NULL, false); 4681 4682 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where)); 4683 } 4684 4685 4686 void 4687 BView::HideToolTip() 4688 { 4689 BToolTipManager::Manager()->HideTip(); 4690 fVisibleToolTip = NULL; 4691 } 4692 4693 4694 bool 4695 BView::GetToolTipAt(BPoint point, BToolTip** _tip) 4696 { 4697 if (fVisibleToolTip != NULL) { 4698 *_tip = fVisibleToolTip; 4699 return true; 4700 } 4701 if (fToolTip != NULL) { 4702 *_tip = fToolTip; 4703 return true; 4704 } 4705 4706 *_tip = NULL; 4707 return false; 4708 } 4709 4710 4711 void 4712 BView::_Layout(bool force, BLayoutContext* context) 4713 { 4714 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 4715 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 4716 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, 4717 //fLayoutData->fLayoutInProgress); 4718 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 4719 fLayoutData->fLayoutValid = false; 4720 4721 if (fLayoutData->fLayoutInProgress) 4722 return; 4723 4724 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 4725 fLayoutData->fLayoutContext = context; 4726 4727 fLayoutData->fLayoutInProgress = true; 4728 DoLayout(); 4729 fLayoutData->fLayoutInProgress = false; 4730 4731 fLayoutData->fLayoutValid = true; 4732 fLayoutData->fMinMaxValid = true; 4733 fLayoutData->fNeedsRelayout = false; 4734 4735 // layout children 4736 int32 childCount = CountChildren(); 4737 for (int32 i = 0; i < childCount; i++) { 4738 BView* child = ChildAt(i); 4739 if (!child->IsHidden(child)) 4740 child->_Layout(force, context); 4741 } 4742 4743 fLayoutData->fLayoutContext = oldContext; 4744 4745 // invalidate the drawn content, if requested 4746 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 4747 Invalidate(); 4748 } 4749 } 4750 4751 4752 // #pragma mark - Private Functions 4753 4754 4755 void 4756 BView::_InitData(BRect frame, const char* name, uint32 resizingMode, 4757 uint32 flags) 4758 { 4759 // Info: The name of the view is set by BHandler constructor 4760 4761 STRACE(("BView::InitData: enter\n")); 4762 4763 // initialize members 4764 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 4765 printf("%s BView::InitData(): resizing mode or flags swapped\n", name); 4766 4767 // There are applications that swap the resize mask and the flags in the 4768 // BView constructor. This does not cause problems under BeOS as it just 4769 // ors the two fields to one 32bit flag. 4770 // For now we do the same but print the above warning message. 4771 // TODO: this should be removed at some point and the original 4772 // version restored: 4773 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4774 fFlags = resizingMode | flags; 4775 4776 // handle rounding 4777 frame.left = roundf(frame.left); 4778 frame.top = roundf(frame.top); 4779 frame.right = roundf(frame.right); 4780 frame.bottom = roundf(frame.bottom); 4781 4782 fParentOffset.Set(frame.left, frame.top); 4783 4784 fOwner = NULL; 4785 fParent = NULL; 4786 fNextSibling = NULL; 4787 fPreviousSibling = NULL; 4788 fFirstChild = NULL; 4789 4790 fShowLevel = 0; 4791 fTopLevelView = false; 4792 4793 fCurrentPicture = NULL; 4794 fCommArray = NULL; 4795 4796 fVerScroller = NULL; 4797 fHorScroller = NULL; 4798 4799 fIsPrinting = false; 4800 fAttached = false; 4801 4802 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 4803 // TODO: Maybe we could auto-delete those views on AddChild() instead? 4804 fState = new BPrivate::ViewState; 4805 4806 fBounds = frame.OffsetToCopy(B_ORIGIN); 4807 fShelf = NULL; 4808 4809 fEventMask = 0; 4810 fEventOptions = 0; 4811 fMouseEventOptions = 0; 4812 4813 fLayoutData = new LayoutData; 4814 4815 fToolTip = NULL; 4816 fVisibleToolTip = NULL; 4817 } 4818 4819 4820 void 4821 BView::_RemoveCommArray() 4822 { 4823 if (fCommArray) { 4824 delete [] fCommArray->array; 4825 delete fCommArray; 4826 fCommArray = NULL; 4827 } 4828 } 4829 4830 4831 void 4832 BView::_SetOwner(BWindow* newOwner) 4833 { 4834 if (!newOwner) 4835 _RemoveCommArray(); 4836 4837 if (fOwner != newOwner && fOwner) { 4838 if (fOwner->fFocus == this) 4839 MakeFocus(false); 4840 4841 if (fOwner->fLastMouseMovedView == this) 4842 fOwner->fLastMouseMovedView = NULL; 4843 4844 fOwner->RemoveHandler(this); 4845 if (fShelf) 4846 fOwner->RemoveHandler(fShelf); 4847 } 4848 4849 if (newOwner && newOwner != fOwner) { 4850 newOwner->AddHandler(this); 4851 if (fShelf) 4852 newOwner->AddHandler(fShelf); 4853 4854 if (fTopLevelView) 4855 SetNextHandler(newOwner); 4856 else 4857 SetNextHandler(fParent); 4858 } 4859 4860 fOwner = newOwner; 4861 4862 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) 4863 child->_SetOwner(newOwner); 4864 } 4865 4866 4867 void 4868 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) 4869 { 4870 if (!picture) 4871 return; 4872 4873 #if 1 4874 // TODO: Move the implementation to the server!!! 4875 // This implementation is pretty slow, since just creating an offscreen 4876 // bitmap takes a lot of time. That's the main reason why it should be moved 4877 // to the server. 4878 4879 // Here the idea is to get rid of the padding bytes in the bitmap, 4880 // as padding complicates and slows down the iteration. 4881 // TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned 4882 // to a 4 byte boundary. 4883 BRect bounds(Bounds()); 4884 if ((bounds.IntegerWidth() + 1) % 32) { 4885 bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1) 4886 * 32 - 1; 4887 } 4888 4889 // TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work. 4890 BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true); 4891 if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) { 4892 BView* view = new(std::nothrow) BView(bounds, "drawing view", 4893 B_FOLLOW_NONE, 0); 4894 if (view != NULL) { 4895 bitmap->AddChild(view); 4896 view->DrawPicture(picture, where); 4897 view->Sync(); 4898 } 4899 bitmap->Unlock(); 4900 } 4901 4902 BRegion region; 4903 int32 width = bounds.IntegerWidth() + 1; 4904 int32 height = bounds.IntegerHeight() + 1; 4905 if (bitmap != NULL && bitmap->LockBits() == B_OK) { 4906 uint32 bit = 0; 4907 uint32* bits = (uint32*)bitmap->Bits(); 4908 clipping_rect rect; 4909 4910 // TODO: A possible optimization would be adding "spans" instead 4911 // of 1x1 rects. That would probably help with very complex 4912 // BPictures 4913 for (int32 y = 0; y < height; y++) { 4914 for (int32 x = 0; x < width; x++) { 4915 bit = *bits++; 4916 if (bit != 0xFFFFFFFF) { 4917 rect.left = x; 4918 rect.right = rect.left; 4919 rect.top = rect.bottom = y; 4920 region.Include(rect); 4921 } 4922 } 4923 } 4924 bitmap->UnlockBits(); 4925 } 4926 delete bitmap; 4927 4928 if (invert) { 4929 BRegion inverseRegion; 4930 inverseRegion.Include(Bounds()); 4931 inverseRegion.Exclude(®ion); 4932 ConstrainClippingRegion(&inverseRegion); 4933 } else 4934 ConstrainClippingRegion(®ion); 4935 #else 4936 if (_CheckOwnerLockAndSwitchCurrent()) { 4937 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 4938 fOwner->fLink->Attach<int32>(picture->Token()); 4939 fOwner->fLink->Attach<BPoint>(where); 4940 fOwner->fLink->Attach<bool>(invert); 4941 4942 // TODO: I think that "sync" means another thing here: 4943 // the bebook, at least, says so. 4944 if (sync) 4945 fOwner->fLink->Flush(); 4946 4947 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 4948 } 4949 4950 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 4951 #endif 4952 } 4953 4954 4955 bool 4956 BView::_RemoveChildFromList(BView* child) 4957 { 4958 if (child->fParent != this) 4959 return false; 4960 4961 if (fFirstChild == child) { 4962 // it's the first view in the list 4963 fFirstChild = child->fNextSibling; 4964 } else { 4965 // there must be a previous sibling 4966 child->fPreviousSibling->fNextSibling = child->fNextSibling; 4967 } 4968 4969 if (child->fNextSibling) 4970 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 4971 4972 child->fParent = NULL; 4973 child->fNextSibling = NULL; 4974 child->fPreviousSibling = NULL; 4975 4976 return true; 4977 } 4978 4979 4980 bool 4981 BView::_AddChildToList(BView* child, BView* before) 4982 { 4983 if (!child) 4984 return false; 4985 if (child->fParent != NULL) { 4986 debugger("View already belongs to someone else"); 4987 return false; 4988 } 4989 if (before != NULL && before->fParent != this) { 4990 debugger("Invalid before view"); 4991 return false; 4992 } 4993 4994 if (before != NULL) { 4995 // add view before this one 4996 child->fNextSibling = before; 4997 child->fPreviousSibling = before->fPreviousSibling; 4998 if (child->fPreviousSibling != NULL) 4999 child->fPreviousSibling->fNextSibling = child; 5000 5001 before->fPreviousSibling = child; 5002 if (fFirstChild == before) 5003 fFirstChild = child; 5004 } else { 5005 // add view to the end of the list 5006 BView* last = fFirstChild; 5007 while (last != NULL && last->fNextSibling != NULL) { 5008 last = last->fNextSibling; 5009 } 5010 5011 if (last != NULL) { 5012 last->fNextSibling = child; 5013 child->fPreviousSibling = last; 5014 } else { 5015 fFirstChild = child; 5016 child->fPreviousSibling = NULL; 5017 } 5018 5019 child->fNextSibling = NULL; 5020 } 5021 5022 child->fParent = this; 5023 return true; 5024 } 5025 5026 5027 /*! \brief Creates the server counterpart of this view. 5028 This is only done for views that are part of the view hierarchy, ie. when 5029 they are attached to a window. 5030 RemoveSelf() deletes the server object again. 5031 */ 5032 bool 5033 BView::_CreateSelf() 5034 { 5035 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 5036 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 5037 // of the view and its parent are both send to the server. 5038 5039 if (fTopLevelView) 5040 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 5041 else 5042 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 5043 5044 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 5045 fOwner->fLink->AttachString(Name()); 5046 fOwner->fLink->Attach<BRect>(Frame()); 5047 fOwner->fLink->Attach<BPoint>(LeftTop()); 5048 fOwner->fLink->Attach<uint32>(ResizingMode()); 5049 fOwner->fLink->Attach<uint32>(fEventMask); 5050 fOwner->fLink->Attach<uint32>(fEventOptions); 5051 fOwner->fLink->Attach<uint32>(Flags()); 5052 fOwner->fLink->Attach<bool>(IsHidden(this)); 5053 fOwner->fLink->Attach<rgb_color>(fState->view_color); 5054 if (fTopLevelView) 5055 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 5056 else 5057 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 5058 fOwner->fLink->Flush(); 5059 5060 _CheckOwnerLockAndSwitchCurrent(); 5061 fState->UpdateServerState(*fOwner->fLink); 5062 5063 // we create all its children, too 5064 5065 for (BView* child = fFirstChild; child != NULL; 5066 child = child->fNextSibling) { 5067 child->_CreateSelf(); 5068 } 5069 5070 fOwner->fLink->Flush(); 5071 return true; 5072 } 5073 5074 5075 /*! Sets the new view position. 5076 It doesn't contact the server, though - the only case where this 5077 is called outside of MoveTo() is as reaction of moving a view 5078 in the server (a.k.a. B_WINDOW_RESIZED). 5079 It also calls the BView's FrameMoved() hook. 5080 */ 5081 void 5082 BView::_MoveTo(int32 x, int32 y) 5083 { 5084 fParentOffset.Set(x, y); 5085 5086 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 5087 BMessage moved(B_VIEW_MOVED); 5088 moved.AddInt64("when", system_time()); 5089 moved.AddPoint("where", BPoint(x, y)); 5090 5091 BMessenger target(this); 5092 target.SendMessage(&moved); 5093 } 5094 } 5095 5096 5097 /*! Computes the actual new frame size and recalculates the size of 5098 the children as well. 5099 It doesn't contact the server, though - the only case where this 5100 is called outside of ResizeBy() is as reaction of resizing a view 5101 in the server (a.k.a. B_WINDOW_RESIZED). 5102 It also calls the BView's FrameResized() hook. 5103 */ 5104 void 5105 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 5106 { 5107 fBounds.right += deltaWidth; 5108 fBounds.bottom += deltaHeight; 5109 5110 if (Window() == NULL) { 5111 // we're not supposed to exercise the resizing code in case 5112 // we haven't been attached to a window yet 5113 return; 5114 } 5115 5116 // layout the children 5117 if (fFlags & B_SUPPORTS_LAYOUT) { 5118 Relayout(); 5119 } else { 5120 for (BView* child = fFirstChild; child; child = child->fNextSibling) 5121 child->_ParentResizedBy(deltaWidth, deltaHeight); 5122 } 5123 5124 if (fFlags & B_FRAME_EVENTS) { 5125 BMessage resized(B_VIEW_RESIZED); 5126 resized.AddInt64("when", system_time()); 5127 resized.AddFloat("width", fBounds.Width()); 5128 resized.AddFloat("height", fBounds.Height()); 5129 5130 BMessenger target(this); 5131 target.SendMessage(&resized); 5132 } 5133 } 5134 5135 5136 /*! Relayouts the view according to its resizing mode. */ 5137 void 5138 BView::_ParentResizedBy(int32 x, int32 y) 5139 { 5140 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5141 BRect newFrame = Frame(); 5142 5143 // follow with left side 5144 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5145 newFrame.left += x; 5146 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5147 newFrame.left += x / 2; 5148 5149 // follow with right side 5150 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5151 newFrame.right += x; 5152 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5153 newFrame.right += x / 2; 5154 5155 // follow with top side 5156 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5157 newFrame.top += y; 5158 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5159 newFrame.top += y / 2; 5160 5161 // follow with bottom side 5162 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5163 newFrame.bottom += y; 5164 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5165 newFrame.bottom += y / 2; 5166 5167 if (newFrame.LeftTop() != fParentOffset) { 5168 // move view 5169 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5170 } 5171 5172 if (newFrame != Frame()) { 5173 // resize view 5174 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5175 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5176 _ResizeBy(widthDiff, heightDiff); 5177 } 5178 } 5179 5180 5181 void 5182 BView::_Activate(bool active) 5183 { 5184 WindowActivated(active); 5185 5186 for (BView* child = fFirstChild; child != NULL; 5187 child = child->fNextSibling) { 5188 child->_Activate(active); 5189 } 5190 } 5191 5192 5193 void 5194 BView::_Attach() 5195 { 5196 AttachedToWindow(); 5197 fAttached = true; 5198 5199 // after giving the view a chance to do this itself, 5200 // check for the B_PULSE_NEEDED flag and make sure the 5201 // window set's up the pulse messaging 5202 if (fOwner) { 5203 if (fFlags & B_PULSE_NEEDED) { 5204 _CheckLock(); 5205 if (fOwner->fPulseRunner == NULL) 5206 fOwner->SetPulseRate(fOwner->PulseRate()); 5207 } 5208 5209 if (!fOwner->IsHidden()) 5210 Invalidate(); 5211 } 5212 5213 for (BView* child = fFirstChild; child != NULL; 5214 child = child->fNextSibling) { 5215 // we need to check for fAttached as new views could have been 5216 // added in AttachedToWindow() - and those are already attached 5217 if (!child->fAttached) 5218 child->_Attach(); 5219 } 5220 5221 AllAttached(); 5222 } 5223 5224 5225 void 5226 BView::_Detach() 5227 { 5228 DetachedFromWindow(); 5229 fAttached = false; 5230 5231 for (BView* child = fFirstChild; child != NULL; 5232 child = child->fNextSibling) { 5233 child->_Detach(); 5234 } 5235 5236 AllDetached(); 5237 5238 if (fOwner) { 5239 _CheckLock(); 5240 5241 if (!fOwner->IsHidden()) 5242 Invalidate(); 5243 5244 // make sure our owner doesn't need us anymore 5245 5246 if (fOwner->CurrentFocus() == this) { 5247 MakeFocus(false); 5248 // MakeFocus() is virtual and might not be 5249 // passing through to the BView version, 5250 // but we need to make sure at this point 5251 // that we are not the focus view anymore. 5252 if (fOwner->CurrentFocus() == this) 5253 fOwner->_SetFocus(NULL, true); 5254 } 5255 5256 if (fOwner->fDefaultButton == this) 5257 fOwner->SetDefaultButton(NULL); 5258 5259 if (fOwner->fKeyMenuBar == this) 5260 fOwner->fKeyMenuBar = NULL; 5261 5262 if (fOwner->fLastMouseMovedView == this) 5263 fOwner->fLastMouseMovedView = NULL; 5264 5265 if (fOwner->fLastViewToken == _get_object_token_(this)) 5266 fOwner->fLastViewToken = B_NULL_TOKEN; 5267 5268 _SetOwner(NULL); 5269 } 5270 } 5271 5272 5273 void 5274 BView::_Draw(BRect updateRect) 5275 { 5276 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 5277 return; 5278 5279 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 5280 // -> View is simply not drawn at all 5281 5282 _SwitchServerCurrentView(); 5283 5284 ConvertFromScreen(&updateRect); 5285 5286 // TODO: make states robust (the hook implementation could 5287 // mess things up if it uses non-matching Push- and PopState(), 5288 // we would not be guaranteed to still have the same state on 5289 // the stack after having called Draw()) 5290 PushState(); 5291 Draw(updateRect); 5292 PopState(); 5293 Flush(); 5294 } 5295 5296 5297 void 5298 BView::_DrawAfterChildren(BRect updateRect) 5299 { 5300 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 5301 || !(Flags() & B_DRAW_ON_CHILDREN)) 5302 return; 5303 5304 _SwitchServerCurrentView(); 5305 5306 ConvertFromScreen(&updateRect); 5307 5308 // TODO: make states robust (see above) 5309 PushState(); 5310 DrawAfterChildren(updateRect); 5311 PopState(); 5312 Flush(); 5313 } 5314 5315 5316 void 5317 BView::_Pulse() 5318 { 5319 if ((Flags() & B_PULSE_NEEDED) != 0) 5320 Pulse(); 5321 5322 for (BView* child = fFirstChild; child != NULL; 5323 child = child->fNextSibling) { 5324 child->_Pulse(); 5325 } 5326 } 5327 5328 5329 void 5330 BView::_UpdateStateForRemove() 5331 { 5332 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 5333 if (!_CheckOwnerLockAndSwitchCurrent()) 5334 return; 5335 5336 fState->UpdateFrom(*fOwner->fLink); 5337 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 5338 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 5339 // 5340 // status_t code; 5341 // if (fOwner->fLink->FlushWithReply(code) == B_OK 5342 // && code == B_OK) { 5343 // fOwner->fLink->Read<BPoint>(&fParentOffset); 5344 // fOwner->fLink->Read<BRect>(&fBounds); 5345 // fState->valid_flags |= B_VIEW_FRAME_BIT; 5346 // } 5347 // } 5348 5349 // update children as well 5350 5351 for (BView* child = fFirstChild; child != NULL; 5352 child = child->fNextSibling) { 5353 if (child->fOwner) 5354 child->_UpdateStateForRemove(); 5355 } 5356 } 5357 5358 5359 inline void 5360 BView::_UpdatePattern(::pattern pattern) 5361 { 5362 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 5363 return; 5364 5365 if (fOwner) { 5366 _CheckLockAndSwitchCurrent(); 5367 5368 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 5369 fOwner->fLink->Attach< ::pattern>(pattern); 5370 5371 fState->valid_flags |= B_VIEW_PATTERN_BIT; 5372 } 5373 5374 fState->pattern = pattern; 5375 } 5376 5377 5378 void 5379 BView::_FlushIfNotInTransaction() 5380 { 5381 if (!fOwner->fInTransaction) { 5382 fOwner->Flush(); 5383 } 5384 } 5385 5386 5387 BShelf* 5388 BView::_Shelf() const 5389 { 5390 return fShelf; 5391 } 5392 5393 5394 void 5395 BView::_SetShelf(BShelf* shelf) 5396 { 5397 if (fShelf != NULL && fOwner != NULL) 5398 fOwner->RemoveHandler(fShelf); 5399 5400 fShelf = shelf; 5401 5402 if (fShelf != NULL && fOwner != NULL) 5403 fOwner->AddHandler(fShelf); 5404 } 5405 5406 5407 status_t 5408 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 5409 uint32 followFlags, uint32 options) 5410 { 5411 if (!_CheckOwnerLockAndSwitchCurrent()) 5412 return B_ERROR; 5413 5414 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 5415 5416 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 5417 fOwner->fLink->Attach<int32>(serverToken); 5418 fOwner->fLink->Attach<BRect>(srcRect); 5419 fOwner->fLink->Attach<BRect>(dstRect); 5420 fOwner->fLink->Attach<int32>(followFlags); 5421 fOwner->fLink->Attach<int32>(options); 5422 5423 status_t status = B_ERROR; 5424 fOwner->fLink->FlushWithReply(status); 5425 5426 return status; 5427 } 5428 5429 5430 bool 5431 BView::_CheckOwnerLockAndSwitchCurrent() const 5432 { 5433 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name())); 5434 5435 if (fOwner == NULL) { 5436 debugger("View method requires owner and doesn't have one."); 5437 return false; 5438 } 5439 5440 _CheckLockAndSwitchCurrent(); 5441 5442 return true; 5443 } 5444 5445 5446 bool 5447 BView::_CheckOwnerLock() const 5448 { 5449 if (fOwner) { 5450 fOwner->check_lock(); 5451 return true; 5452 } else { 5453 debugger("View method requires owner and doesn't have one."); 5454 return false; 5455 } 5456 } 5457 5458 5459 void 5460 BView::_CheckLockAndSwitchCurrent() const 5461 { 5462 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name())); 5463 5464 if (!fOwner) 5465 return; 5466 5467 fOwner->check_lock(); 5468 5469 _SwitchServerCurrentView(); 5470 } 5471 5472 5473 void 5474 BView::_CheckLock() const 5475 { 5476 if (fOwner) 5477 fOwner->check_lock(); 5478 } 5479 5480 5481 void 5482 BView::_SwitchServerCurrentView() const 5483 { 5484 int32 serverToken = _get_object_token_(this); 5485 5486 if (fOwner->fLastViewToken != serverToken) { 5487 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 5488 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 5489 fOwner->fLink->Attach<int32>(serverToken); 5490 5491 fOwner->fLastViewToken = serverToken; 5492 } 5493 } 5494 5495 5496 #if __GNUC__ == 2 5497 5498 5499 extern "C" void 5500 _ReservedView1__5BView(BView* view, BRect rect) 5501 { 5502 view->BView::DrawAfterChildren(rect); 5503 } 5504 5505 5506 extern "C" void 5507 _ReservedView2__5BView(BView* view) 5508 { 5509 // MinSize() 5510 perform_data_min_size data; 5511 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 5512 } 5513 5514 5515 extern "C" void 5516 _ReservedView3__5BView(BView* view) 5517 { 5518 // MaxSize() 5519 perform_data_max_size data; 5520 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 5521 } 5522 5523 5524 extern "C" BSize 5525 _ReservedView4__5BView(BView* view) 5526 { 5527 // PreferredSize() 5528 perform_data_preferred_size data; 5529 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 5530 return data.return_value; 5531 } 5532 5533 5534 extern "C" BAlignment 5535 _ReservedView5__5BView(BView* view) 5536 { 5537 // LayoutAlignment() 5538 perform_data_layout_alignment data; 5539 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 5540 return data.return_value; 5541 } 5542 5543 5544 extern "C" bool 5545 _ReservedView6__5BView(BView* view) 5546 { 5547 // HasHeightForWidth() 5548 perform_data_has_height_for_width data; 5549 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 5550 return data.return_value; 5551 } 5552 5553 5554 extern "C" void 5555 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 5556 float* preferred) 5557 { 5558 // GetHeightForWidth() 5559 perform_data_get_height_for_width data; 5560 data.width = width; 5561 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 5562 if (min != NULL) 5563 *min = data.min; 5564 if (max != NULL) 5565 *max = data.max; 5566 if (preferred != NULL) 5567 *preferred = data.preferred; 5568 } 5569 5570 5571 extern "C" void 5572 _ReservedView8__5BView(BView* view, BLayout* layout) 5573 { 5574 // SetLayout() 5575 perform_data_set_layout data; 5576 data.layout = layout; 5577 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 5578 } 5579 5580 5581 extern "C" void 5582 _ReservedView9__5BView(BView* view, bool descendants) 5583 { 5584 // InvalidateLayout() 5585 perform_data_invalidate_layout data; 5586 data.descendants = descendants; 5587 view->Perform(PERFORM_CODE_INVALIDATE_LAYOUT, &data); 5588 } 5589 5590 5591 extern "C" void 5592 _ReservedView10__5BView(BView* view) 5593 { 5594 // DoLayout() 5595 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 5596 } 5597 5598 5599 extern "C" bool 5600 _ReservedView11__5BView(BView* view, BPoint point, BToolTip** _toolTip) 5601 { 5602 // GetToolTipAt() 5603 perform_data_get_tool_tip_at data; 5604 data.point = point; 5605 data.tool_tip = _toolTip; 5606 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 5607 return data.return_value; 5608 } 5609 5610 5611 #elif __GNUC__ > 2 5612 5613 5614 extern "C" bool 5615 _ZN5BView15_ReservedView11Ev(BView* view, BPoint point, BToolTip** _toolTip) 5616 { 5617 // GetToolTipAt() 5618 perform_data_get_tool_tip_at data; 5619 data.point = point; 5620 data.tool_tip = _toolTip; 5621 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 5622 return data.return_value; 5623 } 5624 5625 5626 #endif // __GNUC__ > 2 5627 5628 void BView::_ReservedView12() {} 5629 void BView::_ReservedView13() {} 5630 void BView::_ReservedView14() {} 5631 void BView::_ReservedView15() {} 5632 void BView::_ReservedView16() {} 5633 5634 5635 BView::BView(const BView& other) 5636 : 5637 BHandler() 5638 { 5639 // this is private and not functional, but exported 5640 } 5641 5642 5643 BView& 5644 BView::operator=(const BView& other) 5645 { 5646 // this is private and not functional, but exported 5647 return *this; 5648 } 5649 5650 5651 void 5652 BView::_PrintToStream() 5653 { 5654 printf("BView::_PrintToStream()\n"); 5655 printf("\tName: %s\n" 5656 "\tParent: %s\n" 5657 "\tFirstChild: %s\n" 5658 "\tNextSibling: %s\n" 5659 "\tPrevSibling: %s\n" 5660 "\tOwner(Window): %s\n" 5661 "\tToken: %ld\n" 5662 "\tFlags: %ld\n" 5663 "\tView origin: (%f,%f)\n" 5664 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 5665 "\tShow level: %d\n" 5666 "\tTopView?: %s\n" 5667 "\tBPicture: %s\n" 5668 "\tVertical Scrollbar %s\n" 5669 "\tHorizontal Scrollbar %s\n" 5670 "\tIs Printing?: %s\n" 5671 "\tShelf?: %s\n" 5672 "\tEventMask: %ld\n" 5673 "\tEventOptions: %ld\n", 5674 Name(), 5675 fParent ? fParent->Name() : "NULL", 5676 fFirstChild ? fFirstChild->Name() : "NULL", 5677 fNextSibling ? fNextSibling->Name() : "NULL", 5678 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 5679 fOwner ? fOwner->Name() : "NULL", 5680 _get_object_token_(this), 5681 fFlags, 5682 fParentOffset.x, fParentOffset.y, 5683 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 5684 fShowLevel, 5685 fTopLevelView ? "YES" : "NO", 5686 fCurrentPicture? "YES" : "NULL", 5687 fVerScroller? "YES" : "NULL", 5688 fHorScroller? "YES" : "NULL", 5689 fIsPrinting? "YES" : "NO", 5690 fShelf? "YES" : "NO", 5691 fEventMask, 5692 fEventOptions); 5693 5694 printf("\tState status:\n" 5695 "\t\tLocalCoordianteSystem: (%f,%f)\n" 5696 "\t\tPenLocation: (%f,%f)\n" 5697 "\t\tPenSize: %f\n" 5698 "\t\tHighColor: [%d,%d,%d,%d]\n" 5699 "\t\tLowColor: [%d,%d,%d,%d]\n" 5700 "\t\tViewColor: [%d,%d,%d,%d]\n" 5701 "\t\tPattern: %llx\n" 5702 "\t\tDrawingMode: %d\n" 5703 "\t\tLineJoinMode: %d\n" 5704 "\t\tLineCapMode: %d\n" 5705 "\t\tMiterLimit: %f\n" 5706 "\t\tAlphaSource: %d\n" 5707 "\t\tAlphaFuntion: %d\n" 5708 "\t\tScale: %f\n" 5709 "\t\t(Print)FontAliasing: %s\n" 5710 "\t\tFont Info:\n", 5711 fState->origin.x, fState->origin.y, 5712 fState->pen_location.x, fState->pen_location.y, 5713 fState->pen_size, 5714 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 5715 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 5716 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 5717 *((uint64*)&(fState->pattern)), 5718 fState->drawing_mode, 5719 fState->line_join, 5720 fState->line_cap, 5721 fState->miter_limit, 5722 fState->alpha_source_mode, 5723 fState->alpha_function_mode, 5724 fState->scale, 5725 fState->font_aliasing? "YES" : "NO"); 5726 5727 fState->font.PrintToStream(); 5728 5729 // TODO: also print the line array. 5730 } 5731 5732 5733 void 5734 BView::_PrintTree() 5735 { 5736 int32 spaces = 2; 5737 BView* c = fFirstChild; //c = short for: current 5738 printf( "'%s'\n", Name() ); 5739 if (c != NULL) { 5740 while(true) { 5741 // action block 5742 { 5743 for (int i = 0; i < spaces; i++) 5744 printf(" "); 5745 5746 printf( "'%s'\n", c->Name() ); 5747 } 5748 5749 // go deep 5750 if (c->fFirstChild) { 5751 c = c->fFirstChild; 5752 spaces += 2; 5753 } else { 5754 // go right 5755 if (c->fNextSibling) { 5756 c = c->fNextSibling; 5757 } else { 5758 // go up 5759 while (!c->fParent->fNextSibling && c->fParent != this) { 5760 c = c->fParent; 5761 spaces -= 2; 5762 } 5763 5764 // that enough! We've reached this view. 5765 if (c->fParent == this) 5766 break; 5767 5768 c = c->fParent->fNextSibling; 5769 spaces -= 2; 5770 } 5771 } 5772 } 5773 } 5774 } 5775