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