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