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 else 4189 BHandler::MessageReceived(msg); 4190 break; 4191 } 4192 4193 case B_MOUSE_WHEEL_CHANGED: 4194 { 4195 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL); 4196 BScrollBar* vertical = ScrollBar(B_VERTICAL); 4197 if (horizontal == NULL && vertical == NULL) { 4198 // Pass the message to the next handler 4199 BHandler::MessageReceived(msg); 4200 break; 4201 } 4202 4203 float deltaX = 0.0f, deltaY = 0.0f; 4204 if (horizontal != NULL) 4205 msg->FindFloat("be:wheel_delta_x", &deltaX); 4206 if (vertical != NULL) 4207 msg->FindFloat("be:wheel_delta_y", &deltaY); 4208 4209 if (deltaX == 0.0f && deltaY == 0.0f) 4210 break; 4211 4212 float smallStep, largeStep; 4213 if (horizontal != NULL) { 4214 horizontal->GetSteps(&smallStep, &largeStep); 4215 4216 // pressing the option/command/control key scrolls faster 4217 if (modifiers() 4218 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4219 deltaX *= largeStep; 4220 } else 4221 deltaX *= smallStep * 3; 4222 4223 horizontal->SetValue(horizontal->Value() + deltaX); 4224 } 4225 4226 if (vertical != NULL) { 4227 vertical->GetSteps(&smallStep, &largeStep); 4228 4229 // pressing the option/command/control key scrolls faster 4230 if (modifiers() 4231 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4232 deltaY *= largeStep; 4233 } else 4234 deltaY *= smallStep * 3; 4235 4236 vertical->SetValue(vertical->Value() + deltaY); 4237 } 4238 break; 4239 } 4240 4241 default: 4242 BHandler::MessageReceived(msg); 4243 break; 4244 } 4245 4246 return; 4247 } 4248 4249 // Scripting message 4250 4251 BMessage replyMsg(B_REPLY); 4252 status_t err = B_BAD_SCRIPT_SYNTAX; 4253 int32 index; 4254 BMessage specifier; 4255 int32 what; 4256 const char* property; 4257 4258 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &property) != B_OK) 4259 return BHandler::MessageReceived(msg); 4260 4261 BPropertyInfo propertyInfo(sViewPropInfo); 4262 switch (propertyInfo.FindMatch(msg, index, &specifier, what, property)) { 4263 case 0: 4264 if (msg->what == B_GET_PROPERTY) { 4265 err = replyMsg.AddRect("result", Frame()); 4266 } else if (msg->what == B_SET_PROPERTY) { 4267 BRect newFrame; 4268 err = msg->FindRect("data", &newFrame); 4269 if (err == B_OK) { 4270 MoveTo(newFrame.LeftTop()); 4271 ResizeTo(newFrame.Width(), newFrame.Height()); 4272 } 4273 } 4274 break; 4275 case 1: 4276 if (msg->what == B_GET_PROPERTY) { 4277 err = replyMsg.AddBool("result", IsHidden()); 4278 } else if (msg->what == B_SET_PROPERTY) { 4279 bool newHiddenState; 4280 err = msg->FindBool("data", &newHiddenState); 4281 if (err == B_OK) { 4282 if (newHiddenState == true) 4283 Hide(); 4284 else 4285 Show(); 4286 } 4287 } 4288 break; 4289 case 2: 4290 err = replyMsg.AddInt32("result", CountChildren()); 4291 break; 4292 default: 4293 return BHandler::MessageReceived(msg); 4294 } 4295 4296 if (err != B_OK) { 4297 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4298 4299 if (err == B_BAD_SCRIPT_SYNTAX) 4300 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4301 else 4302 replyMsg.AddString("message", strerror(err)); 4303 4304 replyMsg.AddInt32("error", err); 4305 } 4306 4307 msg->SendReply(&replyMsg); 4308 } 4309 4310 4311 status_t 4312 BView::Perform(perform_code code, void* _data) 4313 { 4314 switch (code) { 4315 case PERFORM_CODE_MIN_SIZE: 4316 ((perform_data_min_size*)_data)->return_value 4317 = BView::MinSize(); 4318 return B_OK; 4319 case PERFORM_CODE_MAX_SIZE: 4320 ((perform_data_max_size*)_data)->return_value 4321 = BView::MaxSize(); 4322 return B_OK; 4323 case PERFORM_CODE_PREFERRED_SIZE: 4324 ((perform_data_preferred_size*)_data)->return_value 4325 = BView::PreferredSize(); 4326 return B_OK; 4327 case PERFORM_CODE_LAYOUT_ALIGNMENT: 4328 ((perform_data_layout_alignment*)_data)->return_value 4329 = BView::LayoutAlignment(); 4330 return B_OK; 4331 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 4332 ((perform_data_has_height_for_width*)_data)->return_value 4333 = BView::HasHeightForWidth(); 4334 return B_OK; 4335 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 4336 { 4337 perform_data_get_height_for_width* data 4338 = (perform_data_get_height_for_width*)_data; 4339 BView::GetHeightForWidth(data->width, &data->min, &data->max, 4340 &data->preferred); 4341 return B_OK; 4342 } 4343 case PERFORM_CODE_SET_LAYOUT: 4344 { 4345 perform_data_set_layout* data = (perform_data_set_layout*)_data; 4346 BView::SetLayout(data->layout); 4347 return B_OK; 4348 } 4349 case PERFORM_CODE_INVALIDATE_LAYOUT: 4350 { 4351 perform_data_invalidate_layout* data 4352 = (perform_data_invalidate_layout*)_data; 4353 BView::InvalidateLayout(data->descendants); 4354 return B_OK; 4355 } 4356 case PERFORM_CODE_DO_LAYOUT: 4357 { 4358 BView::DoLayout(); 4359 return B_OK; 4360 } 4361 case PERFORM_CODE_GET_TOOL_TIP_AT: 4362 { 4363 perform_data_get_tool_tip_at* data 4364 = (perform_data_get_tool_tip_at*)_data; 4365 data->return_value 4366 = BView::GetToolTipAt(data->point, data->tool_tip); 4367 return B_OK; 4368 } 4369 } 4370 4371 return BHandler::Perform(code, _data); 4372 } 4373 4374 4375 // #pragma mark - Layout Functions 4376 4377 4378 BSize 4379 BView::MinSize() 4380 { 4381 // TODO: make sure this works correctly when some methods are overridden 4382 float width, height; 4383 GetPreferredSize(&width, &height); 4384 4385 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 4386 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 4387 : BSize(width, height))); 4388 } 4389 4390 4391 BSize 4392 BView::MaxSize() 4393 { 4394 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 4395 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 4396 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 4397 } 4398 4399 4400 BSize 4401 BView::PreferredSize() 4402 { 4403 // TODO: make sure this works correctly when some methods are overridden 4404 float width, height; 4405 GetPreferredSize(&width, &height); 4406 4407 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 4408 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 4409 : BSize(width, height))); 4410 } 4411 4412 4413 BAlignment 4414 BView::LayoutAlignment() 4415 { 4416 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 4417 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 4418 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 4419 } 4420 4421 4422 void 4423 BView::SetExplicitMinSize(BSize size) 4424 { 4425 fLayoutData->fMinSize = size; 4426 InvalidateLayout(); 4427 } 4428 4429 4430 void 4431 BView::SetExplicitMaxSize(BSize size) 4432 { 4433 fLayoutData->fMaxSize = size; 4434 InvalidateLayout(); 4435 } 4436 4437 4438 void 4439 BView::SetExplicitPreferredSize(BSize size) 4440 { 4441 fLayoutData->fPreferredSize = size; 4442 InvalidateLayout(); 4443 } 4444 4445 4446 void 4447 BView::SetExplicitAlignment(BAlignment alignment) 4448 { 4449 fLayoutData->fAlignment = alignment; 4450 InvalidateLayout(); 4451 } 4452 4453 4454 BSize 4455 BView::ExplicitMinSize() const 4456 { 4457 return fLayoutData->fMinSize; 4458 } 4459 4460 4461 BSize 4462 BView::ExplicitMaxSize() const 4463 { 4464 return fLayoutData->fMaxSize; 4465 } 4466 4467 4468 BSize 4469 BView::ExplicitPreferredSize() const 4470 { 4471 return fLayoutData->fPreferredSize; 4472 } 4473 4474 4475 BAlignment 4476 BView::ExplicitAlignment() const 4477 { 4478 return fLayoutData->fAlignment; 4479 } 4480 4481 4482 bool 4483 BView::HasHeightForWidth() 4484 { 4485 return (fLayoutData->fLayout 4486 ? fLayoutData->fLayout->HasHeightForWidth() : false); 4487 } 4488 4489 4490 void 4491 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 4492 { 4493 if (fLayoutData->fLayout) 4494 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 4495 } 4496 4497 4498 void 4499 BView::SetLayout(BLayout* layout) 4500 { 4501 if (layout == fLayoutData->fLayout) 4502 return; 4503 4504 fFlags |= B_SUPPORTS_LAYOUT; 4505 4506 // unset and delete the old layout 4507 if (fLayoutData->fLayout) { 4508 fLayoutData->fLayout->SetView(NULL); 4509 delete fLayoutData->fLayout; 4510 } 4511 4512 fLayoutData->fLayout = layout; 4513 4514 if (fLayoutData->fLayout) { 4515 fLayoutData->fLayout->SetView(this); 4516 4517 // add all children 4518 int count = CountChildren(); 4519 for (int i = 0; i < count; i++) 4520 fLayoutData->fLayout->AddView(ChildAt(i)); 4521 } 4522 4523 InvalidateLayout(); 4524 } 4525 4526 4527 BLayout* 4528 BView::GetLayout() const 4529 { 4530 return fLayoutData->fLayout; 4531 } 4532 4533 4534 void 4535 BView::InvalidateLayout(bool descendants) 4536 { 4537 if (fLayoutData->fMinMaxValid && !fLayoutData->fLayoutInProgress 4538 && fLayoutData->fLayoutInvalidationDisabled == 0) { 4539 if (fParent && fParent->fLayoutData->fMinMaxValid) 4540 fParent->InvalidateLayout(false); 4541 4542 fLayoutData->fLayoutValid = false; 4543 fLayoutData->fMinMaxValid = false; 4544 4545 if (fLayoutData->fLayout) 4546 fLayoutData->fLayout->InvalidateLayout(); 4547 4548 if (descendants) { 4549 int count = CountChildren(); 4550 for (int i = 0; i < count; i++) 4551 ChildAt(i)->InvalidateLayout(descendants); 4552 } 4553 4554 if (fTopLevelView) { 4555 // trigger layout process 4556 if (fOwner) 4557 fOwner->PostMessage(B_LAYOUT_WINDOW); 4558 } 4559 } 4560 } 4561 4562 4563 void 4564 BView::EnableLayoutInvalidation() 4565 { 4566 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4567 fLayoutData->fLayoutInvalidationDisabled--; 4568 } 4569 4570 4571 void 4572 BView::DisableLayoutInvalidation() 4573 { 4574 fLayoutData->fLayoutInvalidationDisabled++; 4575 } 4576 4577 4578 bool 4579 BView::IsLayoutValid() const 4580 { 4581 return fLayoutData->fLayoutValid; 4582 } 4583 4584 4585 /*! \brief Service call for BLayout derived classes reenabling 4586 InvalidateLayout() notifications. 4587 BView::InvalidateLayout() invokes InvalidateLayout() on its layout the first 4588 time, but suppresses further calls until Layout()/Relayout() has been 4589 invoked. This method will reenable the notification for the next call of 4590 BView::InvalidateLayout(). 4591 4592 If the layout caches internal layout information and updates those 4593 information also in methods other than LayoutView(), it has to invoke this 4594 method, when it has done so, since otherwise the information might become 4595 obsolete without the layout noticing. 4596 */ 4597 void 4598 BView::ResetLayoutInvalidation() 4599 { 4600 fLayoutData->fMinMaxValid = true; 4601 } 4602 4603 4604 BLayoutContext* 4605 BView::LayoutContext() const 4606 { 4607 return fLayoutData->fLayoutContext; 4608 } 4609 4610 4611 void 4612 BView::Layout(bool force) 4613 { 4614 BLayoutContext context; 4615 _Layout(force, &context); 4616 } 4617 4618 4619 void 4620 BView::Relayout() 4621 { 4622 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 4623 fLayoutData->fNeedsRelayout = true; 4624 4625 // Layout() is recursive, that is if the parent view is currently laid 4626 // out, we don't call layout() on this view, but wait for the parent's 4627 // Layout() to do that for us. 4628 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 4629 Layout(false); 4630 } 4631 } 4632 4633 4634 void 4635 BView::DoLayout() 4636 { 4637 if (fLayoutData->fLayout) 4638 fLayoutData->fLayout->LayoutView(); 4639 } 4640 4641 4642 void 4643 BView::SetToolTip(const char* text) 4644 { 4645 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip)) 4646 tip->SetText(text); 4647 else 4648 SetToolTip(new BTextToolTip(text)); 4649 } 4650 4651 4652 void 4653 BView::SetToolTip(BToolTip* tip) 4654 { 4655 if (fToolTip == tip) 4656 return; 4657 4658 if (fToolTip != NULL) 4659 fToolTip->ReleaseReference(); 4660 fToolTip = tip; 4661 if (fToolTip != NULL) 4662 fToolTip->AcquireReference(); 4663 } 4664 4665 4666 BToolTip* 4667 BView::ToolTip() const 4668 { 4669 return fToolTip; 4670 } 4671 4672 4673 void 4674 BView::ShowToolTip(BToolTip* tip) 4675 { 4676 if (tip == NULL) 4677 return; 4678 4679 fVisibleToolTip = tip; 4680 4681 BPoint where; 4682 GetMouse(&where, NULL, false); 4683 4684 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where)); 4685 } 4686 4687 4688 void 4689 BView::HideToolTip() 4690 { 4691 BToolTipManager::Manager()->HideTip(); 4692 fVisibleToolTip = NULL; 4693 } 4694 4695 4696 bool 4697 BView::GetToolTipAt(BPoint point, BToolTip** _tip) 4698 { 4699 if (fVisibleToolTip != NULL) { 4700 *_tip = fVisibleToolTip; 4701 return true; 4702 } 4703 if (fToolTip != NULL) { 4704 *_tip = fToolTip; 4705 return true; 4706 } 4707 4708 *_tip = NULL; 4709 return false; 4710 } 4711 4712 4713 void 4714 BView::_Layout(bool force, BLayoutContext* context) 4715 { 4716 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 4717 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 4718 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, 4719 //fLayoutData->fLayoutInProgress); 4720 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 4721 fLayoutData->fLayoutValid = false; 4722 4723 if (fLayoutData->fLayoutInProgress) 4724 return; 4725 4726 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 4727 fLayoutData->fLayoutContext = context; 4728 4729 fLayoutData->fLayoutInProgress = true; 4730 DoLayout(); 4731 fLayoutData->fLayoutInProgress = false; 4732 4733 fLayoutData->fLayoutValid = true; 4734 fLayoutData->fMinMaxValid = true; 4735 fLayoutData->fNeedsRelayout = false; 4736 4737 // layout children 4738 int32 childCount = CountChildren(); 4739 for (int32 i = 0; i < childCount; i++) { 4740 BView* child = ChildAt(i); 4741 if (!child->IsHidden(child)) 4742 child->_Layout(force, context); 4743 } 4744 4745 fLayoutData->fLayoutContext = oldContext; 4746 4747 // invalidate the drawn content, if requested 4748 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 4749 Invalidate(); 4750 } 4751 } 4752 4753 4754 // #pragma mark - Private Functions 4755 4756 4757 void 4758 BView::_InitData(BRect frame, const char* name, uint32 resizingMode, 4759 uint32 flags) 4760 { 4761 // Info: The name of the view is set by BHandler constructor 4762 4763 STRACE(("BView::InitData: enter\n")); 4764 4765 // initialize members 4766 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 4767 printf("%s BView::InitData(): resizing mode or flags swapped\n", name); 4768 4769 // There are applications that swap the resize mask and the flags in the 4770 // BView constructor. This does not cause problems under BeOS as it just 4771 // ors the two fields to one 32bit flag. 4772 // For now we do the same but print the above warning message. 4773 // TODO: this should be removed at some point and the original 4774 // version restored: 4775 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4776 fFlags = resizingMode | flags; 4777 4778 // handle rounding 4779 frame.left = roundf(frame.left); 4780 frame.top = roundf(frame.top); 4781 frame.right = roundf(frame.right); 4782 frame.bottom = roundf(frame.bottom); 4783 4784 fParentOffset.Set(frame.left, frame.top); 4785 4786 fOwner = NULL; 4787 fParent = NULL; 4788 fNextSibling = NULL; 4789 fPreviousSibling = NULL; 4790 fFirstChild = NULL; 4791 4792 fShowLevel = 0; 4793 fTopLevelView = false; 4794 4795 fCurrentPicture = NULL; 4796 fCommArray = NULL; 4797 4798 fVerScroller = NULL; 4799 fHorScroller = NULL; 4800 4801 fIsPrinting = false; 4802 fAttached = false; 4803 4804 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 4805 // TODO: Maybe we could auto-delete those views on AddChild() instead? 4806 fState = new BPrivate::ViewState; 4807 4808 fBounds = frame.OffsetToCopy(B_ORIGIN); 4809 fShelf = NULL; 4810 4811 fEventMask = 0; 4812 fEventOptions = 0; 4813 fMouseEventOptions = 0; 4814 4815 fLayoutData = new LayoutData; 4816 4817 fToolTip = NULL; 4818 fVisibleToolTip = NULL; 4819 } 4820 4821 4822 void 4823 BView::_RemoveCommArray() 4824 { 4825 if (fCommArray) { 4826 delete [] fCommArray->array; 4827 delete fCommArray; 4828 fCommArray = NULL; 4829 } 4830 } 4831 4832 4833 void 4834 BView::_SetOwner(BWindow* newOwner) 4835 { 4836 if (!newOwner) 4837 _RemoveCommArray(); 4838 4839 if (fOwner != newOwner && fOwner) { 4840 if (fOwner->fFocus == this) 4841 MakeFocus(false); 4842 4843 if (fOwner->fLastMouseMovedView == this) 4844 fOwner->fLastMouseMovedView = NULL; 4845 4846 fOwner->RemoveHandler(this); 4847 if (fShelf) 4848 fOwner->RemoveHandler(fShelf); 4849 } 4850 4851 if (newOwner && newOwner != fOwner) { 4852 newOwner->AddHandler(this); 4853 if (fShelf) 4854 newOwner->AddHandler(fShelf); 4855 4856 if (fTopLevelView) 4857 SetNextHandler(newOwner); 4858 else 4859 SetNextHandler(fParent); 4860 } 4861 4862 fOwner = newOwner; 4863 4864 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) 4865 child->_SetOwner(newOwner); 4866 } 4867 4868 4869 void 4870 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) 4871 { 4872 if (!picture) 4873 return; 4874 4875 #if 1 4876 // TODO: Move the implementation to the server!!! 4877 // This implementation is pretty slow, since just creating an offscreen 4878 // bitmap takes a lot of time. That's the main reason why it should be moved 4879 // to the server. 4880 4881 // Here the idea is to get rid of the padding bytes in the bitmap, 4882 // as padding complicates and slows down the iteration. 4883 // TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned 4884 // to a 4 byte boundary. 4885 BRect bounds(Bounds()); 4886 if ((bounds.IntegerWidth() + 1) % 32) { 4887 bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1) 4888 * 32 - 1; 4889 } 4890 4891 // TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work. 4892 BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true); 4893 if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) { 4894 BView* view = new(std::nothrow) BView(bounds, "drawing view", 4895 B_FOLLOW_NONE, 0); 4896 if (view != NULL) { 4897 bitmap->AddChild(view); 4898 view->DrawPicture(picture, where); 4899 view->Sync(); 4900 } 4901 bitmap->Unlock(); 4902 } 4903 4904 BRegion region; 4905 int32 width = bounds.IntegerWidth() + 1; 4906 int32 height = bounds.IntegerHeight() + 1; 4907 if (bitmap != NULL && bitmap->LockBits() == B_OK) { 4908 uint32 bit = 0; 4909 uint32* bits = (uint32*)bitmap->Bits(); 4910 clipping_rect rect; 4911 4912 // TODO: A possible optimization would be adding "spans" instead 4913 // of 1x1 rects. That would probably help with very complex 4914 // BPictures 4915 for (int32 y = 0; y < height; y++) { 4916 for (int32 x = 0; x < width; x++) { 4917 bit = *bits++; 4918 if (bit != 0xFFFFFFFF) { 4919 rect.left = x; 4920 rect.right = rect.left; 4921 rect.top = rect.bottom = y; 4922 region.Include(rect); 4923 } 4924 } 4925 } 4926 bitmap->UnlockBits(); 4927 } 4928 delete bitmap; 4929 4930 if (invert) { 4931 BRegion inverseRegion; 4932 inverseRegion.Include(Bounds()); 4933 inverseRegion.Exclude(®ion); 4934 ConstrainClippingRegion(&inverseRegion); 4935 } else 4936 ConstrainClippingRegion(®ion); 4937 #else 4938 if (_CheckOwnerLockAndSwitchCurrent()) { 4939 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 4940 fOwner->fLink->Attach<int32>(picture->Token()); 4941 fOwner->fLink->Attach<BPoint>(where); 4942 fOwner->fLink->Attach<bool>(invert); 4943 4944 // TODO: I think that "sync" means another thing here: 4945 // the bebook, at least, says so. 4946 if (sync) 4947 fOwner->fLink->Flush(); 4948 4949 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 4950 } 4951 4952 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 4953 #endif 4954 } 4955 4956 4957 bool 4958 BView::_RemoveChildFromList(BView* child) 4959 { 4960 if (child->fParent != this) 4961 return false; 4962 4963 if (fFirstChild == child) { 4964 // it's the first view in the list 4965 fFirstChild = child->fNextSibling; 4966 } else { 4967 // there must be a previous sibling 4968 child->fPreviousSibling->fNextSibling = child->fNextSibling; 4969 } 4970 4971 if (child->fNextSibling) 4972 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 4973 4974 child->fParent = NULL; 4975 child->fNextSibling = NULL; 4976 child->fPreviousSibling = NULL; 4977 4978 return true; 4979 } 4980 4981 4982 bool 4983 BView::_AddChildToList(BView* child, BView* before) 4984 { 4985 if (!child) 4986 return false; 4987 if (child->fParent != NULL) { 4988 debugger("View already belongs to someone else"); 4989 return false; 4990 } 4991 if (before != NULL && before->fParent != this) { 4992 debugger("Invalid before view"); 4993 return false; 4994 } 4995 4996 if (before != NULL) { 4997 // add view before this one 4998 child->fNextSibling = before; 4999 child->fPreviousSibling = before->fPreviousSibling; 5000 if (child->fPreviousSibling != NULL) 5001 child->fPreviousSibling->fNextSibling = child; 5002 5003 before->fPreviousSibling = child; 5004 if (fFirstChild == before) 5005 fFirstChild = child; 5006 } else { 5007 // add view to the end of the list 5008 BView* last = fFirstChild; 5009 while (last != NULL && last->fNextSibling != NULL) { 5010 last = last->fNextSibling; 5011 } 5012 5013 if (last != NULL) { 5014 last->fNextSibling = child; 5015 child->fPreviousSibling = last; 5016 } else { 5017 fFirstChild = child; 5018 child->fPreviousSibling = NULL; 5019 } 5020 5021 child->fNextSibling = NULL; 5022 } 5023 5024 child->fParent = this; 5025 return true; 5026 } 5027 5028 5029 /*! \brief Creates the server counterpart of this view. 5030 This is only done for views that are part of the view hierarchy, ie. when 5031 they are attached to a window. 5032 RemoveSelf() deletes the server object again. 5033 */ 5034 bool 5035 BView::_CreateSelf() 5036 { 5037 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 5038 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 5039 // of the view and its parent are both send to the server. 5040 5041 if (fTopLevelView) 5042 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 5043 else 5044 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 5045 5046 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 5047 fOwner->fLink->AttachString(Name()); 5048 fOwner->fLink->Attach<BRect>(Frame()); 5049 fOwner->fLink->Attach<BPoint>(LeftTop()); 5050 fOwner->fLink->Attach<uint32>(ResizingMode()); 5051 fOwner->fLink->Attach<uint32>(fEventMask); 5052 fOwner->fLink->Attach<uint32>(fEventOptions); 5053 fOwner->fLink->Attach<uint32>(Flags()); 5054 fOwner->fLink->Attach<bool>(IsHidden(this)); 5055 fOwner->fLink->Attach<rgb_color>(fState->view_color); 5056 if (fTopLevelView) 5057 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 5058 else 5059 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 5060 fOwner->fLink->Flush(); 5061 5062 _CheckOwnerLockAndSwitchCurrent(); 5063 fState->UpdateServerState(*fOwner->fLink); 5064 5065 // we create all its children, too 5066 5067 for (BView* child = fFirstChild; child != NULL; 5068 child = child->fNextSibling) { 5069 child->_CreateSelf(); 5070 } 5071 5072 fOwner->fLink->Flush(); 5073 return true; 5074 } 5075 5076 5077 /*! Sets the new view position. 5078 It doesn't contact the server, though - the only case where this 5079 is called outside of MoveTo() is as reaction of moving a view 5080 in the server (a.k.a. B_WINDOW_RESIZED). 5081 It also calls the BView's FrameMoved() hook. 5082 */ 5083 void 5084 BView::_MoveTo(int32 x, int32 y) 5085 { 5086 fParentOffset.Set(x, y); 5087 5088 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 5089 BMessage moved(B_VIEW_MOVED); 5090 moved.AddInt64("when", system_time()); 5091 moved.AddPoint("where", BPoint(x, y)); 5092 5093 BMessenger target(this); 5094 target.SendMessage(&moved); 5095 } 5096 } 5097 5098 5099 /*! Computes the actual new frame size and recalculates the size of 5100 the children as well. 5101 It doesn't contact the server, though - the only case where this 5102 is called outside of ResizeBy() is as reaction of resizing a view 5103 in the server (a.k.a. B_WINDOW_RESIZED). 5104 It also calls the BView's FrameResized() hook. 5105 */ 5106 void 5107 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 5108 { 5109 fBounds.right += deltaWidth; 5110 fBounds.bottom += deltaHeight; 5111 5112 if (Window() == NULL) { 5113 // we're not supposed to exercise the resizing code in case 5114 // we haven't been attached to a window yet 5115 return; 5116 } 5117 5118 // layout the children 5119 if (fFlags & B_SUPPORTS_LAYOUT) { 5120 Relayout(); 5121 } else { 5122 for (BView* child = fFirstChild; child; child = child->fNextSibling) 5123 child->_ParentResizedBy(deltaWidth, deltaHeight); 5124 } 5125 5126 if (fFlags & B_FRAME_EVENTS) { 5127 BMessage resized(B_VIEW_RESIZED); 5128 resized.AddInt64("when", system_time()); 5129 resized.AddFloat("width", fBounds.Width()); 5130 resized.AddFloat("height", fBounds.Height()); 5131 5132 BMessenger target(this); 5133 target.SendMessage(&resized); 5134 } 5135 } 5136 5137 5138 /*! Relayouts the view according to its resizing mode. */ 5139 void 5140 BView::_ParentResizedBy(int32 x, int32 y) 5141 { 5142 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5143 BRect newFrame = Frame(); 5144 5145 // follow with left side 5146 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5147 newFrame.left += x; 5148 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5149 newFrame.left += x / 2; 5150 5151 // follow with right side 5152 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5153 newFrame.right += x; 5154 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5155 newFrame.right += x / 2; 5156 5157 // follow with top side 5158 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5159 newFrame.top += y; 5160 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5161 newFrame.top += y / 2; 5162 5163 // follow with bottom side 5164 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5165 newFrame.bottom += y; 5166 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5167 newFrame.bottom += y / 2; 5168 5169 if (newFrame.LeftTop() != fParentOffset) { 5170 // move view 5171 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5172 } 5173 5174 if (newFrame != Frame()) { 5175 // resize view 5176 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5177 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5178 _ResizeBy(widthDiff, heightDiff); 5179 } 5180 } 5181 5182 5183 void 5184 BView::_Activate(bool active) 5185 { 5186 WindowActivated(active); 5187 5188 for (BView* child = fFirstChild; child != NULL; 5189 child = child->fNextSibling) { 5190 child->_Activate(active); 5191 } 5192 } 5193 5194 5195 void 5196 BView::_Attach() 5197 { 5198 AttachedToWindow(); 5199 fAttached = true; 5200 5201 // after giving the view a chance to do this itself, 5202 // check for the B_PULSE_NEEDED flag and make sure the 5203 // window set's up the pulse messaging 5204 if (fOwner) { 5205 if (fFlags & B_PULSE_NEEDED) { 5206 _CheckLock(); 5207 if (fOwner->fPulseRunner == NULL) 5208 fOwner->SetPulseRate(fOwner->PulseRate()); 5209 } 5210 5211 if (!fOwner->IsHidden()) 5212 Invalidate(); 5213 } 5214 5215 for (BView* child = fFirstChild; child != NULL; 5216 child = child->fNextSibling) { 5217 // we need to check for fAttached as new views could have been 5218 // added in AttachedToWindow() - and those are already attached 5219 if (!child->fAttached) 5220 child->_Attach(); 5221 } 5222 5223 AllAttached(); 5224 } 5225 5226 5227 void 5228 BView::_Detach() 5229 { 5230 DetachedFromWindow(); 5231 fAttached = false; 5232 5233 for (BView* child = fFirstChild; child != NULL; 5234 child = child->fNextSibling) { 5235 child->_Detach(); 5236 } 5237 5238 AllDetached(); 5239 5240 if (fOwner) { 5241 _CheckLock(); 5242 5243 if (!fOwner->IsHidden()) 5244 Invalidate(); 5245 5246 // make sure our owner doesn't need us anymore 5247 5248 if (fOwner->CurrentFocus() == this) { 5249 MakeFocus(false); 5250 // MakeFocus() is virtual and might not be 5251 // passing through to the BView version, 5252 // but we need to make sure at this point 5253 // that we are not the focus view anymore. 5254 if (fOwner->CurrentFocus() == this) 5255 fOwner->_SetFocus(NULL, true); 5256 } 5257 5258 if (fOwner->fDefaultButton == this) 5259 fOwner->SetDefaultButton(NULL); 5260 5261 if (fOwner->fKeyMenuBar == this) 5262 fOwner->fKeyMenuBar = NULL; 5263 5264 if (fOwner->fLastMouseMovedView == this) 5265 fOwner->fLastMouseMovedView = NULL; 5266 5267 if (fOwner->fLastViewToken == _get_object_token_(this)) 5268 fOwner->fLastViewToken = B_NULL_TOKEN; 5269 5270 _SetOwner(NULL); 5271 } 5272 } 5273 5274 5275 void 5276 BView::_Draw(BRect updateRect) 5277 { 5278 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 5279 return; 5280 5281 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 5282 // -> View is simply not drawn at all 5283 5284 _SwitchServerCurrentView(); 5285 5286 ConvertFromScreen(&updateRect); 5287 5288 // TODO: make states robust (the hook implementation could 5289 // mess things up if it uses non-matching Push- and PopState(), 5290 // we would not be guaranteed to still have the same state on 5291 // the stack after having called Draw()) 5292 PushState(); 5293 Draw(updateRect); 5294 PopState(); 5295 Flush(); 5296 } 5297 5298 5299 void 5300 BView::_DrawAfterChildren(BRect updateRect) 5301 { 5302 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 5303 || !(Flags() & B_DRAW_ON_CHILDREN)) 5304 return; 5305 5306 _SwitchServerCurrentView(); 5307 5308 ConvertFromScreen(&updateRect); 5309 5310 // TODO: make states robust (see above) 5311 PushState(); 5312 DrawAfterChildren(updateRect); 5313 PopState(); 5314 Flush(); 5315 } 5316 5317 5318 void 5319 BView::_Pulse() 5320 { 5321 if ((Flags() & B_PULSE_NEEDED) != 0) 5322 Pulse(); 5323 5324 for (BView* child = fFirstChild; child != NULL; 5325 child = child->fNextSibling) { 5326 child->_Pulse(); 5327 } 5328 } 5329 5330 5331 void 5332 BView::_UpdateStateForRemove() 5333 { 5334 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 5335 if (!_CheckOwnerLockAndSwitchCurrent()) 5336 return; 5337 5338 fState->UpdateFrom(*fOwner->fLink); 5339 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 5340 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 5341 // 5342 // status_t code; 5343 // if (fOwner->fLink->FlushWithReply(code) == B_OK 5344 // && code == B_OK) { 5345 // fOwner->fLink->Read<BPoint>(&fParentOffset); 5346 // fOwner->fLink->Read<BRect>(&fBounds); 5347 // fState->valid_flags |= B_VIEW_FRAME_BIT; 5348 // } 5349 // } 5350 5351 // update children as well 5352 5353 for (BView* child = fFirstChild; child != NULL; 5354 child = child->fNextSibling) { 5355 if (child->fOwner) 5356 child->_UpdateStateForRemove(); 5357 } 5358 } 5359 5360 5361 inline void 5362 BView::_UpdatePattern(::pattern pattern) 5363 { 5364 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 5365 return; 5366 5367 if (fOwner) { 5368 _CheckLockAndSwitchCurrent(); 5369 5370 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 5371 fOwner->fLink->Attach< ::pattern>(pattern); 5372 5373 fState->valid_flags |= B_VIEW_PATTERN_BIT; 5374 } 5375 5376 fState->pattern = pattern; 5377 } 5378 5379 5380 void 5381 BView::_FlushIfNotInTransaction() 5382 { 5383 if (!fOwner->fInTransaction) { 5384 fOwner->Flush(); 5385 } 5386 } 5387 5388 5389 BShelf* 5390 BView::_Shelf() const 5391 { 5392 return fShelf; 5393 } 5394 5395 5396 void 5397 BView::_SetShelf(BShelf* shelf) 5398 { 5399 if (fShelf != NULL && fOwner != NULL) 5400 fOwner->RemoveHandler(fShelf); 5401 5402 fShelf = shelf; 5403 5404 if (fShelf != NULL && fOwner != NULL) 5405 fOwner->AddHandler(fShelf); 5406 } 5407 5408 5409 status_t 5410 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 5411 uint32 followFlags, uint32 options) 5412 { 5413 if (!_CheckOwnerLockAndSwitchCurrent()) 5414 return B_ERROR; 5415 5416 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 5417 5418 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 5419 fOwner->fLink->Attach<int32>(serverToken); 5420 fOwner->fLink->Attach<BRect>(srcRect); 5421 fOwner->fLink->Attach<BRect>(dstRect); 5422 fOwner->fLink->Attach<int32>(followFlags); 5423 fOwner->fLink->Attach<int32>(options); 5424 5425 status_t status = B_ERROR; 5426 fOwner->fLink->FlushWithReply(status); 5427 5428 return status; 5429 } 5430 5431 5432 bool 5433 BView::_CheckOwnerLockAndSwitchCurrent() const 5434 { 5435 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name())); 5436 5437 if (fOwner == NULL) { 5438 debugger("View method requires owner and doesn't have one."); 5439 return false; 5440 } 5441 5442 _CheckLockAndSwitchCurrent(); 5443 5444 return true; 5445 } 5446 5447 5448 bool 5449 BView::_CheckOwnerLock() const 5450 { 5451 if (fOwner) { 5452 fOwner->check_lock(); 5453 return true; 5454 } else { 5455 debugger("View method requires owner and doesn't have one."); 5456 return false; 5457 } 5458 } 5459 5460 5461 void 5462 BView::_CheckLockAndSwitchCurrent() const 5463 { 5464 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name())); 5465 5466 if (!fOwner) 5467 return; 5468 5469 fOwner->check_lock(); 5470 5471 _SwitchServerCurrentView(); 5472 } 5473 5474 5475 void 5476 BView::_CheckLock() const 5477 { 5478 if (fOwner) 5479 fOwner->check_lock(); 5480 } 5481 5482 5483 void 5484 BView::_SwitchServerCurrentView() const 5485 { 5486 int32 serverToken = _get_object_token_(this); 5487 5488 if (fOwner->fLastViewToken != serverToken) { 5489 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 5490 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 5491 fOwner->fLink->Attach<int32>(serverToken); 5492 5493 fOwner->fLastViewToken = serverToken; 5494 } 5495 } 5496 5497 5498 #if __GNUC__ == 2 5499 5500 5501 extern "C" void 5502 _ReservedView1__5BView(BView* view, BRect rect) 5503 { 5504 view->BView::DrawAfterChildren(rect); 5505 } 5506 5507 5508 extern "C" void 5509 _ReservedView2__5BView(BView* view) 5510 { 5511 // MinSize() 5512 perform_data_min_size data; 5513 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 5514 } 5515 5516 5517 extern "C" void 5518 _ReservedView3__5BView(BView* view) 5519 { 5520 // MaxSize() 5521 perform_data_max_size data; 5522 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 5523 } 5524 5525 5526 extern "C" BSize 5527 _ReservedView4__5BView(BView* view) 5528 { 5529 // PreferredSize() 5530 perform_data_preferred_size data; 5531 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 5532 return data.return_value; 5533 } 5534 5535 5536 extern "C" BAlignment 5537 _ReservedView5__5BView(BView* view) 5538 { 5539 // LayoutAlignment() 5540 perform_data_layout_alignment data; 5541 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 5542 return data.return_value; 5543 } 5544 5545 5546 extern "C" bool 5547 _ReservedView6__5BView(BView* view) 5548 { 5549 // HasHeightForWidth() 5550 perform_data_has_height_for_width data; 5551 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 5552 return data.return_value; 5553 } 5554 5555 5556 extern "C" void 5557 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 5558 float* preferred) 5559 { 5560 // GetHeightForWidth() 5561 perform_data_get_height_for_width data; 5562 data.width = width; 5563 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 5564 if (min != NULL) 5565 *min = data.min; 5566 if (max != NULL) 5567 *max = data.max; 5568 if (preferred != NULL) 5569 *preferred = data.preferred; 5570 } 5571 5572 5573 extern "C" void 5574 _ReservedView8__5BView(BView* view, BLayout* layout) 5575 { 5576 // SetLayout() 5577 perform_data_set_layout data; 5578 data.layout = layout; 5579 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 5580 } 5581 5582 5583 extern "C" void 5584 _ReservedView9__5BView(BView* view, bool descendants) 5585 { 5586 // InvalidateLayout() 5587 perform_data_invalidate_layout data; 5588 data.descendants = descendants; 5589 view->Perform(PERFORM_CODE_INVALIDATE_LAYOUT, &data); 5590 } 5591 5592 5593 extern "C" void 5594 _ReservedView10__5BView(BView* view) 5595 { 5596 // DoLayout() 5597 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 5598 } 5599 5600 5601 extern "C" bool 5602 _ReservedView11__5BView(BView* view, BPoint point, BToolTip** _toolTip) 5603 { 5604 // GetToolTipAt() 5605 perform_data_get_tool_tip_at data; 5606 data.point = point; 5607 data.tool_tip = _toolTip; 5608 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 5609 return data.return_value; 5610 } 5611 5612 5613 #elif __GNUC__ > 2 5614 5615 5616 extern "C" bool 5617 _ZN5BView15_ReservedView11Ev(BView* view, BPoint point, BToolTip** _toolTip) 5618 { 5619 // GetToolTipAt() 5620 perform_data_get_tool_tip_at data; 5621 data.point = point; 5622 data.tool_tip = _toolTip; 5623 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 5624 return data.return_value; 5625 } 5626 5627 5628 #endif // __GNUC__ > 2 5629 5630 void BView::_ReservedView12() {} 5631 void BView::_ReservedView13() {} 5632 void BView::_ReservedView14() {} 5633 void BView::_ReservedView15() {} 5634 void BView::_ReservedView16() {} 5635 5636 5637 BView::BView(const BView& other) 5638 : 5639 BHandler() 5640 { 5641 // this is private and not functional, but exported 5642 } 5643 5644 5645 BView& 5646 BView::operator=(const BView& other) 5647 { 5648 // this is private and not functional, but exported 5649 return *this; 5650 } 5651 5652 5653 void 5654 BView::_PrintToStream() 5655 { 5656 printf("BView::_PrintToStream()\n"); 5657 printf("\tName: %s\n" 5658 "\tParent: %s\n" 5659 "\tFirstChild: %s\n" 5660 "\tNextSibling: %s\n" 5661 "\tPrevSibling: %s\n" 5662 "\tOwner(Window): %s\n" 5663 "\tToken: %ld\n" 5664 "\tFlags: %ld\n" 5665 "\tView origin: (%f,%f)\n" 5666 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 5667 "\tShow level: %d\n" 5668 "\tTopView?: %s\n" 5669 "\tBPicture: %s\n" 5670 "\tVertical Scrollbar %s\n" 5671 "\tHorizontal Scrollbar %s\n" 5672 "\tIs Printing?: %s\n" 5673 "\tShelf?: %s\n" 5674 "\tEventMask: %ld\n" 5675 "\tEventOptions: %ld\n", 5676 Name(), 5677 fParent ? fParent->Name() : "NULL", 5678 fFirstChild ? fFirstChild->Name() : "NULL", 5679 fNextSibling ? fNextSibling->Name() : "NULL", 5680 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 5681 fOwner ? fOwner->Name() : "NULL", 5682 _get_object_token_(this), 5683 fFlags, 5684 fParentOffset.x, fParentOffset.y, 5685 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 5686 fShowLevel, 5687 fTopLevelView ? "YES" : "NO", 5688 fCurrentPicture? "YES" : "NULL", 5689 fVerScroller? "YES" : "NULL", 5690 fHorScroller? "YES" : "NULL", 5691 fIsPrinting? "YES" : "NO", 5692 fShelf? "YES" : "NO", 5693 fEventMask, 5694 fEventOptions); 5695 5696 printf("\tState status:\n" 5697 "\t\tLocalCoordianteSystem: (%f,%f)\n" 5698 "\t\tPenLocation: (%f,%f)\n" 5699 "\t\tPenSize: %f\n" 5700 "\t\tHighColor: [%d,%d,%d,%d]\n" 5701 "\t\tLowColor: [%d,%d,%d,%d]\n" 5702 "\t\tViewColor: [%d,%d,%d,%d]\n" 5703 "\t\tPattern: %llx\n" 5704 "\t\tDrawingMode: %d\n" 5705 "\t\tLineJoinMode: %d\n" 5706 "\t\tLineCapMode: %d\n" 5707 "\t\tMiterLimit: %f\n" 5708 "\t\tAlphaSource: %d\n" 5709 "\t\tAlphaFuntion: %d\n" 5710 "\t\tScale: %f\n" 5711 "\t\t(Print)FontAliasing: %s\n" 5712 "\t\tFont Info:\n", 5713 fState->origin.x, fState->origin.y, 5714 fState->pen_location.x, fState->pen_location.y, 5715 fState->pen_size, 5716 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 5717 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 5718 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 5719 *((uint64*)&(fState->pattern)), 5720 fState->drawing_mode, 5721 fState->line_join, 5722 fState->line_cap, 5723 fState->miter_limit, 5724 fState->alpha_source_mode, 5725 fState->alpha_function_mode, 5726 fState->scale, 5727 fState->font_aliasing? "YES" : "NO"); 5728 5729 fState->font.PrintToStream(); 5730 5731 // TODO: also print the line array. 5732 } 5733 5734 5735 void 5736 BView::_PrintTree() 5737 { 5738 int32 spaces = 2; 5739 BView* c = fFirstChild; //c = short for: current 5740 printf( "'%s'\n", Name() ); 5741 if (c != NULL) { 5742 while(true) { 5743 // action block 5744 { 5745 for (int i = 0; i < spaces; i++) 5746 printf(" "); 5747 5748 printf( "'%s'\n", c->Name() ); 5749 } 5750 5751 // go deep 5752 if (c->fFirstChild) { 5753 c = c->fFirstChild; 5754 spaces += 2; 5755 } else { 5756 // go right 5757 if (c->fNextSibling) { 5758 c = c->fNextSibling; 5759 } else { 5760 // go up 5761 while (!c->fParent->fNextSibling && c->fParent != this) { 5762 c = c->fParent; 5763 spaces -= 2; 5764 } 5765 5766 // that enough! We've reached this view. 5767 if (c->fParent == this) 5768 break; 5769 5770 c = c->fParent->fNextSibling; 5771 spaces -= 2; 5772 } 5773 } 5774 } 5775 } 5776 } 5777