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