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