1 /* 2 * Copyright 2001-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Adrian Oanca <adioanca@cotty.iren.ro> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Ingo Weinhold <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 // don't change the mask if it's zero and we've got options 1591 if (mask != 0 || options == 0) 1592 fEventMask = mask | (fEventMask & 0xffff0000); 1593 fEventOptions = options; 1594 1595 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT; 1596 1597 if (fOwner) { 1598 _CheckLockAndSwitchCurrent(); 1599 1600 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK); 1601 fOwner->fLink->Attach<uint32>(mask); 1602 fOwner->fLink->Attach<uint32>(options); 1603 fOwner->fLink->Flush(); 1604 } 1605 1606 return B_OK; 1607 } 1608 1609 1610 uint32 1611 BView::EventMask() 1612 { 1613 return fEventMask; 1614 } 1615 1616 1617 status_t 1618 BView::SetMouseEventMask(uint32 mask, uint32 options) 1619 { 1620 // Just don't do anything if the view is not yet attached 1621 // or we were called outside of BView::MouseDown() 1622 if (fOwner != NULL 1623 && fOwner->CurrentMessage() != NULL 1624 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) { 1625 _CheckLockAndSwitchCurrent(); 1626 fMouseEventOptions = options; 1627 1628 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK); 1629 fOwner->fLink->Attach<uint32>(mask); 1630 fOwner->fLink->Attach<uint32>(options); 1631 fOwner->fLink->Flush(); 1632 return B_OK; 1633 } 1634 1635 return B_ERROR; 1636 } 1637 1638 1639 // #pragma mark - Graphic State Functions 1640 1641 1642 void 1643 BView::PushState() 1644 { 1645 _CheckOwnerLockAndSwitchCurrent(); 1646 1647 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE); 1648 1649 // initialize origin and scale 1650 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT; 1651 fState->scale = 1.0f; 1652 fState->origin.Set(0, 0); 1653 } 1654 1655 1656 void 1657 BView::PopState() 1658 { 1659 _CheckOwnerLockAndSwitchCurrent(); 1660 1661 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE); 1662 _FlushIfNotInTransaction(); 1663 1664 // invalidate all flags (except those that are not part of pop/push) 1665 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT; 1666 } 1667 1668 1669 void 1670 BView::SetOrigin(BPoint pt) 1671 { 1672 SetOrigin(pt.x, pt.y); 1673 } 1674 1675 1676 void 1677 BView::SetOrigin(float x, float y) 1678 { 1679 if (fState->IsValid(B_VIEW_ORIGIN_BIT) 1680 && x == fState->origin.x && y == fState->origin.y) 1681 return; 1682 1683 fState->origin.x = x; 1684 fState->origin.y = y; 1685 1686 if (_CheckOwnerLockAndSwitchCurrent()) { 1687 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN); 1688 fOwner->fLink->Attach<float>(x); 1689 fOwner->fLink->Attach<float>(y); 1690 1691 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1692 } 1693 1694 // our local coord system origin has changed, so when archiving we'll add 1695 // this too 1696 fState->archiving_flags |= B_VIEW_ORIGIN_BIT; 1697 } 1698 1699 1700 BPoint 1701 BView::Origin() const 1702 { 1703 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) { 1704 // we don't keep graphics state information, therefor 1705 // we need to ask the server for the origin after PopState() 1706 _CheckOwnerLockAndSwitchCurrent(); 1707 1708 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN); 1709 1710 int32 code; 1711 if (fOwner->fLink->FlushWithReply(code) == B_OK 1712 && code == B_OK) { 1713 fOwner->fLink->Read<BPoint>(&fState->origin); 1714 1715 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1716 } 1717 } 1718 1719 return fState->origin; 1720 } 1721 1722 1723 void 1724 BView::SetScale(float scale) const 1725 { 1726 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale) 1727 return; 1728 1729 if (fOwner) { 1730 _CheckLockAndSwitchCurrent(); 1731 1732 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE); 1733 fOwner->fLink->Attach<float>(scale); 1734 1735 fState->valid_flags |= B_VIEW_SCALE_BIT; 1736 } 1737 1738 fState->scale = scale; 1739 fState->archiving_flags |= B_VIEW_SCALE_BIT; 1740 } 1741 1742 1743 float 1744 BView::Scale() const 1745 { 1746 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) { 1747 _CheckLockAndSwitchCurrent(); 1748 1749 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE); 1750 1751 int32 code; 1752 if (fOwner->fLink->FlushWithReply(code) == B_OK 1753 && code == B_OK) 1754 fOwner->fLink->Read<float>(&fState->scale); 1755 1756 fState->valid_flags |= B_VIEW_SCALE_BIT; 1757 } 1758 1759 return fState->scale; 1760 } 1761 1762 1763 void 1764 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) 1765 { 1766 if (fState->IsValid(B_VIEW_LINE_MODES_BIT) 1767 && lineCap == fState->line_cap && lineJoin == fState->line_join 1768 && miterLimit == fState->miter_limit) 1769 return; 1770 1771 if (fOwner) { 1772 _CheckLockAndSwitchCurrent(); 1773 1774 ViewSetLineModeInfo info; 1775 info.lineJoin = lineJoin; 1776 info.lineCap = lineCap; 1777 info.miterLimit = miterLimit; 1778 1779 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE); 1780 fOwner->fLink->Attach<ViewSetLineModeInfo>(info); 1781 1782 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1783 } 1784 1785 fState->line_cap = lineCap; 1786 fState->line_join = lineJoin; 1787 fState->miter_limit = miterLimit; 1788 1789 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT; 1790 } 1791 1792 1793 join_mode 1794 BView::LineJoinMode() const 1795 { 1796 // This will update the current state, if necessary 1797 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1798 LineMiterLimit(); 1799 1800 return fState->line_join; 1801 } 1802 1803 1804 cap_mode 1805 BView::LineCapMode() const 1806 { 1807 // This will update the current state, if necessary 1808 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1809 LineMiterLimit(); 1810 1811 return fState->line_cap; 1812 } 1813 1814 1815 float 1816 BView::LineMiterLimit() const 1817 { 1818 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) { 1819 _CheckLockAndSwitchCurrent(); 1820 1821 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE); 1822 1823 int32 code; 1824 if (fOwner->fLink->FlushWithReply(code) == B_OK 1825 && code == B_OK) { 1826 1827 ViewSetLineModeInfo info; 1828 fOwner->fLink->Read<ViewSetLineModeInfo>(&info); 1829 1830 fState->line_cap = info.lineCap; 1831 fState->line_join = info.lineJoin; 1832 fState->miter_limit = info.miterLimit; 1833 } 1834 1835 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1836 } 1837 1838 return fState->miter_limit; 1839 } 1840 1841 1842 void 1843 BView::SetDrawingMode(drawing_mode mode) 1844 { 1845 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT) 1846 && mode == fState->drawing_mode) 1847 return; 1848 1849 if (fOwner) { 1850 _CheckLockAndSwitchCurrent(); 1851 1852 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE); 1853 fOwner->fLink->Attach<int8>((int8)mode); 1854 1855 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1856 } 1857 1858 fState->drawing_mode = mode; 1859 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT; 1860 } 1861 1862 1863 drawing_mode 1864 BView::DrawingMode() const 1865 { 1866 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) { 1867 _CheckLockAndSwitchCurrent(); 1868 1869 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE); 1870 1871 int32 code; 1872 if (fOwner->fLink->FlushWithReply(code) == B_OK 1873 && code == B_OK) { 1874 int8 drawingMode; 1875 fOwner->fLink->Read<int8>(&drawingMode); 1876 1877 fState->drawing_mode = (drawing_mode)drawingMode; 1878 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1879 } 1880 } 1881 1882 return fState->drawing_mode; 1883 } 1884 1885 1886 void 1887 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction) 1888 { 1889 if (fState->IsValid(B_VIEW_BLENDING_BIT) 1890 && sourceAlpha == fState->alpha_source_mode 1891 && alphaFunction == fState->alpha_function_mode) 1892 return; 1893 1894 if (fOwner) { 1895 _CheckLockAndSwitchCurrent(); 1896 1897 ViewBlendingModeInfo info; 1898 info.sourceAlpha = sourceAlpha; 1899 info.alphaFunction = alphaFunction; 1900 1901 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE); 1902 fOwner->fLink->Attach<ViewBlendingModeInfo>(info); 1903 1904 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1905 } 1906 1907 fState->alpha_source_mode = sourceAlpha; 1908 fState->alpha_function_mode = alphaFunction; 1909 1910 fState->archiving_flags |= B_VIEW_BLENDING_BIT; 1911 } 1912 1913 1914 void 1915 BView::GetBlendingMode(source_alpha *_sourceAlpha, 1916 alpha_function *_alphaFunction) const 1917 { 1918 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) { 1919 _CheckLockAndSwitchCurrent(); 1920 1921 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE); 1922 1923 int32 code; 1924 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 1925 ViewBlendingModeInfo info; 1926 fOwner->fLink->Read<ViewBlendingModeInfo>(&info); 1927 1928 fState->alpha_source_mode = info.sourceAlpha; 1929 fState->alpha_function_mode = info.alphaFunction; 1930 1931 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1932 } 1933 } 1934 1935 if (_sourceAlpha) 1936 *_sourceAlpha = fState->alpha_source_mode; 1937 1938 if (_alphaFunction) 1939 *_alphaFunction = fState->alpha_function_mode; 1940 } 1941 1942 1943 void 1944 BView::MovePenTo(BPoint point) 1945 { 1946 MovePenTo(point.x, point.y); 1947 } 1948 1949 1950 void 1951 BView::MovePenTo(float x, float y) 1952 { 1953 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT) 1954 && x == fState->pen_location.x && y == fState->pen_location.y) 1955 return; 1956 1957 if (fOwner) { 1958 _CheckLockAndSwitchCurrent(); 1959 1960 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC); 1961 fOwner->fLink->Attach<BPoint>(BPoint(x, y)); 1962 1963 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 1964 } 1965 1966 fState->pen_location.x = x; 1967 fState->pen_location.y = y; 1968 1969 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT; 1970 } 1971 1972 1973 void 1974 BView::MovePenBy(float x, float y) 1975 { 1976 // this will update the pen location if necessary 1977 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT)) 1978 PenLocation(); 1979 1980 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y); 1981 } 1982 1983 1984 BPoint 1985 BView::PenLocation() const 1986 { 1987 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) { 1988 _CheckLockAndSwitchCurrent(); 1989 1990 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC); 1991 1992 int32 code; 1993 if (fOwner->fLink->FlushWithReply(code) == B_OK 1994 && code == B_OK) { 1995 fOwner->fLink->Read<BPoint>(&fState->pen_location); 1996 1997 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 1998 } 1999 } 2000 2001 return fState->pen_location; 2002 } 2003 2004 2005 void 2006 BView::SetPenSize(float size) 2007 { 2008 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size) 2009 return; 2010 2011 if (fOwner) { 2012 _CheckLockAndSwitchCurrent(); 2013 2014 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE); 2015 fOwner->fLink->Attach<float>(size); 2016 2017 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2018 } 2019 2020 fState->pen_size = size; 2021 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT; 2022 } 2023 2024 2025 float 2026 BView::PenSize() const 2027 { 2028 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) { 2029 _CheckLockAndSwitchCurrent(); 2030 2031 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE); 2032 2033 int32 code; 2034 if (fOwner->fLink->FlushWithReply(code) == B_OK 2035 && code == B_OK) { 2036 fOwner->fLink->Read<float>(&fState->pen_size); 2037 2038 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2039 } 2040 } 2041 2042 return fState->pen_size; 2043 } 2044 2045 2046 void 2047 BView::SetHighColor(rgb_color color) 2048 { 2049 // are we up-to-date already? 2050 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT) 2051 && fState->high_color == color) 2052 return; 2053 2054 if (fOwner) { 2055 _CheckLockAndSwitchCurrent(); 2056 2057 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR); 2058 fOwner->fLink->Attach<rgb_color>(color); 2059 2060 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2061 } 2062 2063 fState->high_color = color; 2064 2065 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT; 2066 } 2067 2068 2069 rgb_color 2070 BView::HighColor() const 2071 { 2072 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) { 2073 _CheckLockAndSwitchCurrent(); 2074 2075 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR); 2076 2077 int32 code; 2078 if (fOwner->fLink->FlushWithReply(code) == B_OK 2079 && code == B_OK) { 2080 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2081 2082 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2083 } 2084 } 2085 2086 return fState->high_color; 2087 } 2088 2089 2090 void 2091 BView::SetLowColor(rgb_color color) 2092 { 2093 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT) 2094 && fState->low_color == color) 2095 return; 2096 2097 if (fOwner) { 2098 _CheckLockAndSwitchCurrent(); 2099 2100 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR); 2101 fOwner->fLink->Attach<rgb_color>(color); 2102 2103 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2104 } 2105 2106 fState->low_color = color; 2107 2108 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT; 2109 } 2110 2111 2112 rgb_color 2113 BView::LowColor() const 2114 { 2115 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) { 2116 _CheckLockAndSwitchCurrent(); 2117 2118 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR); 2119 2120 int32 code; 2121 if (fOwner->fLink->FlushWithReply(code) == B_OK 2122 && code == B_OK) { 2123 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2124 2125 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2126 } 2127 } 2128 2129 return fState->low_color; 2130 } 2131 2132 2133 void 2134 BView::SetViewColor(rgb_color color) 2135 { 2136 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color) 2137 return; 2138 2139 if (fOwner) { 2140 _CheckLockAndSwitchCurrent(); 2141 2142 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR); 2143 fOwner->fLink->Attach<rgb_color>(color); 2144 fOwner->fLink->Flush(); 2145 2146 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2147 } 2148 2149 fState->view_color = color; 2150 2151 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT; 2152 } 2153 2154 2155 rgb_color 2156 BView::ViewColor() const 2157 { 2158 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) { 2159 _CheckLockAndSwitchCurrent(); 2160 2161 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR); 2162 2163 int32 code; 2164 if (fOwner->fLink->FlushWithReply(code) == B_OK 2165 && code == B_OK) { 2166 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2167 2168 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2169 } 2170 } 2171 2172 return fState->view_color; 2173 } 2174 2175 2176 void 2177 BView::ForceFontAliasing(bool enable) 2178 { 2179 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) 2180 && enable == fState->font_aliasing) 2181 return; 2182 2183 if (fOwner) { 2184 _CheckLockAndSwitchCurrent(); 2185 2186 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING); 2187 fOwner->fLink->Attach<bool>(enable); 2188 2189 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT; 2190 } 2191 2192 fState->font_aliasing = enable; 2193 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT; 2194 } 2195 2196 2197 void 2198 BView::SetFont(const BFont* font, uint32 mask) 2199 { 2200 if (!font || mask == 0) 2201 return; 2202 2203 if (mask == B_FONT_ALL) { 2204 fState->font = *font; 2205 } else { 2206 // ToDo: move this into a BFont method 2207 if (mask & B_FONT_FAMILY_AND_STYLE) 2208 fState->font.SetFamilyAndStyle(font->FamilyAndStyle()); 2209 2210 if (mask & B_FONT_SIZE) 2211 fState->font.SetSize(font->Size()); 2212 2213 if (mask & B_FONT_SHEAR) 2214 fState->font.SetShear(font->Shear()); 2215 2216 if (mask & B_FONT_ROTATION) 2217 fState->font.SetRotation(font->Rotation()); 2218 2219 if (mask & B_FONT_FALSE_BOLD_WIDTH) 2220 fState->font.SetFalseBoldWidth(font->FalseBoldWidth()); 2221 2222 if (mask & B_FONT_SPACING) 2223 fState->font.SetSpacing(font->Spacing()); 2224 2225 if (mask & B_FONT_ENCODING) 2226 fState->font.SetEncoding(font->Encoding()); 2227 2228 if (mask & B_FONT_FACE) 2229 fState->font.SetFace(font->Face()); 2230 2231 if (mask & B_FONT_FLAGS) 2232 fState->font.SetFlags(font->Flags()); 2233 } 2234 2235 fState->font_flags |= mask; 2236 2237 if (fOwner) { 2238 _CheckLockAndSwitchCurrent(); 2239 2240 fState->UpdateServerFontState(*fOwner->fLink); 2241 } 2242 2243 // TODO: InvalidateLayout() here for convenience? 2244 } 2245 2246 2247 void 2248 BView::GetFont(BFont *font) const 2249 { 2250 *font = fState->font; 2251 } 2252 2253 2254 void 2255 BView::GetFontHeight(font_height *height) const 2256 { 2257 fState->font.GetHeight(height); 2258 } 2259 2260 2261 void 2262 BView::SetFontSize(float size) 2263 { 2264 BFont font; 2265 font.SetSize(size); 2266 2267 SetFont(&font, B_FONT_SIZE); 2268 } 2269 2270 2271 float 2272 BView::StringWidth(const char *string) const 2273 { 2274 return fState->font.StringWidth(string); 2275 } 2276 2277 2278 float 2279 BView::StringWidth(const char* string, int32 length) const 2280 { 2281 return fState->font.StringWidth(string, length); 2282 } 2283 2284 2285 void 2286 BView::GetStringWidths(char *stringArray[],int32 lengthArray[], 2287 int32 numStrings, float widthArray[]) const 2288 { 2289 fState->font.GetStringWidths(const_cast<const char **>(stringArray), 2290 const_cast<const int32 *>(lengthArray), numStrings, widthArray); 2291 } 2292 2293 2294 void 2295 BView::TruncateString(BString *in_out, uint32 mode, float width) const 2296 { 2297 fState->font.TruncateString(in_out, mode, width); 2298 } 2299 2300 2301 void 2302 BView::ClipToPicture(BPicture *picture, BPoint where, bool sync) 2303 { 2304 _ClipToPicture(picture, where, false, sync); 2305 } 2306 2307 2308 void 2309 BView::ClipToInversePicture(BPicture *picture, 2310 BPoint where, bool sync) 2311 { 2312 _ClipToPicture(picture, where, true, sync); 2313 } 2314 2315 2316 void 2317 BView::GetClippingRegion(BRegion* region) const 2318 { 2319 if (!region) 2320 return; 2321 2322 // NOTE: the client has no idea when the clipping in the server 2323 // changed, so it is always read from the server 2324 region->MakeEmpty(); 2325 2326 2327 if (fOwner) { 2328 if (fIsPrinting && _CheckOwnerLock()) { 2329 region->Set(fState->print_rect); 2330 return; 2331 } 2332 2333 _CheckLockAndSwitchCurrent(); 2334 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION); 2335 2336 int32 code; 2337 if (fOwner->fLink->FlushWithReply(code) == B_OK 2338 && code == B_OK) { 2339 fOwner->fLink->ReadRegion(region); 2340 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT; 2341 } 2342 } 2343 } 2344 2345 2346 void 2347 BView::ConstrainClippingRegion(BRegion* region) 2348 { 2349 if (_CheckOwnerLockAndSwitchCurrent()) { 2350 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION); 2351 2352 if (region) { 2353 int32 count = region->CountRects(); 2354 fOwner->fLink->Attach<int32>(count); 2355 if (count > 0) 2356 fOwner->fLink->AttachRegion(*region); 2357 } else { 2358 fOwner->fLink->Attach<int32>(-1); 2359 // '-1' means that in the app_server, there won't be any 'local' 2360 // clipping region (it will be NULL) 2361 } 2362 2363 _FlushIfNotInTransaction(); 2364 2365 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 2366 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 2367 } 2368 } 2369 2370 2371 // #pragma mark - Drawing Functions 2372 2373 2374 void 2375 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 2376 uint32 options) 2377 { 2378 if (bitmap == NULL || fOwner == NULL 2379 || !bitmapRect.IsValid() || !viewRect.IsValid()) 2380 return; 2381 2382 _CheckLockAndSwitchCurrent(); 2383 2384 ViewDrawBitmapInfo info; 2385 info.bitmapToken = bitmap->_ServerToken(); 2386 info.options = options; 2387 info.viewRect = viewRect; 2388 info.bitmapRect = bitmapRect; 2389 2390 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 2391 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 2392 2393 _FlushIfNotInTransaction(); 2394 } 2395 2396 2397 void 2398 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 2399 { 2400 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 2401 } 2402 2403 2404 void 2405 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect) 2406 { 2407 if (bitmap && fOwner) { 2408 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), 2409 viewRect, 0); 2410 } 2411 } 2412 2413 2414 void 2415 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where) 2416 { 2417 if (bitmap == NULL || fOwner == NULL) 2418 return; 2419 2420 _CheckLockAndSwitchCurrent(); 2421 2422 ViewDrawBitmapInfo info; 2423 info.bitmapToken = bitmap->_ServerToken(); 2424 info.options = 0; 2425 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN); 2426 info.viewRect = info.bitmapRect.OffsetToCopy(where); 2427 2428 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 2429 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 2430 2431 _FlushIfNotInTransaction(); 2432 } 2433 2434 2435 void 2436 BView::DrawBitmapAsync(const BBitmap* bitmap) 2437 { 2438 DrawBitmapAsync(bitmap, PenLocation()); 2439 } 2440 2441 2442 void 2443 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 2444 uint32 options) 2445 { 2446 if (fOwner) { 2447 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options); 2448 Sync(); 2449 } 2450 } 2451 2452 2453 void 2454 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 2455 { 2456 if (fOwner) { 2457 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 2458 Sync(); 2459 } 2460 } 2461 2462 2463 void 2464 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect) 2465 { 2466 if (bitmap && fOwner) { 2467 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect, 2468 0); 2469 } 2470 } 2471 2472 2473 void 2474 BView::DrawBitmap(const BBitmap* bitmap, BPoint where) 2475 { 2476 if (fOwner) { 2477 DrawBitmapAsync(bitmap, where); 2478 Sync(); 2479 } 2480 } 2481 2482 2483 void 2484 BView::DrawBitmap(const BBitmap* bitmap) 2485 { 2486 DrawBitmap(bitmap, PenLocation()); 2487 } 2488 2489 2490 void 2491 BView::DrawChar(char c) 2492 { 2493 DrawString(&c, 1, PenLocation()); 2494 } 2495 2496 2497 void 2498 BView::DrawChar(char c, BPoint location) 2499 { 2500 DrawString(&c, 1, location); 2501 } 2502 2503 2504 void 2505 BView::DrawString(const char *string, escapement_delta *delta) 2506 { 2507 if (string == NULL) 2508 return; 2509 2510 DrawString(string, strlen(string), PenLocation(), delta); 2511 } 2512 2513 2514 void 2515 BView::DrawString(const char *string, BPoint location, escapement_delta *delta) 2516 { 2517 if (string == NULL) 2518 return; 2519 2520 DrawString(string, strlen(string), location, delta); 2521 } 2522 2523 2524 void 2525 BView::DrawString(const char *string, int32 length, escapement_delta *delta) 2526 { 2527 DrawString(string, length, PenLocation(), delta); 2528 } 2529 2530 2531 void 2532 BView::DrawString(const char* string, int32 length, BPoint location, 2533 escapement_delta* delta) 2534 { 2535 if (fOwner == NULL || string == NULL || length < 1) 2536 return; 2537 2538 _CheckLockAndSwitchCurrent(); 2539 2540 ViewDrawStringInfo info; 2541 info.stringLength = length; 2542 info.location = location; 2543 if (delta != NULL) 2544 info.delta = *delta; 2545 2546 // quite often delta will be NULL 2547 if (delta) 2548 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA); 2549 else 2550 fOwner->fLink->StartMessage(AS_DRAW_STRING); 2551 2552 fOwner->fLink->Attach<ViewDrawStringInfo>(info); 2553 fOwner->fLink->Attach(string, length); 2554 2555 _FlushIfNotInTransaction(); 2556 2557 // this modifies our pen location, so we invalidate the flag. 2558 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 2559 } 2560 2561 2562 void 2563 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, 2564 ::pattern pattern) 2565 { 2566 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, 2567 center.x + xRadius, center.y + yRadius), pattern); 2568 } 2569 2570 2571 void 2572 BView::StrokeEllipse(BRect rect, ::pattern pattern) 2573 { 2574 if (fOwner == NULL) 2575 return; 2576 2577 _CheckLockAndSwitchCurrent(); 2578 _UpdatePattern(pattern); 2579 2580 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE); 2581 fOwner->fLink->Attach<BRect>(rect); 2582 2583 _FlushIfNotInTransaction(); 2584 } 2585 2586 2587 void 2588 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2589 ::pattern pattern) 2590 { 2591 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2592 center.x + xRadius, center.y + yRadius), pattern); 2593 } 2594 2595 2596 void 2597 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2598 const BGradient& gradient) 2599 { 2600 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2601 center.x + xRadius, center.y + yRadius), gradient); 2602 } 2603 2604 2605 void 2606 BView::FillEllipse(BRect rect, ::pattern pattern) 2607 { 2608 if (fOwner == NULL) 2609 return; 2610 2611 _CheckLockAndSwitchCurrent(); 2612 _UpdatePattern(pattern); 2613 2614 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE); 2615 fOwner->fLink->Attach<BRect>(rect); 2616 2617 _FlushIfNotInTransaction(); 2618 } 2619 2620 2621 void 2622 BView::FillEllipse(BRect rect, const BGradient& gradient) 2623 { 2624 if (fOwner == NULL) 2625 return; 2626 2627 _CheckLockAndSwitchCurrent(); 2628 2629 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT); 2630 fOwner->fLink->Attach<BRect>(rect); 2631 fOwner->fLink->AttachGradient(gradient); 2632 2633 _FlushIfNotInTransaction(); 2634 } 2635 2636 2637 void 2638 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle, 2639 float arcAngle, ::pattern pattern) 2640 { 2641 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2642 center.y + yRadius), startAngle, arcAngle, pattern); 2643 } 2644 2645 2646 void 2647 BView::StrokeArc(BRect rect, float startAngle, float arcAngle, 2648 ::pattern pattern) 2649 { 2650 if (fOwner == NULL) 2651 return; 2652 2653 _CheckLockAndSwitchCurrent(); 2654 _UpdatePattern(pattern); 2655 2656 fOwner->fLink->StartMessage(AS_STROKE_ARC); 2657 fOwner->fLink->Attach<BRect>(rect); 2658 fOwner->fLink->Attach<float>(startAngle); 2659 fOwner->fLink->Attach<float>(arcAngle); 2660 2661 _FlushIfNotInTransaction(); 2662 } 2663 2664 2665 void 2666 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 2667 float arcAngle, ::pattern pattern) 2668 { 2669 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2670 center.y + yRadius), startAngle, arcAngle, pattern); 2671 } 2672 2673 2674 void 2675 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 2676 float arcAngle, const BGradient& gradient) 2677 { 2678 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2679 center.y + yRadius), startAngle, arcAngle, gradient); 2680 } 2681 2682 2683 void 2684 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2685 ::pattern pattern) 2686 { 2687 if (fOwner == NULL) 2688 return; 2689 2690 _CheckLockAndSwitchCurrent(); 2691 _UpdatePattern(pattern); 2692 2693 fOwner->fLink->StartMessage(AS_FILL_ARC); 2694 fOwner->fLink->Attach<BRect>(rect); 2695 fOwner->fLink->Attach<float>(startAngle); 2696 fOwner->fLink->Attach<float>(arcAngle); 2697 2698 _FlushIfNotInTransaction(); 2699 } 2700 2701 2702 void 2703 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2704 const BGradient& gradient) 2705 { 2706 if (fOwner == NULL) 2707 return; 2708 2709 _CheckLockAndSwitchCurrent(); 2710 2711 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT); 2712 fOwner->fLink->Attach<BRect>(rect); 2713 fOwner->fLink->Attach<float>(startAngle); 2714 fOwner->fLink->Attach<float>(arcAngle); 2715 fOwner->fLink->AttachGradient(gradient); 2716 2717 _FlushIfNotInTransaction(); 2718 } 2719 2720 2721 void 2722 BView::StrokeBezier(BPoint *controlPoints, ::pattern pattern) 2723 { 2724 if (fOwner == NULL) 2725 return; 2726 2727 _CheckLockAndSwitchCurrent(); 2728 _UpdatePattern(pattern); 2729 2730 fOwner->fLink->StartMessage(AS_STROKE_BEZIER); 2731 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2732 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2733 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2734 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2735 2736 _FlushIfNotInTransaction(); 2737 } 2738 2739 2740 void 2741 BView::FillBezier(BPoint *controlPoints, ::pattern pattern) 2742 { 2743 if (fOwner == NULL) 2744 return; 2745 2746 _CheckLockAndSwitchCurrent(); 2747 _UpdatePattern(pattern); 2748 2749 fOwner->fLink->StartMessage(AS_FILL_BEZIER); 2750 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2751 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2752 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2753 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2754 2755 _FlushIfNotInTransaction(); 2756 } 2757 2758 2759 void 2760 BView::FillBezier(BPoint *controlPoints, const BGradient& gradient) 2761 { 2762 if (fOwner == NULL) 2763 return; 2764 2765 _CheckLockAndSwitchCurrent(); 2766 2767 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT); 2768 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2769 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2770 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2771 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2772 fOwner->fLink->AttachGradient(gradient); 2773 2774 _FlushIfNotInTransaction(); 2775 } 2776 2777 2778 void 2779 BView::StrokePolygon(const BPolygon *polygon, bool closed, ::pattern pattern) 2780 { 2781 if (!polygon) 2782 return; 2783 2784 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, 2785 pattern); 2786 } 2787 2788 2789 void 2790 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed, 2791 ::pattern pattern) 2792 { 2793 BPolygon polygon(pointArray, numPoints); 2794 2795 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, 2796 pattern); 2797 } 2798 2799 2800 void 2801 BView::StrokePolygon(const BPoint *ptArray, int32 numPoints, BRect bounds, 2802 bool closed, ::pattern pattern) 2803 { 2804 if (!ptArray 2805 || numPoints <= 1 2806 || fOwner == NULL) 2807 return; 2808 2809 _CheckLockAndSwitchCurrent(); 2810 _UpdatePattern(pattern); 2811 2812 BPolygon polygon(ptArray, numPoints); 2813 polygon.MapTo(polygon.Frame(), bounds); 2814 2815 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON, 2816 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) 2817 + sizeof(int32)) == B_OK) { 2818 fOwner->fLink->Attach<BRect>(polygon.Frame()); 2819 fOwner->fLink->Attach<bool>(closed); 2820 fOwner->fLink->Attach<int32>(polygon.fCount); 2821 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint)); 2822 2823 _FlushIfNotInTransaction(); 2824 } else { 2825 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2826 } 2827 } 2828 2829 2830 void 2831 BView::FillPolygon(const BPolygon *polygon, ::pattern pattern) 2832 { 2833 if (polygon == NULL 2834 || polygon->fCount <= 2 2835 || fOwner == NULL) 2836 return; 2837 2838 _CheckLockAndSwitchCurrent(); 2839 _UpdatePattern(pattern); 2840 2841 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON, 2842 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 2843 == B_OK) { 2844 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2845 fOwner->fLink->Attach<int32>(polygon->fCount); 2846 fOwner->fLink->Attach(polygon->fPoints, 2847 polygon->fCount * sizeof(BPoint)); 2848 2849 _FlushIfNotInTransaction(); 2850 } else { 2851 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2852 } 2853 } 2854 2855 2856 void 2857 BView::FillPolygon(const BPolygon *polygon, const BGradient& gradient) 2858 { 2859 if (polygon == NULL 2860 || polygon->fCount <= 2 2861 || fOwner == NULL) 2862 return; 2863 2864 _CheckLockAndSwitchCurrent(); 2865 2866 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT, 2867 polygon->fCount * sizeof(BPoint) 2868 + sizeof(BRect) + sizeof(int32)) == B_OK) { 2869 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2870 fOwner->fLink->Attach<int32>(polygon->fCount); 2871 fOwner->fLink->Attach(polygon->fPoints, 2872 polygon->fCount * sizeof(BPoint)); 2873 fOwner->fLink->AttachGradient(gradient); 2874 2875 _FlushIfNotInTransaction(); 2876 } else { 2877 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2878 } 2879 } 2880 2881 2882 void 2883 BView::FillPolygon(const BPoint *ptArray, int32 numPts, ::pattern pattern) 2884 { 2885 if (!ptArray) 2886 return; 2887 2888 BPolygon polygon(ptArray, numPts); 2889 FillPolygon(&polygon, pattern); 2890 } 2891 2892 2893 void 2894 BView::FillPolygon(const BPoint *ptArray, int32 numPts, 2895 const BGradient& gradient) 2896 { 2897 if (!ptArray) 2898 return; 2899 2900 BPolygon polygon(ptArray, numPts); 2901 FillPolygon(&polygon, gradient); 2902 } 2903 2904 2905 void 2906 BView::FillPolygon(const BPoint *ptArray, int32 numPts, BRect bounds, 2907 pattern p) 2908 { 2909 if (!ptArray) 2910 return; 2911 2912 BPolygon polygon(ptArray, numPts); 2913 2914 polygon.MapTo(polygon.Frame(), bounds); 2915 FillPolygon(&polygon, p); 2916 } 2917 2918 2919 void 2920 BView::FillPolygon(const BPoint *ptArray, int32 numPts, BRect bounds, 2921 const BGradient& gradient) 2922 { 2923 if (!ptArray) 2924 return; 2925 2926 BPolygon polygon(ptArray, numPts); 2927 2928 polygon.MapTo(polygon.Frame(), bounds); 2929 FillPolygon(&polygon, gradient); 2930 } 2931 2932 2933 void 2934 BView::StrokeRect(BRect rect, ::pattern pattern) 2935 { 2936 if (fOwner == NULL) 2937 return; 2938 2939 _CheckLockAndSwitchCurrent(); 2940 _UpdatePattern(pattern); 2941 2942 fOwner->fLink->StartMessage(AS_STROKE_RECT); 2943 fOwner->fLink->Attach<BRect>(rect); 2944 2945 _FlushIfNotInTransaction(); 2946 } 2947 2948 2949 void 2950 BView::FillRect(BRect rect, ::pattern pattern) 2951 { 2952 if (fOwner == NULL) 2953 return; 2954 2955 // NOTE: ensuring compatibility with R5, 2956 // invalid rects are not filled, they are stroked though! 2957 if (!rect.IsValid()) 2958 return; 2959 2960 _CheckLockAndSwitchCurrent(); 2961 _UpdatePattern(pattern); 2962 2963 fOwner->fLink->StartMessage(AS_FILL_RECT); 2964 fOwner->fLink->Attach<BRect>(rect); 2965 2966 _FlushIfNotInTransaction(); 2967 } 2968 2969 2970 void 2971 BView::FillRect(BRect rect, const BGradient& gradient) 2972 { 2973 if (fOwner == NULL) 2974 return; 2975 2976 // NOTE: ensuring compatibility with R5, 2977 // invalid rects are not filled, they are stroked though! 2978 if (!rect.IsValid()) 2979 return; 2980 2981 _CheckLockAndSwitchCurrent(); 2982 2983 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT); 2984 fOwner->fLink->Attach<BRect>(rect); 2985 fOwner->fLink->AttachGradient(gradient); 2986 2987 _FlushIfNotInTransaction(); 2988 } 2989 2990 2991 void 2992 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius, 2993 ::pattern pattern) 2994 { 2995 if (fOwner == NULL) 2996 return; 2997 2998 _CheckLockAndSwitchCurrent(); 2999 _UpdatePattern(pattern); 3000 3001 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT); 3002 fOwner->fLink->Attach<BRect>(rect); 3003 fOwner->fLink->Attach<float>(xRadius); 3004 fOwner->fLink->Attach<float>(yRadius); 3005 3006 _FlushIfNotInTransaction(); 3007 } 3008 3009 3010 void 3011 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3012 ::pattern pattern) 3013 { 3014 if (fOwner == NULL) 3015 return; 3016 3017 _CheckLockAndSwitchCurrent(); 3018 3019 _UpdatePattern(pattern); 3020 3021 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT); 3022 fOwner->fLink->Attach<BRect>(rect); 3023 fOwner->fLink->Attach<float>(xRadius); 3024 fOwner->fLink->Attach<float>(yRadius); 3025 3026 _FlushIfNotInTransaction(); 3027 } 3028 3029 3030 void 3031 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3032 const BGradient& gradient) 3033 { 3034 if (fOwner == NULL) 3035 return; 3036 3037 _CheckLockAndSwitchCurrent(); 3038 3039 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT); 3040 fOwner->fLink->Attach<BRect>(rect); 3041 fOwner->fLink->Attach<float>(xRadius); 3042 fOwner->fLink->Attach<float>(yRadius); 3043 fOwner->fLink->AttachGradient(gradient); 3044 3045 _FlushIfNotInTransaction(); 3046 } 3047 3048 3049 void 3050 BView::FillRegion(BRegion *region, ::pattern pattern) 3051 { 3052 if (region == NULL || fOwner == NULL) 3053 return; 3054 3055 _CheckLockAndSwitchCurrent(); 3056 3057 _UpdatePattern(pattern); 3058 3059 fOwner->fLink->StartMessage(AS_FILL_REGION); 3060 fOwner->fLink->AttachRegion(*region); 3061 3062 _FlushIfNotInTransaction(); 3063 } 3064 3065 3066 void 3067 BView::FillRegion(BRegion *region, const BGradient& gradient) 3068 { 3069 if (region == NULL || fOwner == NULL) 3070 return; 3071 3072 _CheckLockAndSwitchCurrent(); 3073 3074 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT); 3075 fOwner->fLink->AttachRegion(*region); 3076 fOwner->fLink->AttachGradient(gradient); 3077 3078 _FlushIfNotInTransaction(); 3079 } 3080 3081 3082 void 3083 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds, 3084 ::pattern pattern) 3085 { 3086 if (fOwner == NULL) 3087 return; 3088 3089 _CheckLockAndSwitchCurrent(); 3090 3091 _UpdatePattern(pattern); 3092 3093 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE); 3094 fOwner->fLink->Attach<BPoint>(pt1); 3095 fOwner->fLink->Attach<BPoint>(pt2); 3096 fOwner->fLink->Attach<BPoint>(pt3); 3097 fOwner->fLink->Attach<BRect>(bounds); 3098 3099 _FlushIfNotInTransaction(); 3100 } 3101 3102 3103 void 3104 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 3105 { 3106 if (fOwner) { 3107 // we construct the smallest rectangle that contains the 3 points 3108 // for the 1st point 3109 BRect bounds(pt1, pt1); 3110 3111 // for the 2nd point 3112 if (pt2.x < bounds.left) 3113 bounds.left = pt2.x; 3114 3115 if (pt2.y < bounds.top) 3116 bounds.top = pt2.y; 3117 3118 if (pt2.x > bounds.right) 3119 bounds.right = pt2.x; 3120 3121 if (pt2.y > bounds.bottom) 3122 bounds.bottom = pt2.y; 3123 3124 // for the 3rd point 3125 if (pt3.x < bounds.left) 3126 bounds.left = pt3.x; 3127 3128 if (pt3.y < bounds.top) 3129 bounds.top = pt3.y; 3130 3131 if (pt3.x > bounds.right) 3132 bounds.right = pt3.x; 3133 3134 if (pt3.y > bounds.bottom) 3135 bounds.bottom = pt3.y; 3136 3137 StrokeTriangle(pt1, pt2, pt3, bounds, p); 3138 } 3139 } 3140 3141 3142 void 3143 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 3144 { 3145 if (fOwner) { 3146 // we construct the smallest rectangle that contains the 3 points 3147 // for the 1st point 3148 BRect bounds(pt1, pt1); 3149 3150 // for the 2nd point 3151 if (pt2.x < bounds.left) 3152 bounds.left = pt2.x; 3153 3154 if (pt2.y < bounds.top) 3155 bounds.top = pt2.y; 3156 3157 if (pt2.x > bounds.right) 3158 bounds.right = pt2.x; 3159 3160 if (pt2.y > bounds.bottom) 3161 bounds.bottom = pt2.y; 3162 3163 // for the 3rd point 3164 if (pt3.x < bounds.left) 3165 bounds.left = pt3.x; 3166 3167 if (pt3.y < bounds.top) 3168 bounds.top = pt3.y; 3169 3170 if (pt3.x > bounds.right) 3171 bounds.right = pt3.x; 3172 3173 if (pt3.y > bounds.bottom) 3174 bounds.bottom = pt3.y; 3175 3176 FillTriangle(pt1, pt2, pt3, bounds, p); 3177 } 3178 } 3179 3180 3181 void 3182 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3183 const BGradient& gradient) 3184 { 3185 if (fOwner) { 3186 // we construct the smallest rectangle that contains the 3 points 3187 // for the 1st point 3188 BRect bounds(pt1, pt1); 3189 3190 // for the 2nd point 3191 if (pt2.x < bounds.left) 3192 bounds.left = pt2.x; 3193 3194 if (pt2.y < bounds.top) 3195 bounds.top = pt2.y; 3196 3197 if (pt2.x > bounds.right) 3198 bounds.right = pt2.x; 3199 3200 if (pt2.y > bounds.bottom) 3201 bounds.bottom = pt2.y; 3202 3203 // for the 3rd point 3204 if (pt3.x < bounds.left) 3205 bounds.left = pt3.x; 3206 3207 if (pt3.y < bounds.top) 3208 bounds.top = pt3.y; 3209 3210 if (pt3.x > bounds.right) 3211 bounds.right = pt3.x; 3212 3213 if (pt3.y > bounds.bottom) 3214 bounds.bottom = pt3.y; 3215 3216 FillTriangle(pt1, pt2, pt3, bounds, gradient); 3217 } 3218 } 3219 3220 3221 void 3222 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3223 BRect bounds, ::pattern pattern) 3224 { 3225 if (fOwner == NULL) 3226 return; 3227 3228 _CheckLockAndSwitchCurrent(); 3229 _UpdatePattern(pattern); 3230 3231 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 3232 fOwner->fLink->Attach<BPoint>(pt1); 3233 fOwner->fLink->Attach<BPoint>(pt2); 3234 fOwner->fLink->Attach<BPoint>(pt3); 3235 fOwner->fLink->Attach<BRect>(bounds); 3236 3237 _FlushIfNotInTransaction(); 3238 } 3239 3240 3241 void 3242 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3243 BRect bounds, const BGradient& gradient) 3244 { 3245 if (fOwner == NULL) 3246 return; 3247 3248 _CheckLockAndSwitchCurrent(); 3249 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT); 3250 fOwner->fLink->Attach<BPoint>(pt1); 3251 fOwner->fLink->Attach<BPoint>(pt2); 3252 fOwner->fLink->Attach<BPoint>(pt3); 3253 fOwner->fLink->Attach<BRect>(bounds); 3254 fOwner->fLink->AttachGradient(gradient); 3255 3256 _FlushIfNotInTransaction(); 3257 } 3258 3259 3260 void 3261 BView::StrokeLine(BPoint toPt, pattern p) 3262 { 3263 StrokeLine(PenLocation(), toPt, p); 3264 } 3265 3266 3267 void 3268 BView::StrokeLine(BPoint pt0, BPoint pt1, ::pattern pattern) 3269 { 3270 if (fOwner == NULL) 3271 return; 3272 3273 _CheckLockAndSwitchCurrent(); 3274 _UpdatePattern(pattern); 3275 3276 ViewStrokeLineInfo info; 3277 info.startPoint = pt0; 3278 info.endPoint = pt1; 3279 3280 fOwner->fLink->StartMessage(AS_STROKE_LINE); 3281 fOwner->fLink->Attach<ViewStrokeLineInfo>(info); 3282 3283 _FlushIfNotInTransaction(); 3284 3285 // this modifies our pen location, so we invalidate the flag. 3286 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3287 } 3288 3289 3290 void 3291 BView::StrokeShape(BShape *shape, ::pattern pattern) 3292 { 3293 if (shape == NULL || fOwner == NULL) 3294 return; 3295 3296 shape_data *sd = (shape_data *)shape->fPrivateData; 3297 if (sd->opCount == 0 || sd->ptCount == 0) 3298 return; 3299 3300 _CheckLockAndSwitchCurrent(); 3301 _UpdatePattern(pattern); 3302 3303 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 3304 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3305 fOwner->fLink->Attach<int32>(sd->opCount); 3306 fOwner->fLink->Attach<int32>(sd->ptCount); 3307 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 3308 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3309 3310 _FlushIfNotInTransaction(); 3311 } 3312 3313 3314 void 3315 BView::FillShape(BShape *shape, ::pattern pattern) 3316 { 3317 if (shape == NULL || fOwner == NULL) 3318 return; 3319 3320 shape_data *sd = (shape_data *)(shape->fPrivateData); 3321 if (sd->opCount == 0 || sd->ptCount == 0) 3322 return; 3323 3324 _CheckLockAndSwitchCurrent(); 3325 _UpdatePattern(pattern); 3326 3327 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 3328 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3329 fOwner->fLink->Attach<int32>(sd->opCount); 3330 fOwner->fLink->Attach<int32>(sd->ptCount); 3331 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3332 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3333 3334 _FlushIfNotInTransaction(); 3335 } 3336 3337 3338 void 3339 BView::FillShape(BShape *shape, const BGradient& gradient) 3340 { 3341 if (shape == NULL || fOwner == NULL) 3342 return; 3343 3344 shape_data *sd = (shape_data *)(shape->fPrivateData); 3345 if (sd->opCount == 0 || sd->ptCount == 0) 3346 return; 3347 3348 _CheckLockAndSwitchCurrent(); 3349 3350 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT); 3351 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3352 fOwner->fLink->Attach<int32>(sd->opCount); 3353 fOwner->fLink->Attach<int32>(sd->ptCount); 3354 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3355 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3356 fOwner->fLink->AttachGradient(gradient); 3357 3358 _FlushIfNotInTransaction(); 3359 } 3360 3361 3362 void 3363 BView::BeginLineArray(int32 count) 3364 { 3365 if (fOwner == NULL) 3366 return; 3367 3368 if (count <= 0) 3369 debugger("Calling BeginLineArray with a count <= 0"); 3370 3371 _CheckLock(); 3372 3373 if (fCommArray) { 3374 debugger("Can't nest BeginLineArray calls"); 3375 // not fatal, but it helps during 3376 // development of your app and is in 3377 // line with R5... 3378 delete[] fCommArray->array; 3379 delete fCommArray; 3380 } 3381 3382 // TODO: since this method cannot return failure, and further AddLine() 3383 // calls with a NULL fCommArray would drop into the debugger anyway, 3384 // we allow the possible std::bad_alloc exceptions here... 3385 fCommArray = new _array_data_; 3386 fCommArray->maxCount = count; 3387 fCommArray->count = 0; 3388 fCommArray->array = new ViewLineArrayInfo[count]; 3389 } 3390 3391 3392 void 3393 BView::AddLine(BPoint pt0, BPoint pt1, rgb_color col) 3394 { 3395 if (fOwner == NULL) 3396 return; 3397 3398 if (!fCommArray) 3399 debugger("BeginLineArray must be called before using AddLine"); 3400 3401 _CheckLock(); 3402 3403 const uint32 &arrayCount = fCommArray->count; 3404 if (arrayCount < fCommArray->maxCount) { 3405 fCommArray->array[arrayCount].startPoint = pt0; 3406 fCommArray->array[arrayCount].endPoint = pt1; 3407 fCommArray->array[arrayCount].color = col; 3408 3409 fCommArray->count++; 3410 } 3411 } 3412 3413 3414 void 3415 BView::EndLineArray() 3416 { 3417 if (fOwner == NULL) 3418 return; 3419 3420 if (fCommArray == NULL) 3421 debugger("Can't call EndLineArray before BeginLineArray"); 3422 3423 _CheckLockAndSwitchCurrent(); 3424 3425 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 3426 fOwner->fLink->Attach<int32>(fCommArray->count); 3427 fOwner->fLink->Attach(fCommArray->array, 3428 fCommArray->count * sizeof(ViewLineArrayInfo)); 3429 3430 _FlushIfNotInTransaction(); 3431 3432 _RemoveCommArray(); 3433 } 3434 3435 3436 void 3437 BView::SetDiskMode(char* filename, long offset) 3438 { 3439 // TODO: implement 3440 // One BeBook version has this to say about SetDiskMode(): 3441 // 3442 // "Begins recording a picture to the file with the given filename 3443 // at the given offset. Subsequent drawing commands sent to the view 3444 // will be written to the file until EndPicture() is called. The 3445 // stored commands may be played from the file with DrawPicture()." 3446 } 3447 3448 3449 void 3450 BView::BeginPicture(BPicture *picture) 3451 { 3452 if (_CheckOwnerLockAndSwitchCurrent() 3453 && picture && picture->fUsurped == NULL) { 3454 picture->Usurp(fCurrentPicture); 3455 fCurrentPicture = picture; 3456 3457 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE); 3458 } 3459 } 3460 3461 3462 void 3463 BView::AppendToPicture(BPicture *picture) 3464 { 3465 _CheckLockAndSwitchCurrent(); 3466 3467 if (picture && picture->fUsurped == NULL) { 3468 int32 token = picture->Token(); 3469 3470 if (token == -1) { 3471 BeginPicture(picture); 3472 } else { 3473 picture->SetToken(-1); 3474 picture->Usurp(fCurrentPicture); 3475 fCurrentPicture = picture; 3476 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE); 3477 fOwner->fLink->Attach<int32>(token); 3478 } 3479 } 3480 } 3481 3482 3483 BPicture * 3484 BView::EndPicture() 3485 { 3486 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) { 3487 int32 token; 3488 3489 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE); 3490 3491 int32 code; 3492 if (fOwner->fLink->FlushWithReply(code) == B_OK 3493 && code == B_OK 3494 && fOwner->fLink->Read<int32>(&token) == B_OK) { 3495 BPicture *picture = fCurrentPicture; 3496 fCurrentPicture = picture->StepDown(); 3497 picture->SetToken(token); 3498 3499 return picture; 3500 } 3501 } 3502 3503 return NULL; 3504 } 3505 3506 3507 void 3508 BView::SetViewBitmap(const BBitmap *bitmap, BRect srcRect, BRect dstRect, 3509 uint32 followFlags, uint32 options) 3510 { 3511 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 3512 } 3513 3514 3515 void 3516 BView::SetViewBitmap(const BBitmap *bitmap, uint32 followFlags, uint32 options) 3517 { 3518 BRect rect; 3519 if (bitmap) 3520 rect = bitmap->Bounds(); 3521 3522 rect.OffsetTo(B_ORIGIN); 3523 3524 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 3525 } 3526 3527 3528 void 3529 BView::ClearViewBitmap() 3530 { 3531 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3532 } 3533 3534 3535 status_t 3536 BView::SetViewOverlay(const BBitmap *overlay, BRect srcRect, BRect dstRect, 3537 rgb_color *colorKey, uint32 followFlags, uint32 options) 3538 { 3539 if ((overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 3540 return B_BAD_VALUE; 3541 3542 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 3543 options | AS_REQUEST_COLOR_KEY); 3544 if (status == B_OK) { 3545 // read the color that will be treated as transparent 3546 fOwner->fLink->Read<rgb_color>(colorKey); 3547 } 3548 3549 return status; 3550 } 3551 3552 3553 status_t 3554 BView::SetViewOverlay(const BBitmap *overlay, rgb_color *colorKey, 3555 uint32 followFlags, uint32 options) 3556 { 3557 BRect rect; 3558 if (overlay != NULL) { 3559 rect = overlay->Bounds(); 3560 rect.OffsetTo(B_ORIGIN); 3561 } 3562 3563 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 3564 } 3565 3566 3567 void 3568 BView::ClearViewOverlay() 3569 { 3570 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3571 } 3572 3573 3574 void 3575 BView::CopyBits(BRect src, BRect dst) 3576 { 3577 if (fOwner == NULL) 3578 return; 3579 3580 if (!src.IsValid() || !dst.IsValid()) 3581 return; 3582 3583 _CheckLockAndSwitchCurrent(); 3584 3585 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS); 3586 fOwner->fLink->Attach<BRect>(src); 3587 fOwner->fLink->Attach<BRect>(dst); 3588 3589 _FlushIfNotInTransaction(); 3590 } 3591 3592 3593 void 3594 BView::DrawPicture(const BPicture *picture) 3595 { 3596 if (picture == NULL) 3597 return; 3598 3599 DrawPictureAsync(picture, PenLocation()); 3600 Sync(); 3601 } 3602 3603 3604 void 3605 BView::DrawPicture(const BPicture *picture, BPoint where) 3606 { 3607 if (picture == NULL) 3608 return; 3609 3610 DrawPictureAsync(picture, where); 3611 Sync(); 3612 } 3613 3614 3615 void 3616 BView::DrawPicture(const char *filename, long offset, BPoint where) 3617 { 3618 if (!filename) 3619 return; 3620 3621 DrawPictureAsync(filename, offset, where); 3622 Sync(); 3623 } 3624 3625 3626 void 3627 BView::DrawPictureAsync(const BPicture *picture) 3628 { 3629 if (picture == NULL) 3630 return; 3631 3632 DrawPictureAsync(picture, PenLocation()); 3633 } 3634 3635 3636 void 3637 BView::DrawPictureAsync(const BPicture *picture, BPoint where) 3638 { 3639 if (picture == NULL) 3640 return; 3641 3642 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 3643 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE); 3644 fOwner->fLink->Attach<int32>(picture->Token()); 3645 fOwner->fLink->Attach<BPoint>(where); 3646 3647 _FlushIfNotInTransaction(); 3648 } 3649 } 3650 3651 3652 void 3653 BView::DrawPictureAsync(const char *filename, long offset, BPoint where) 3654 { 3655 if (!filename) 3656 return; 3657 3658 // TODO: Test 3659 BFile file(filename, B_READ_ONLY); 3660 if (file.InitCheck() < B_OK) 3661 return; 3662 3663 file.Seek(offset, SEEK_SET); 3664 3665 BPicture picture; 3666 if (picture.Unflatten(&file) < B_OK) 3667 return; 3668 3669 DrawPictureAsync(&picture, where); 3670 } 3671 3672 3673 void 3674 BView::Invalidate(BRect invalRect) 3675 { 3676 if (fOwner == NULL) 3677 return; 3678 3679 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 3680 // On the server side, the invalid rect will be converted to a BRegion, 3681 // which rounds in a different manner, so that it really includes the 3682 // fractional coordinates of a BRect (ie ceilf(rect.right) & 3683 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 3684 // different rounding here to stay compatible in both ways. 3685 invalRect.left = (int)invalRect.left; 3686 invalRect.top = (int)invalRect.top; 3687 invalRect.right = (int)invalRect.right; 3688 invalRect.bottom = (int)invalRect.bottom; 3689 if (!invalRect.IsValid()) 3690 return; 3691 3692 _CheckLockAndSwitchCurrent(); 3693 3694 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT); 3695 fOwner->fLink->Attach<BRect>(invalRect); 3696 3697 // TODO: determine why this check isn't working correctly. 3698 #if 0 3699 if (!fOwner->fUpdateRequested) { 3700 fOwner->fLink->Flush(); 3701 fOwner->fUpdateRequested = true; 3702 } 3703 #endif 3704 fOwner->fLink->Flush(); 3705 } 3706 3707 3708 void 3709 BView::Invalidate(const BRegion* region) 3710 { 3711 if (region == NULL || fOwner == NULL) 3712 return; 3713 3714 _CheckLockAndSwitchCurrent(); 3715 3716 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION); 3717 fOwner->fLink->AttachRegion(*region); 3718 3719 if (!fOwner->fUpdateRequested) { 3720 fOwner->fLink->Flush(); 3721 fOwner->fUpdateRequested = true; 3722 } 3723 } 3724 3725 3726 void 3727 BView::Invalidate() 3728 { 3729 Invalidate(Bounds()); 3730 } 3731 3732 3733 void 3734 BView::InvertRect(BRect rect) 3735 { 3736 if (fOwner) { 3737 _CheckLockAndSwitchCurrent(); 3738 3739 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT); 3740 fOwner->fLink->Attach<BRect>(rect); 3741 3742 _FlushIfNotInTransaction(); 3743 } 3744 } 3745 3746 3747 // #pragma mark - View Hierarchy Functions 3748 3749 3750 void 3751 BView::AddChild(BView *child, BView *before) 3752 { 3753 STRACE(("BView(%s)::AddChild(child='%s' before='%s')\n", 3754 this->Name() ? this->Name(): "NULL", 3755 child && child->Name() ? child->Name(): "NULL", 3756 before && before->Name() ? before->Name(): "NULL")); 3757 3758 if (!_AddChild(child, before)) 3759 return; 3760 3761 if (fLayoutData->fLayout) 3762 fLayoutData->fLayout->AddView(child); 3763 } 3764 3765 3766 bool 3767 BView::AddChild(BLayoutItem* child) 3768 { 3769 if (!fLayoutData->fLayout) 3770 return false; 3771 return fLayoutData->fLayout->AddItem(child); 3772 } 3773 3774 3775 bool 3776 BView::_AddChild(BView *child, BView *before) 3777 { 3778 if (!child) 3779 return false; 3780 3781 if (child->fParent != NULL) { 3782 debugger("AddChild failed - the view already has a parent."); 3783 return false; 3784 } 3785 3786 bool lockedOwner = false; 3787 if (fOwner && !fOwner->IsLocked()) { 3788 fOwner->Lock(); 3789 lockedOwner = true; 3790 } 3791 3792 if (!_AddChildToList(child, before)) { 3793 debugger("AddChild failed!"); 3794 if (lockedOwner) 3795 fOwner->Unlock(); 3796 return false; 3797 } 3798 3799 if (fOwner) { 3800 _CheckLockAndSwitchCurrent(); 3801 3802 child->_SetOwner(fOwner); 3803 child->_CreateSelf(); 3804 child->_Attach(); 3805 3806 if (lockedOwner) 3807 fOwner->Unlock(); 3808 } 3809 3810 InvalidateLayout(); 3811 3812 return true; 3813 } 3814 3815 3816 bool 3817 BView::RemoveChild(BView *child) 3818 { 3819 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name())); 3820 3821 if (!child) 3822 return false; 3823 3824 if (child->fParent != this) 3825 return false; 3826 3827 return child->RemoveSelf(); 3828 } 3829 3830 int32 3831 BView::CountChildren() const 3832 { 3833 _CheckLock(); 3834 3835 uint32 count = 0; 3836 BView *child = fFirstChild; 3837 3838 while (child != NULL) { 3839 count++; 3840 child = child->fNextSibling; 3841 } 3842 3843 return count; 3844 } 3845 3846 3847 BView * 3848 BView::ChildAt(int32 index) const 3849 { 3850 _CheckLock(); 3851 3852 BView *child = fFirstChild; 3853 while (child != NULL && index-- > 0) { 3854 child = child->fNextSibling; 3855 } 3856 3857 return child; 3858 } 3859 3860 3861 BView * 3862 BView::NextSibling() const 3863 { 3864 return fNextSibling; 3865 } 3866 3867 3868 BView * 3869 BView::PreviousSibling() const 3870 { 3871 return fPreviousSibling; 3872 } 3873 3874 3875 bool 3876 BView::RemoveSelf() 3877 { 3878 if (fParent && fParent->fLayoutData->fLayout) 3879 return fParent->fLayoutData->fLayout->RemoveView(this); 3880 else 3881 return _RemoveSelf(); 3882 } 3883 3884 3885 bool 3886 BView::_RemoveSelf() 3887 { 3888 STRACE(("BView(%s)::RemoveSelf()...\n", Name())); 3889 3890 // Remove this child from its parent 3891 3892 BWindow* owner = fOwner; 3893 _CheckLock(); 3894 3895 if (owner != NULL) { 3896 _UpdateStateForRemove(); 3897 _Detach(); 3898 } 3899 3900 BView* parent = fParent; 3901 if (!parent || !parent->_RemoveChildFromList(this)) 3902 return false; 3903 3904 if (owner != NULL && !fTopLevelView) { 3905 // the top level view is deleted by the app_server automatically 3906 owner->fLink->StartMessage(AS_VIEW_DELETE); 3907 owner->fLink->Attach<int32>(_get_object_token_(this)); 3908 } 3909 3910 parent->InvalidateLayout(); 3911 3912 STRACE(("DONE: BView(%s)::RemoveSelf()\n", Name())); 3913 3914 return true; 3915 } 3916 3917 3918 BView * 3919 BView::Parent() const 3920 { 3921 if (fParent && fParent->fTopLevelView) 3922 return NULL; 3923 3924 return fParent; 3925 } 3926 3927 3928 BView * 3929 BView::FindView(const char *name) const 3930 { 3931 if (name == NULL) 3932 return NULL; 3933 3934 if (Name() != NULL && !strcmp(Name(), name)) 3935 return const_cast<BView *>(this); 3936 3937 BView *child = fFirstChild; 3938 while (child != NULL) { 3939 BView *view = child->FindView(name); 3940 if (view != NULL) 3941 return view; 3942 3943 child = child->fNextSibling; 3944 } 3945 3946 return NULL; 3947 } 3948 3949 3950 void 3951 BView::MoveBy(float deltaX, float deltaY) 3952 { 3953 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY)); 3954 } 3955 3956 3957 void 3958 BView::MoveTo(BPoint where) 3959 { 3960 MoveTo(where.x, where.y); 3961 } 3962 3963 3964 void 3965 BView::MoveTo(float x, float y) 3966 { 3967 if (x == fParentOffset.x && y == fParentOffset.y) 3968 return; 3969 3970 // BeBook says we should do this. And it makes sense. 3971 x = roundf(x); 3972 y = roundf(y); 3973 3974 if (fOwner) { 3975 _CheckLockAndSwitchCurrent(); 3976 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO); 3977 fOwner->fLink->Attach<float>(x); 3978 fOwner->fLink->Attach<float>(y); 3979 3980 // fState->valid_flags |= B_VIEW_FRAME_BIT; 3981 3982 _FlushIfNotInTransaction(); 3983 } 3984 3985 _MoveTo((int32)x, (int32)y); 3986 } 3987 3988 3989 void 3990 BView::ResizeBy(float deltaWidth, float deltaHeight) 3991 { 3992 // BeBook says we should do this. And it makes sense. 3993 deltaWidth = roundf(deltaWidth); 3994 deltaHeight = roundf(deltaHeight); 3995 3996 if (deltaWidth == 0 && deltaHeight == 0) 3997 return; 3998 3999 if (fOwner) { 4000 _CheckLockAndSwitchCurrent(); 4001 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO); 4002 4003 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth); 4004 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight); 4005 4006 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4007 4008 _FlushIfNotInTransaction(); 4009 } 4010 4011 _ResizeBy((int32)deltaWidth, (int32)deltaHeight); 4012 } 4013 4014 4015 void 4016 BView::ResizeTo(float width, float height) 4017 { 4018 ResizeBy(width - fBounds.Width(), height - fBounds.Height()); 4019 } 4020 4021 4022 void 4023 BView::ResizeTo(BSize size) 4024 { 4025 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height()); 4026 } 4027 4028 4029 // #pragma mark - Inherited Methods (from BHandler) 4030 4031 4032 status_t 4033 BView::GetSupportedSuites(BMessage *data) 4034 { 4035 if (data == NULL) 4036 return B_BAD_VALUE; 4037 4038 status_t status = data->AddString("suites", "suite/vnd.Be-view"); 4039 BPropertyInfo propertyInfo(sViewPropInfo); 4040 if (status == B_OK) 4041 status = data->AddFlat("messages", &propertyInfo); 4042 if (status == B_OK) 4043 return BHandler::GetSupportedSuites(data); 4044 return status; 4045 } 4046 4047 4048 BHandler * 4049 BView::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, 4050 int32 what, const char *property) 4051 { 4052 if (msg->what == B_WINDOW_MOVE_BY 4053 || msg->what == B_WINDOW_MOVE_TO) 4054 return this; 4055 4056 BPropertyInfo propertyInfo(sViewPropInfo); 4057 status_t err = B_BAD_SCRIPT_SYNTAX; 4058 BMessage replyMsg(B_REPLY); 4059 4060 switch (propertyInfo.FindMatch(msg, index, specifier, what, property)) { 4061 case 0: 4062 case 1: 4063 case 2: 4064 case 3: 4065 case 5: 4066 return this; 4067 4068 case 4: 4069 if (fShelf) { 4070 msg->PopSpecifier(); 4071 return fShelf; 4072 } 4073 4074 err = B_NAME_NOT_FOUND; 4075 replyMsg.AddString("message", "This window doesn't have a shelf"); 4076 break; 4077 4078 case 6: 4079 { 4080 if (!fFirstChild) { 4081 err = B_NAME_NOT_FOUND; 4082 replyMsg.AddString("message", "This window doesn't have children."); 4083 break; 4084 } 4085 BView *child = NULL; 4086 switch (what) { 4087 case B_INDEX_SPECIFIER: 4088 { 4089 int32 index; 4090 err = specifier->FindInt32("index", &index); 4091 if (err == B_OK) 4092 child = ChildAt(index); 4093 break; 4094 } 4095 case B_REVERSE_INDEX_SPECIFIER: 4096 { 4097 int32 rindex; 4098 err = specifier->FindInt32("index", &rindex); 4099 if (err == B_OK) 4100 child = ChildAt(CountChildren() - rindex); 4101 break; 4102 } 4103 case B_NAME_SPECIFIER: 4104 { 4105 const char *name; 4106 err = specifier->FindString("name", &name); 4107 if (err == B_OK) 4108 child = FindView(name); 4109 break; 4110 } 4111 } 4112 4113 if (child != NULL) { 4114 msg->PopSpecifier(); 4115 return child; 4116 } 4117 4118 if (err == B_OK) 4119 err = B_BAD_INDEX; 4120 4121 replyMsg.AddString("message", 4122 "Cannot find view at/with specified index/name."); 4123 break; 4124 } 4125 4126 default: 4127 return BHandler::ResolveSpecifier(msg, index, specifier, what, 4128 property); 4129 } 4130 4131 if (err < B_OK) { 4132 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4133 4134 if (err == B_BAD_SCRIPT_SYNTAX) 4135 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4136 else 4137 replyMsg.AddString("message", strerror(err)); 4138 } 4139 4140 replyMsg.AddInt32("error", err); 4141 msg->SendReply(&replyMsg); 4142 return NULL; 4143 } 4144 4145 4146 void 4147 BView::MessageReceived(BMessage* msg) 4148 { 4149 if (!msg->HasSpecifiers()) { 4150 switch (msg->what) { 4151 case B_VIEW_RESIZED: 4152 // By the time the message arrives, the bounds may have 4153 // changed already, that's why we don't use the values 4154 // in the message itself. 4155 FrameResized(fBounds.Width(), fBounds.Height()); 4156 break; 4157 4158 case B_VIEW_MOVED: 4159 FrameMoved(fParentOffset); 4160 break; 4161 4162 case B_MOUSE_WHEEL_CHANGED: 4163 { 4164 float deltaX = 0.0f, deltaY = 0.0f; 4165 4166 BScrollBar *horizontal = ScrollBar(B_HORIZONTAL); 4167 if (horizontal != NULL) 4168 msg->FindFloat("be:wheel_delta_x", &deltaX); 4169 4170 BScrollBar *vertical = ScrollBar(B_VERTICAL); 4171 if (vertical != NULL) 4172 msg->FindFloat("be:wheel_delta_y", &deltaY); 4173 4174 if (deltaX == 0.0f && deltaY == 0.0f) 4175 return; 4176 4177 float smallStep, largeStep; 4178 if (horizontal != NULL) { 4179 horizontal->GetSteps(&smallStep, &largeStep); 4180 4181 // pressing the option/command/control key scrolls faster 4182 if (modifiers() 4183 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4184 deltaX *= largeStep; 4185 } else 4186 deltaX *= smallStep * 3; 4187 4188 horizontal->SetValue(horizontal->Value() + deltaX); 4189 } 4190 4191 if (vertical != NULL) { 4192 vertical->GetSteps(&smallStep, &largeStep); 4193 4194 // pressing the option/command/control key scrolls faster 4195 if (modifiers() 4196 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4197 deltaY *= largeStep; 4198 } else 4199 deltaY *= smallStep * 3; 4200 4201 vertical->SetValue(vertical->Value() + deltaY); 4202 } 4203 break; 4204 } 4205 4206 default: 4207 return BHandler::MessageReceived(msg); 4208 } 4209 4210 return; 4211 } 4212 4213 // Scripting message 4214 4215 BMessage replyMsg(B_REPLY); 4216 status_t err = B_BAD_SCRIPT_SYNTAX; 4217 int32 index; 4218 BMessage specifier; 4219 int32 what; 4220 const char *prop; 4221 4222 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK) 4223 return BHandler::MessageReceived(msg); 4224 4225 BPropertyInfo propertyInfo(sViewPropInfo); 4226 switch (propertyInfo.FindMatch(msg, index, &specifier, what, prop)) { 4227 case 0: 4228 err = replyMsg.AddRect("result", Frame()); 4229 break; 4230 case 1: 4231 { 4232 BRect newFrame; 4233 err = msg->FindRect("data", &newFrame); 4234 if (err == B_OK) { 4235 MoveTo(newFrame.LeftTop()); 4236 ResizeTo(newFrame.right, newFrame.bottom); 4237 } 4238 break; 4239 } 4240 case 2: 4241 err = replyMsg.AddBool( "result", IsHidden()); 4242 break; 4243 case 3: 4244 { 4245 bool newHiddenState; 4246 err = msg->FindBool("data", &newHiddenState); 4247 if (err == B_OK) { 4248 if (!IsHidden() && newHiddenState == true) 4249 Hide(); 4250 else if (IsHidden() && newHiddenState == false) 4251 Show(); 4252 } 4253 } 4254 case 5: 4255 err = replyMsg.AddInt32("result", CountChildren()); 4256 break; 4257 default: 4258 return BHandler::MessageReceived(msg); 4259 } 4260 4261 if (err < B_OK) { 4262 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4263 4264 if (err == B_BAD_SCRIPT_SYNTAX) 4265 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4266 else 4267 replyMsg.AddString("message", strerror(err)); 4268 } 4269 4270 replyMsg.AddInt32("error", err); 4271 msg->SendReply(&replyMsg); 4272 } 4273 4274 4275 status_t 4276 BView::Perform(perform_code code, void* _data) 4277 { 4278 switch (code) { 4279 case PERFORM_CODE_MIN_SIZE: 4280 ((perform_data_min_size*)_data)->return_value 4281 = BView::MinSize(); 4282 return B_OK; 4283 case PERFORM_CODE_MAX_SIZE: 4284 ((perform_data_max_size*)_data)->return_value 4285 = BView::MaxSize(); 4286 return B_OK; 4287 case PERFORM_CODE_PREFERRED_SIZE: 4288 ((perform_data_preferred_size*)_data)->return_value 4289 = BView::PreferredSize(); 4290 return B_OK; 4291 case PERFORM_CODE_LAYOUT_ALIGNMENT: 4292 ((perform_data_layout_alignment*)_data)->return_value 4293 = BView::LayoutAlignment(); 4294 return B_OK; 4295 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 4296 ((perform_data_has_height_for_width*)_data)->return_value 4297 = BView::HasHeightForWidth(); 4298 return B_OK; 4299 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 4300 { 4301 perform_data_get_height_for_width* data 4302 = (perform_data_get_height_for_width*)_data; 4303 BView::GetHeightForWidth(data->width, &data->min, &data->max, 4304 &data->preferred); 4305 return B_OK; 4306 } 4307 case PERFORM_CODE_SET_LAYOUT: 4308 { 4309 perform_data_set_layout* data = (perform_data_set_layout*)_data; 4310 BView::SetLayout(data->layout); 4311 return B_OK; 4312 } 4313 case PERFORM_CODE_INVALIDATE_LAYOUT: 4314 { 4315 perform_data_invalidate_layout* data 4316 = (perform_data_invalidate_layout*)_data; 4317 BView::InvalidateLayout(data->descendants); 4318 return B_OK; 4319 } 4320 case PERFORM_CODE_DO_LAYOUT: 4321 { 4322 BView::DoLayout(); 4323 return B_OK; 4324 } 4325 } 4326 4327 return BHandler::Perform(code, _data); 4328 } 4329 4330 4331 // #pragma mark - Layout Functions 4332 4333 4334 BSize 4335 BView::MinSize() 4336 { 4337 // TODO: make sure this works correctly when some methods are overridden 4338 float width, height; 4339 GetPreferredSize(&width, &height); 4340 4341 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 4342 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 4343 : BSize(width, height))); 4344 } 4345 4346 4347 BSize 4348 BView::MaxSize() 4349 { 4350 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 4351 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 4352 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 4353 } 4354 4355 4356 BSize 4357 BView::PreferredSize() 4358 { 4359 // TODO: make sure this works correctly when some methods are overridden 4360 float width, height; 4361 GetPreferredSize(&width, &height); 4362 4363 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 4364 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 4365 : BSize(width, height))); 4366 } 4367 4368 4369 BAlignment 4370 BView::LayoutAlignment() 4371 { 4372 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 4373 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 4374 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 4375 } 4376 4377 4378 void 4379 BView::SetExplicitMinSize(BSize size) 4380 { 4381 fLayoutData->fMinSize = size; 4382 InvalidateLayout(); 4383 } 4384 4385 4386 void 4387 BView::SetExplicitMaxSize(BSize size) 4388 { 4389 fLayoutData->fMaxSize = size; 4390 InvalidateLayout(); 4391 } 4392 4393 4394 void 4395 BView::SetExplicitPreferredSize(BSize size) 4396 { 4397 fLayoutData->fPreferredSize = size; 4398 InvalidateLayout(); 4399 } 4400 4401 4402 void 4403 BView::SetExplicitAlignment(BAlignment alignment) 4404 { 4405 fLayoutData->fAlignment = alignment; 4406 InvalidateLayout(); 4407 } 4408 4409 4410 BSize 4411 BView::ExplicitMinSize() const 4412 { 4413 return fLayoutData->fMinSize; 4414 } 4415 4416 4417 BSize 4418 BView::ExplicitMaxSize() const 4419 { 4420 return fLayoutData->fMaxSize; 4421 } 4422 4423 4424 BSize 4425 BView::ExplicitPreferredSize() const 4426 { 4427 return fLayoutData->fPreferredSize; 4428 } 4429 4430 4431 BAlignment 4432 BView::ExplicitAlignment() const 4433 { 4434 return fLayoutData->fAlignment; 4435 } 4436 4437 4438 bool 4439 BView::HasHeightForWidth() 4440 { 4441 return (fLayoutData->fLayout 4442 ? fLayoutData->fLayout->HasHeightForWidth() : false); 4443 } 4444 4445 4446 void 4447 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 4448 { 4449 if (fLayoutData->fLayout) 4450 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 4451 } 4452 4453 4454 void 4455 BView::SetLayout(BLayout* layout) 4456 { 4457 if (layout == fLayoutData->fLayout) 4458 return; 4459 4460 fFlags |= B_SUPPORTS_LAYOUT; 4461 4462 // unset and delete the old layout 4463 if (fLayoutData->fLayout) { 4464 fLayoutData->fLayout->SetView(NULL); 4465 delete fLayoutData->fLayout; 4466 } 4467 4468 fLayoutData->fLayout = layout; 4469 4470 if (fLayoutData->fLayout) { 4471 fLayoutData->fLayout->SetView(this); 4472 4473 // add all children 4474 int count = CountChildren(); 4475 for (int i = 0; i < count; i++) 4476 fLayoutData->fLayout->AddView(ChildAt(i)); 4477 } 4478 4479 InvalidateLayout(); 4480 } 4481 4482 4483 BLayout* 4484 BView::GetLayout() const 4485 { 4486 return fLayoutData->fLayout; 4487 } 4488 4489 4490 void 4491 BView::InvalidateLayout(bool descendants) 4492 { 4493 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress 4494 && fLayoutData->fLayoutInvalidationDisabled == 0) { 4495 if (fParent && fParent->fLayoutData->fLayoutValid) 4496 fParent->InvalidateLayout(false); 4497 4498 fLayoutData->fLayoutValid = false; 4499 4500 if (fLayoutData->fLayout) 4501 fLayoutData->fLayout->InvalidateLayout(); 4502 4503 if (descendants) { 4504 int count = CountChildren(); 4505 for (int i = 0; i < count; i++) 4506 ChildAt(i)->InvalidateLayout(descendants); 4507 } 4508 4509 if (fTopLevelView) { 4510 // trigger layout process 4511 if (fOwner) 4512 fOwner->PostMessage(B_LAYOUT_WINDOW); 4513 } 4514 } 4515 } 4516 4517 4518 void 4519 BView::EnableLayoutInvalidation() 4520 { 4521 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4522 fLayoutData->fLayoutInvalidationDisabled--; 4523 } 4524 4525 4526 void 4527 BView::DisableLayoutInvalidation() 4528 { 4529 fLayoutData->fLayoutInvalidationDisabled++; 4530 } 4531 4532 4533 bool 4534 BView::IsLayoutValid() const 4535 { 4536 return fLayoutData->fLayoutValid; 4537 } 4538 4539 4540 BLayoutContext* 4541 BView::LayoutContext() const 4542 { 4543 return fLayoutData->fLayoutContext; 4544 } 4545 4546 4547 void 4548 BView::Layout(bool force) 4549 { 4550 BLayoutContext context; 4551 _Layout(force, &context); 4552 } 4553 4554 4555 void 4556 BView::Relayout() 4557 { 4558 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 4559 fLayoutData->fNeedsRelayout = true; 4560 4561 // Layout() is recursive, that is if the parent view is currently laid 4562 // out, we don't call layout() on this view, but wait for the parent's 4563 // Layout() to do that for us. 4564 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 4565 Layout(false); 4566 } 4567 } 4568 4569 4570 void 4571 BView::DoLayout() 4572 { 4573 if (fLayoutData->fLayout) 4574 fLayoutData->fLayout->LayoutView(); 4575 } 4576 4577 4578 void 4579 BView::_Layout(bool force, BLayoutContext* context) 4580 { 4581 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 4582 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 4583 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, fLayoutData->fLayoutInProgress); 4584 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 4585 fLayoutData->fLayoutValid = false; 4586 4587 if (fLayoutData->fLayoutInProgress) 4588 return; 4589 4590 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 4591 fLayoutData->fLayoutContext = context; 4592 4593 fLayoutData->fLayoutInProgress = true; 4594 DoLayout(); 4595 fLayoutData->fLayoutInProgress = false; 4596 4597 fLayoutData->fLayoutValid = true; 4598 fLayoutData->fNeedsRelayout = false; 4599 4600 // layout children 4601 int32 childCount = CountChildren(); 4602 for (int32 i = 0; i < childCount; i++) { 4603 BView* child = ChildAt(i); 4604 if (!child->IsHidden(child)) 4605 child->_Layout(force, context); 4606 } 4607 4608 fLayoutData->fLayoutContext = oldContext; 4609 4610 // invalidate the drawn content, if requested 4611 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 4612 Invalidate(); 4613 } 4614 } 4615 4616 4617 // #pragma mark - Private Functions 4618 4619 4620 void 4621 BView::_InitData(BRect frame, const char *name, uint32 resizingMode, 4622 uint32 flags) 4623 { 4624 // Info: The name of the view is set by BHandler constructor 4625 4626 STRACE(("BView::InitData: enter\n")); 4627 4628 // initialize members 4629 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 4630 printf("%s BView::InitData(): resizing mode or flags swapped\n", name); 4631 4632 // There are applications that swap the resize mask and the flags in the 4633 // BView constructor. This does not cause problems under BeOS as it just 4634 // ors the two fields to one 32bit flag. 4635 // For now we do the same but print the above warning message. 4636 // TODO: this should be removed at some point and the original 4637 // version restored: 4638 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4639 fFlags = resizingMode | flags; 4640 4641 // handle rounding 4642 frame.left = roundf(frame.left); 4643 frame.top = roundf(frame.top); 4644 frame.right = roundf(frame.right); 4645 frame.bottom = roundf(frame.bottom); 4646 4647 fParentOffset.Set(frame.left, frame.top); 4648 4649 fOwner = NULL; 4650 fParent = NULL; 4651 fNextSibling = NULL; 4652 fPreviousSibling = NULL; 4653 fFirstChild = NULL; 4654 4655 fShowLevel = 0; 4656 fTopLevelView = false; 4657 4658 fCurrentPicture = NULL; 4659 fCommArray = NULL; 4660 4661 fVerScroller = NULL; 4662 fHorScroller = NULL; 4663 4664 fIsPrinting = false; 4665 fAttached = false; 4666 4667 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 4668 // TODO: Maybe we could auto-delete those views on AddChild() instead? 4669 fState = new BPrivate::ViewState; 4670 4671 fBounds = frame.OffsetToCopy(B_ORIGIN); 4672 fShelf = NULL; 4673 4674 fEventMask = 0; 4675 fEventOptions = 0; 4676 fMouseEventOptions = 0; 4677 4678 fLayoutData = new LayoutData; 4679 } 4680 4681 4682 void 4683 BView::_RemoveCommArray() 4684 { 4685 if (fCommArray) { 4686 delete [] fCommArray->array; 4687 delete fCommArray; 4688 fCommArray = NULL; 4689 } 4690 } 4691 4692 4693 void 4694 BView::_SetOwner(BWindow *newOwner) 4695 { 4696 if (!newOwner) 4697 _RemoveCommArray(); 4698 4699 if (fOwner != newOwner && fOwner) { 4700 if (fOwner->fFocus == this) 4701 MakeFocus(false); 4702 4703 if (fOwner->fLastMouseMovedView == this) 4704 fOwner->fLastMouseMovedView = NULL; 4705 4706 fOwner->RemoveHandler(this); 4707 if (fShelf) 4708 fOwner->RemoveHandler(fShelf); 4709 } 4710 4711 if (newOwner && newOwner != fOwner) { 4712 newOwner->AddHandler(this); 4713 if (fShelf) 4714 newOwner->AddHandler(fShelf); 4715 4716 if (fTopLevelView) 4717 SetNextHandler(newOwner); 4718 else 4719 SetNextHandler(fParent); 4720 } 4721 4722 fOwner = newOwner; 4723 4724 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) 4725 child->_SetOwner(newOwner); 4726 } 4727 4728 4729 void 4730 BView::_ClipToPicture(BPicture *picture, BPoint where, 4731 bool invert, bool sync) 4732 { 4733 if (!picture) 4734 return; 4735 4736 #if 1 4737 // TODO: Move the implementation to the server!!! 4738 // This implementation is pretty slow, since just creating an offscreen bitmap 4739 // takes a lot of time. That's the main reason why it should be moved 4740 // to the server. 4741 4742 // Here the idea is to get rid of the padding bytes in the bitmap, 4743 // as padding complicates and slows down the iteration. 4744 // TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned 4745 // to a 4 byte boundary. 4746 BRect bounds(Bounds()); 4747 if ((bounds.IntegerWidth() + 1) % 32) 4748 bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1) * 32 - 1; 4749 4750 // TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work. 4751 BBitmap *bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true); 4752 if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) { 4753 BView *view = new(std::nothrow) BView(bounds, "drawing view", 4754 B_FOLLOW_NONE, 0); 4755 if (view != NULL) { 4756 bitmap->AddChild(view); 4757 view->DrawPicture(picture, where); 4758 view->Sync(); 4759 } 4760 bitmap->Unlock(); 4761 } 4762 4763 BRegion region; 4764 int32 width = bounds.IntegerWidth() + 1; 4765 int32 height = bounds.IntegerHeight() + 1; 4766 if (bitmap != NULL && bitmap->LockBits() == B_OK) { 4767 uint32 bit = 0; 4768 uint32 *bits = (uint32 *)bitmap->Bits(); 4769 clipping_rect rect; 4770 4771 // TODO: A possible optimization would be adding "spans" instead 4772 // of 1x1 rects. That would probably help with very complex 4773 // BPictures 4774 for (int32 y = 0; y < height; y++) { 4775 for (int32 x = 0; x < width; x++) { 4776 bit = *bits++; 4777 if (bit != 0xFFFFFFFF) { 4778 rect.left = x; 4779 rect.right = rect.left; 4780 rect.top = rect.bottom = y; 4781 region.Include(rect); 4782 } 4783 } 4784 } 4785 bitmap->UnlockBits(); 4786 } 4787 delete bitmap; 4788 4789 if (invert) { 4790 BRegion inverseRegion; 4791 inverseRegion.Include(Bounds()); 4792 inverseRegion.Exclude(®ion); 4793 ConstrainClippingRegion(&inverseRegion); 4794 } else 4795 ConstrainClippingRegion(®ion); 4796 #else 4797 if (_CheckOwnerLockAndSwitchCurrent()) { 4798 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 4799 fOwner->fLink->Attach<int32>(picture->Token()); 4800 fOwner->fLink->Attach<BPoint>(where); 4801 fOwner->fLink->Attach<bool>(invert); 4802 4803 // TODO: I think that "sync" means another thing here: 4804 // the bebook, at least, says so. 4805 if (sync) 4806 fOwner->fLink->Flush(); 4807 4808 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 4809 } 4810 4811 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 4812 #endif 4813 } 4814 4815 4816 bool 4817 BView::_RemoveChildFromList(BView* child) 4818 { 4819 if (child->fParent != this) 4820 return false; 4821 4822 if (fFirstChild == child) { 4823 // it's the first view in the list 4824 fFirstChild = child->fNextSibling; 4825 } else { 4826 // there must be a previous sibling 4827 child->fPreviousSibling->fNextSibling = child->fNextSibling; 4828 } 4829 4830 if (child->fNextSibling) 4831 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 4832 4833 child->fParent = NULL; 4834 child->fNextSibling = NULL; 4835 child->fPreviousSibling = NULL; 4836 4837 return true; 4838 } 4839 4840 4841 bool 4842 BView::_AddChildToList(BView* child, BView* before) 4843 { 4844 if (!child) 4845 return false; 4846 if (child->fParent != NULL) { 4847 debugger("View already belongs to someone else"); 4848 return false; 4849 } 4850 if (before != NULL && before->fParent != this) { 4851 debugger("Invalid before view"); 4852 return false; 4853 } 4854 4855 if (before != NULL) { 4856 // add view before this one 4857 child->fNextSibling = before; 4858 child->fPreviousSibling = before->fPreviousSibling; 4859 if (child->fPreviousSibling != NULL) 4860 child->fPreviousSibling->fNextSibling = child; 4861 4862 before->fPreviousSibling = child; 4863 if (fFirstChild == before) 4864 fFirstChild = child; 4865 } else { 4866 // add view to the end of the list 4867 BView *last = fFirstChild; 4868 while (last != NULL && last->fNextSibling != NULL) { 4869 last = last->fNextSibling; 4870 } 4871 4872 if (last != NULL) { 4873 last->fNextSibling = child; 4874 child->fPreviousSibling = last; 4875 } else { 4876 fFirstChild = child; 4877 child->fPreviousSibling = NULL; 4878 } 4879 4880 child->fNextSibling = NULL; 4881 } 4882 4883 child->fParent = this; 4884 return true; 4885 } 4886 4887 4888 /*! \brief Creates the server counterpart of this view. 4889 This is only done for views that are part of the view hierarchy, ie. when 4890 they are attached to a window. 4891 RemoveSelf() deletes the server object again. 4892 */ 4893 bool 4894 BView::_CreateSelf() 4895 { 4896 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 4897 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 4898 // of the view and its parent are both send to the server. 4899 4900 if (fTopLevelView) 4901 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 4902 else 4903 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 4904 4905 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 4906 fOwner->fLink->AttachString(Name()); 4907 fOwner->fLink->Attach<BRect>(Frame()); 4908 fOwner->fLink->Attach<BPoint>(LeftTop()); 4909 fOwner->fLink->Attach<uint32>(ResizingMode()); 4910 fOwner->fLink->Attach<uint32>(fEventMask); 4911 fOwner->fLink->Attach<uint32>(fEventOptions); 4912 fOwner->fLink->Attach<uint32>(Flags()); 4913 fOwner->fLink->Attach<bool>(IsHidden(this)); 4914 fOwner->fLink->Attach<rgb_color>(fState->view_color); 4915 if (fTopLevelView) 4916 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 4917 else 4918 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 4919 fOwner->fLink->Flush(); 4920 4921 _CheckOwnerLockAndSwitchCurrent(); 4922 fState->UpdateServerState(*fOwner->fLink); 4923 4924 // we create all its children, too 4925 4926 for (BView *child = fFirstChild; child != NULL; 4927 child = child->fNextSibling) { 4928 child->_CreateSelf(); 4929 } 4930 4931 fOwner->fLink->Flush(); 4932 return true; 4933 } 4934 4935 4936 /*! Sets the new view position. 4937 It doesn't contact the server, though - the only case where this 4938 is called outside of MoveTo() is as reaction of moving a view 4939 in the server (a.k.a. B_WINDOW_RESIZED). 4940 It also calls the BView's FrameMoved() hook. 4941 */ 4942 void 4943 BView::_MoveTo(int32 x, int32 y) 4944 { 4945 fParentOffset.Set(x, y); 4946 4947 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 4948 BMessage moved(B_VIEW_MOVED); 4949 moved.AddInt64("when", system_time()); 4950 moved.AddPoint("where", BPoint(x, y)); 4951 4952 BMessenger target(this); 4953 target.SendMessage(&moved); 4954 } 4955 } 4956 4957 4958 /*! Computes the actual new frame size and recalculates the size of 4959 the children as well. 4960 It doesn't contact the server, though - the only case where this 4961 is called outside of ResizeBy() is as reaction of resizing a view 4962 in the server (a.k.a. B_WINDOW_RESIZED). 4963 It also calls the BView's FrameResized() hook. 4964 */ 4965 void 4966 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 4967 { 4968 fBounds.right += deltaWidth; 4969 fBounds.bottom += deltaHeight; 4970 4971 if (Window() == NULL) { 4972 // we're not supposed to exercise the resizing code in case 4973 // we haven't been attached to a window yet 4974 return; 4975 } 4976 4977 // layout the children 4978 if (fFlags & B_SUPPORTS_LAYOUT) { 4979 Relayout(); 4980 } else { 4981 for (BView* child = fFirstChild; child; child = child->fNextSibling) 4982 child->_ParentResizedBy(deltaWidth, deltaHeight); 4983 } 4984 4985 if (fFlags & B_FRAME_EVENTS) { 4986 BMessage resized(B_VIEW_RESIZED); 4987 resized.AddInt64("when", system_time()); 4988 resized.AddFloat("width", fBounds.Width()); 4989 resized.AddFloat("height", fBounds.Height()); 4990 4991 BMessenger target(this); 4992 target.SendMessage(&resized); 4993 } 4994 } 4995 4996 4997 /*! Relayouts the view according to its resizing mode. */ 4998 void 4999 BView::_ParentResizedBy(int32 x, int32 y) 5000 { 5001 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5002 BRect newFrame = Frame(); 5003 5004 // follow with left side 5005 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5006 newFrame.left += x; 5007 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5008 newFrame.left += x / 2; 5009 5010 // follow with right side 5011 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5012 newFrame.right += x; 5013 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5014 newFrame.right += x / 2; 5015 5016 // follow with top side 5017 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5018 newFrame.top += y; 5019 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5020 newFrame.top += y / 2; 5021 5022 // follow with bottom side 5023 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5024 newFrame.bottom += y; 5025 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5026 newFrame.bottom += y / 2; 5027 5028 if (newFrame.LeftTop() != fParentOffset) { 5029 // move view 5030 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5031 } 5032 5033 if (newFrame != Frame()) { 5034 // resize view 5035 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5036 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5037 _ResizeBy(widthDiff, heightDiff); 5038 } 5039 } 5040 5041 5042 void 5043 BView::_Activate(bool active) 5044 { 5045 WindowActivated(active); 5046 5047 for (BView *child = fFirstChild; child != NULL; 5048 child = child->fNextSibling) { 5049 child->_Activate(active); 5050 } 5051 } 5052 5053 5054 void 5055 BView::_Attach() 5056 { 5057 AttachedToWindow(); 5058 fAttached = true; 5059 5060 // after giving the view a chance to do this itself, 5061 // check for the B_PULSE_NEEDED flag and make sure the 5062 // window set's up the pulse messaging 5063 if (fOwner) { 5064 if (fFlags & B_PULSE_NEEDED) { 5065 _CheckLock(); 5066 if (fOwner->fPulseRunner == NULL) 5067 fOwner->SetPulseRate(fOwner->PulseRate()); 5068 } 5069 5070 if (!fOwner->IsHidden()) 5071 Invalidate(); 5072 } 5073 5074 for (BView* child = fFirstChild; child != NULL; 5075 child = child->fNextSibling) { 5076 // we need to check for fAttached as new views could have been 5077 // added in AttachedToWindow() - and those are already attached 5078 if (!child->fAttached) 5079 child->_Attach(); 5080 } 5081 5082 AllAttached(); 5083 } 5084 5085 5086 void 5087 BView::_Detach() 5088 { 5089 DetachedFromWindow(); 5090 fAttached = false; 5091 5092 for (BView* child = fFirstChild; child != NULL; 5093 child = child->fNextSibling) { 5094 child->_Detach(); 5095 } 5096 5097 AllDetached(); 5098 5099 if (fOwner) { 5100 _CheckLock(); 5101 5102 if (!fOwner->IsHidden()) 5103 Invalidate(); 5104 5105 // make sure our owner doesn't need us anymore 5106 5107 if (fOwner->CurrentFocus() == this) { 5108 MakeFocus(false); 5109 // MakeFocus() is virtual and might not be 5110 // passing through to the BView version, 5111 // but we need to make sure at this point 5112 // that we are not the focus view anymore. 5113 if (fOwner->CurrentFocus() == this) 5114 fOwner->_SetFocus(NULL, true); 5115 } 5116 5117 if (fOwner->fDefaultButton == this) 5118 fOwner->SetDefaultButton(NULL); 5119 5120 if (fOwner->fKeyMenuBar == this) 5121 fOwner->fKeyMenuBar = NULL; 5122 5123 if (fOwner->fLastMouseMovedView == this) 5124 fOwner->fLastMouseMovedView = NULL; 5125 5126 if (fOwner->fLastViewToken == _get_object_token_(this)) 5127 fOwner->fLastViewToken = B_NULL_TOKEN; 5128 5129 _SetOwner(NULL); 5130 } 5131 } 5132 5133 5134 void 5135 BView::_Draw(BRect updateRect) 5136 { 5137 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 5138 return; 5139 5140 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 5141 // -> View is simply not drawn at all 5142 5143 _SwitchServerCurrentView(); 5144 5145 ConvertFromScreen(&updateRect); 5146 5147 // TODO: make states robust (the hook implementation could 5148 // mess things up if it uses non-matching Push- and PopState(), 5149 // we would not be guaranteed to still have the same state on 5150 // the stack after having called Draw()) 5151 PushState(); 5152 Draw(updateRect); 5153 PopState(); 5154 Flush(); 5155 } 5156 5157 void 5158 BView::_DrawAfterChildren(BRect updateRect) 5159 { 5160 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 5161 || !(Flags() & B_DRAW_ON_CHILDREN)) 5162 return; 5163 5164 _SwitchServerCurrentView(); 5165 5166 ConvertFromScreen(&updateRect); 5167 5168 // TODO: make states robust (see above) 5169 PushState(); 5170 DrawAfterChildren(updateRect); 5171 PopState(); 5172 Flush(); 5173 } 5174 5175 5176 void 5177 BView::_Pulse() 5178 { 5179 if (Flags() & B_PULSE_NEEDED) 5180 Pulse(); 5181 5182 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 5183 child->_Pulse(); 5184 } 5185 } 5186 5187 5188 void 5189 BView::_UpdateStateForRemove() 5190 { 5191 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 5192 if (!_CheckOwnerLockAndSwitchCurrent()) 5193 return; 5194 5195 fState->UpdateFrom(*fOwner->fLink); 5196 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 5197 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 5198 // 5199 // status_t code; 5200 // if (fOwner->fLink->FlushWithReply(code) == B_OK 5201 // && code == B_OK) { 5202 // fOwner->fLink->Read<BPoint>(&fParentOffset); 5203 // fOwner->fLink->Read<BRect>(&fBounds); 5204 // fState->valid_flags |= B_VIEW_FRAME_BIT; 5205 // } 5206 // } 5207 5208 // update children as well 5209 5210 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 5211 if (child->fOwner) 5212 child->_UpdateStateForRemove(); 5213 } 5214 } 5215 5216 5217 inline void 5218 BView::_UpdatePattern(::pattern pattern) 5219 { 5220 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 5221 return; 5222 5223 if (fOwner) { 5224 _CheckLockAndSwitchCurrent(); 5225 5226 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 5227 fOwner->fLink->Attach< ::pattern>(pattern); 5228 5229 fState->valid_flags |= B_VIEW_PATTERN_BIT; 5230 } 5231 5232 fState->pattern = pattern; 5233 } 5234 5235 5236 void 5237 BView::_FlushIfNotInTransaction() 5238 { 5239 if (!fOwner->fInTransaction) { 5240 fOwner->Flush(); 5241 } 5242 } 5243 5244 5245 BShelf * 5246 BView::_Shelf() const 5247 { 5248 return fShelf; 5249 } 5250 5251 5252 void 5253 BView::_SetShelf(BShelf *shelf) 5254 { 5255 if (fShelf != NULL && fOwner != NULL) 5256 fOwner->RemoveHandler(fShelf); 5257 5258 fShelf = shelf; 5259 5260 if (fShelf != NULL && fOwner != NULL) 5261 fOwner->AddHandler(fShelf); 5262 } 5263 5264 5265 status_t 5266 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 5267 uint32 followFlags, uint32 options) 5268 { 5269 if (!_CheckOwnerLockAndSwitchCurrent()) 5270 return B_ERROR; 5271 5272 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 5273 5274 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 5275 fOwner->fLink->Attach<int32>(serverToken); 5276 fOwner->fLink->Attach<BRect>(srcRect); 5277 fOwner->fLink->Attach<BRect>(dstRect); 5278 fOwner->fLink->Attach<int32>(followFlags); 5279 fOwner->fLink->Attach<int32>(options); 5280 5281 status_t status = B_ERROR; 5282 fOwner->fLink->FlushWithReply(status); 5283 5284 return status; 5285 } 5286 5287 5288 bool 5289 BView::_CheckOwnerLockAndSwitchCurrent() const 5290 { 5291 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()...", Name())); 5292 5293 if (fOwner == NULL) { 5294 debugger("View method requires owner and doesn't have one."); 5295 return false; 5296 } 5297 5298 _CheckLockAndSwitchCurrent(); 5299 5300 return true; 5301 } 5302 5303 5304 bool 5305 BView::_CheckOwnerLock() const 5306 { 5307 if (fOwner) { 5308 fOwner->check_lock(); 5309 return true; 5310 } else { 5311 debugger("View method requires owner and doesn't have one."); 5312 return false; 5313 } 5314 } 5315 5316 5317 void 5318 BView::_CheckLockAndSwitchCurrent() const 5319 { 5320 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()...", Name() ? Name(): "NULL")); 5321 5322 if (!fOwner) 5323 return; 5324 5325 fOwner->check_lock(); 5326 5327 _SwitchServerCurrentView(); 5328 } 5329 5330 5331 void 5332 BView::_CheckLock() const 5333 { 5334 if (fOwner) 5335 fOwner->check_lock(); 5336 } 5337 5338 5339 void 5340 BView::_SwitchServerCurrentView() const 5341 { 5342 int32 serverToken = _get_object_token_(this); 5343 5344 if (fOwner->fLastViewToken != serverToken) { 5345 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 5346 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 5347 fOwner->fLink->Attach<int32>(serverToken); 5348 5349 fOwner->fLastViewToken = serverToken; 5350 } else { 5351 STRACE(("quiet2\n")); 5352 } 5353 } 5354 5355 5356 extern "C" void 5357 _ReservedView1__5BView(BView* view, BRect rect) 5358 { 5359 view->BView::DrawAfterChildren(rect); 5360 } 5361 5362 5363 extern "C" void 5364 _ReservedView2__5BView(BView* view) 5365 { 5366 // MinSize() 5367 perform_data_min_size data; 5368 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 5369 } 5370 5371 5372 extern "C" void 5373 _ReservedView3__5BView(BView* view) 5374 { 5375 // MaxSize() 5376 perform_data_max_size data; 5377 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 5378 } 5379 5380 5381 extern "C" BSize 5382 _ReservedView4__5BView(BView* view) 5383 { 5384 // PreferredSize() 5385 perform_data_preferred_size data; 5386 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 5387 return data.return_value; 5388 } 5389 5390 5391 extern "C" BAlignment 5392 _ReservedView5__5BView(BView* view) 5393 { 5394 // LayoutAlignment() 5395 perform_data_layout_alignment data; 5396 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 5397 return data.return_value; 5398 } 5399 5400 5401 extern "C" bool 5402 _ReservedView6__5BView(BView* view) 5403 { 5404 // HasHeightForWidth() 5405 perform_data_has_height_for_width data; 5406 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 5407 return data.return_value; 5408 } 5409 5410 5411 extern "C" void 5412 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 5413 float* preferred) 5414 { 5415 // GetHeightForWidth() 5416 perform_data_get_height_for_width data; 5417 data.width = width; 5418 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 5419 if (min != NULL) 5420 *min = data.min; 5421 if (max != NULL) 5422 *max = data.max; 5423 if (preferred != NULL) 5424 *preferred = data.preferred; 5425 } 5426 5427 5428 extern "C" void 5429 _ReservedView8__5BView(BView* view, BLayout* layout) 5430 { 5431 // SetLayout() 5432 perform_data_set_layout data; 5433 data.layout = layout; 5434 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 5435 } 5436 5437 5438 extern "C" void 5439 _ReservedView9__5BView(BView* view, bool descendants) 5440 { 5441 // InvalidateLayout() 5442 perform_data_invalidate_layout data; 5443 data.descendants = descendants; 5444 view->Perform(PERFORM_CODE_INVALIDATE_LAYOUT, &data); 5445 } 5446 5447 5448 extern "C" void 5449 _ReservedView10__5BView(BView* view) 5450 { 5451 // DoLayout() 5452 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 5453 } 5454 5455 5456 void BView::_ReservedView11(){} 5457 void BView::_ReservedView12(){} 5458 void BView::_ReservedView13(){} 5459 void BView::_ReservedView14(){} 5460 void BView::_ReservedView15(){} 5461 void BView::_ReservedView16(){} 5462 5463 5464 BView::BView(const BView &other) 5465 : BHandler() 5466 { 5467 // this is private and not functional, but exported 5468 } 5469 5470 5471 BView & 5472 BView::operator=(const BView &other) 5473 { 5474 // this is private and not functional, but exported 5475 return *this; 5476 } 5477 5478 5479 void 5480 BView::_PrintToStream() 5481 { 5482 printf("BView::_PrintToStream()\n"); 5483 printf("\tName: %s\n" 5484 "\tParent: %s\n" 5485 "\tFirstChild: %s\n" 5486 "\tNextSibling: %s\n" 5487 "\tPrevSibling: %s\n" 5488 "\tOwner(Window): %s\n" 5489 "\tToken: %ld\n" 5490 "\tFlags: %ld\n" 5491 "\tView origin: (%f,%f)\n" 5492 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 5493 "\tShow level: %d\n" 5494 "\tTopView?: %s\n" 5495 "\tBPicture: %s\n" 5496 "\tVertical Scrollbar %s\n" 5497 "\tHorizontal Scrollbar %s\n" 5498 "\tIs Printing?: %s\n" 5499 "\tShelf?: %s\n" 5500 "\tEventMask: %ld\n" 5501 "\tEventOptions: %ld\n", 5502 Name(), 5503 fParent ? fParent->Name() : "NULL", 5504 fFirstChild ? fFirstChild->Name() : "NULL", 5505 fNextSibling ? fNextSibling->Name() : "NULL", 5506 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 5507 fOwner ? fOwner->Name() : "NULL", 5508 _get_object_token_(this), 5509 fFlags, 5510 fParentOffset.x, fParentOffset.y, 5511 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 5512 fShowLevel, 5513 fTopLevelView ? "YES" : "NO", 5514 fCurrentPicture? "YES" : "NULL", 5515 fVerScroller? "YES" : "NULL", 5516 fHorScroller? "YES" : "NULL", 5517 fIsPrinting? "YES" : "NO", 5518 fShelf? "YES" : "NO", 5519 fEventMask, 5520 fEventOptions); 5521 5522 printf("\tState status:\n" 5523 "\t\tLocalCoordianteSystem: (%f,%f)\n" 5524 "\t\tPenLocation: (%f,%f)\n" 5525 "\t\tPenSize: %f\n" 5526 "\t\tHighColor: [%d,%d,%d,%d]\n" 5527 "\t\tLowColor: [%d,%d,%d,%d]\n" 5528 "\t\tViewColor: [%d,%d,%d,%d]\n" 5529 "\t\tPattern: %llx\n" 5530 "\t\tDrawingMode: %d\n" 5531 "\t\tLineJoinMode: %d\n" 5532 "\t\tLineCapMode: %d\n" 5533 "\t\tMiterLimit: %f\n" 5534 "\t\tAlphaSource: %d\n" 5535 "\t\tAlphaFuntion: %d\n" 5536 "\t\tScale: %f\n" 5537 "\t\t(Print)FontAliasing: %s\n" 5538 "\t\tFont Info:\n", 5539 fState->origin.x, fState->origin.y, 5540 fState->pen_location.x, fState->pen_location.y, 5541 fState->pen_size, 5542 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 5543 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 5544 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 5545 *((uint64*)&(fState->pattern)), 5546 fState->drawing_mode, 5547 fState->line_join, 5548 fState->line_cap, 5549 fState->miter_limit, 5550 fState->alpha_source_mode, 5551 fState->alpha_function_mode, 5552 fState->scale, 5553 fState->font_aliasing? "YES" : "NO"); 5554 5555 fState->font.PrintToStream(); 5556 5557 // TODO: also print the line array. 5558 } 5559 5560 5561 void 5562 BView::_PrintTree() 5563 { 5564 int32 spaces = 2; 5565 BView *c = fFirstChild; //c = short for: current 5566 printf( "'%s'\n", Name() ); 5567 if (c != NULL) { 5568 while(true) { 5569 // action block 5570 { 5571 for (int i = 0; i < spaces; i++) 5572 printf(" "); 5573 5574 printf( "'%s'\n", c->Name() ); 5575 } 5576 5577 // go deep 5578 if (c->fFirstChild) { 5579 c = c->fFirstChild; 5580 spaces += 2; 5581 } else { 5582 // go right 5583 if (c->fNextSibling) { 5584 c = c->fNextSibling; 5585 } else { 5586 // go up 5587 while (!c->fParent->fNextSibling && c->fParent != this) { 5588 c = c->fParent; 5589 spaces -= 2; 5590 } 5591 5592 // that enough! We've reached this view. 5593 if (c->fParent == this) 5594 break; 5595 5596 c = c->fParent->fNextSibling; 5597 spaces -= 2; 5598 } 5599 } 5600 } 5601 } 5602 } 5603