1 /* 2 * Copyright 2001-2007, 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_LAYER_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_LAYER_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_LAYER_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 { 350 _InitData(BRect(0, 0, 0, 0), name, B_FOLLOW_NONE, 351 flags | B_SUPPORTS_LAYOUT); 352 SetLayout(layout); 353 } 354 355 356 BView::BView(BRect frame, const char *name, uint32 resizingMode, uint32 flags) 357 : BHandler(name) 358 { 359 _InitData(frame, name, resizingMode, flags); 360 } 361 362 363 BView::BView(BMessage *archive) 364 : BHandler(archive) 365 { 366 BRect frame; 367 archive->FindRect("_frame", &frame); 368 369 uint32 resizingMode; 370 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK) 371 resizingMode = 0; 372 373 uint32 flags; 374 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK) 375 flags = 0; 376 377 _InitData(frame, Name(), resizingMode, flags); 378 379 font_family family; 380 font_style style; 381 if (archive->FindString("_fname", 0, (const char **)&family) == B_OK 382 && archive->FindString("_fname", 1, (const char **)&style) == B_OK) { 383 BFont font; 384 font.SetFamilyAndStyle(family, style); 385 386 float size; 387 if (archive->FindFloat("_fflt", 0, &size) == B_OK) 388 font.SetSize(size); 389 390 float shear; 391 if (archive->FindFloat("_fflt", 1, &shear) == B_OK) 392 font.SetShear(shear); 393 394 float rotation; 395 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK) 396 font.SetRotation(rotation); 397 398 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE 399 | B_FONT_SHEAR | B_FONT_ROTATION); 400 } 401 402 rgb_color color; 403 if (archive->FindInt32("_color", 0, (int32 *)&color) == B_OK) 404 SetHighColor(color); 405 if (archive->FindInt32("_color", 1, (int32 *)&color) == B_OK) 406 SetLowColor(color); 407 if (archive->FindInt32("_color", 2, (int32 *)&color) == B_OK) 408 SetViewColor(color); 409 410 uint32 evMask; 411 uint32 options; 412 if (archive->FindInt32("_evmask", 0, (int32 *)&evMask) == B_OK 413 && archive->FindInt32("_evmask", 1, (int32 *)&options) == B_OK) 414 SetEventMask(evMask, options); 415 416 BPoint origin; 417 if (archive->FindPoint("_origin", &origin) == B_OK) 418 SetOrigin(origin); 419 420 float penSize; 421 if (archive->FindFloat("_psize", &penSize) == B_OK) 422 SetPenSize(penSize); 423 424 BPoint penLocation; 425 if (archive->FindPoint("_ploc", &penLocation) == B_OK) 426 MovePenTo(penLocation); 427 428 int16 lineCap; 429 int16 lineJoin; 430 float lineMiter; 431 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK 432 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK 433 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK) 434 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter); 435 436 int16 alphaBlend; 437 int16 modeBlend; 438 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK 439 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK) 440 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend); 441 442 uint32 drawingMode; 443 if (archive->FindInt32("_dmod", (int32 *)&drawingMode) == B_OK) 444 SetDrawingMode((drawing_mode)drawingMode); 445 446 BMessage msg; 447 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK; i++) { 448 BArchivable *object = instantiate_object(&msg); 449 if (BView *child = dynamic_cast<BView *>(object)) 450 AddChild(child); 451 } 452 } 453 454 455 BArchivable * 456 BView::Instantiate(BMessage *data) 457 { 458 if (!validate_instantiation(data , "BView")) 459 return NULL; 460 461 return new BView(data); 462 } 463 464 465 status_t 466 BView::Archive(BMessage *data, bool deep) const 467 { 468 status_t ret = BHandler::Archive(data, deep); 469 if (ret != B_OK) 470 return ret; 471 472 if (fState->archiving_flags & B_VIEW_FRAME_BIT) 473 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset)); 474 475 if (ret == B_OK) 476 ret = data->AddInt32("_resize_mode", ResizingMode()); 477 478 if (ret == B_OK) 479 ret = data->AddInt32("_flags", Flags()); 480 481 if (ret == B_OK && fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) { 482 ret = data->AddInt32("_evmask", fEventMask); 483 if (ret == B_OK) 484 ret = data->AddInt32("_evmask", fEventOptions); 485 } 486 487 if (ret == B_OK && fState->archiving_flags & B_VIEW_FONT_BIT) { 488 BFont font; 489 GetFont(&font); 490 491 font_family family; 492 font_style style; 493 font.GetFamilyAndStyle(&family, &style); 494 ret = data->AddString("_fname", family); 495 if (ret == B_OK) 496 ret = data->AddString("_fname", style); 497 if (ret == B_OK) 498 ret = data->AddFloat("_fflt", font.Size()); 499 if (ret == B_OK) 500 ret = data->AddFloat("_fflt", font.Shear()); 501 if (ret == B_OK) 502 ret = data->AddFloat("_fflt", font.Rotation()); 503 } 504 505 // colors 506 if (ret == B_OK) 507 ret = data->AddInt32("_color", get_uint32_color(HighColor())); 508 509 if (ret == B_OK) 510 ret = data->AddInt32("_color", get_uint32_color(LowColor())); 511 512 if (ret == B_OK) 513 ret = data->AddInt32("_color", get_uint32_color(ViewColor())); 514 515 // NOTE: we do not use this flag any more 516 // if ( 1 ){ 517 // ret = data->AddInt32("_dbuf", 1); 518 // } 519 520 if (ret == B_OK && fState->archiving_flags & B_VIEW_ORIGIN_BIT) 521 ret = data->AddPoint("_origin", Origin()); 522 523 if (ret == B_OK && fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) 524 ret = data->AddFloat("_psize", PenSize()); 525 526 if (ret == B_OK && fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) 527 ret = data->AddPoint("_ploc", PenLocation()); 528 529 if (ret == B_OK && fState->archiving_flags & B_VIEW_LINE_MODES_BIT) { 530 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode()); 531 if (ret == B_OK) 532 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode()); 533 if (ret == B_OK) 534 ret = data->AddFloat("_lmmiter", LineMiterLimit()); 535 } 536 537 if (ret == B_OK && fState->archiving_flags & B_VIEW_BLENDING_BIT) { 538 source_alpha alphaSourceMode; 539 alpha_function alphaFunctionMode; 540 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode); 541 542 ret = data->AddInt16("_blend", (int16)alphaSourceMode); 543 if (ret == B_OK) 544 ret = data->AddInt16("_blend", (int16)alphaFunctionMode); 545 } 546 547 if (ret == B_OK && fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) 548 ret = data->AddInt32("_dmod", DrawingMode()); 549 550 if (deep) { 551 int32 i = 0; 552 BView *child; 553 554 while (ret == B_OK && (child = ChildAt(i++)) != NULL) { 555 BMessage childArchive; 556 557 ret = child->Archive(&childArchive, deep); 558 if (ret == B_OK) 559 ret = data->AddMessage("_views", &childArchive); 560 } 561 } 562 563 return ret; 564 } 565 566 567 BView::~BView() 568 { 569 STRACE(("BView(%s)::~BView()\n", this->Name())); 570 571 if (fOwner) 572 debugger("Trying to delete a view that belongs to a window. Call RemoveSelf first."); 573 574 RemoveSelf(); 575 576 // TODO: see about BShelf! must I delete it here? is it deleted by the window? 577 578 // we also delete all our children 579 580 BView *child = fFirstChild; 581 while (child) { 582 BView *nextChild = child->fNextSibling; 583 584 delete child; 585 child = nextChild; 586 } 587 588 // delete the layout and the layout data 589 delete fLayoutData->fLayout; 590 delete fLayoutData; 591 592 if (fVerScroller) 593 fVerScroller->SetTarget((BView*)NULL); 594 if (fHorScroller) 595 fHorScroller->SetTarget((BView*)NULL); 596 597 SetName(NULL); 598 599 _RemoveCommArray(); 600 delete fState; 601 } 602 603 604 BRect 605 BView::Bounds() const 606 { 607 // do we need to update our bounds? 608 609 // TODO: why should our frame be out of sync ever? 610 /* 611 if (!fState->IsValid(B_VIEW_FRAME_BIT) && fOwner) { 612 _CheckLockAndSwitchCurrent(); 613 614 fOwner->fLink->StartMessage(AS_LAYER_GET_COORD); 615 616 int32 code; 617 if (fOwner->fLink->FlushWithReply(code) == B_OK 618 && code == B_OK) { 619 fOwner->fLink->Read<BPoint>(const_cast<BPoint *>(&fParentOffset)); 620 fOwner->fLink->Read<BRect>(const_cast<BRect *>(&fBounds)); 621 fState->valid_flags |= B_VIEW_FRAME_BIT; 622 } 623 } 624 */ 625 return fBounds; 626 } 627 628 629 void 630 BView::_ConvertToParent(BPoint *point, bool checkLock) const 631 { 632 if (!fParent) 633 return; 634 635 if (checkLock) 636 _CheckLock(); 637 638 // - our scrolling offset 639 // + our bounds location within the parent 640 point->x += -fBounds.left + fParentOffset.x; 641 point->y += -fBounds.top + fParentOffset.y; 642 } 643 644 void 645 BView::ConvertToParent(BPoint *point) const 646 { 647 _ConvertToParent(point, true); 648 } 649 650 651 BPoint 652 BView::ConvertToParent(BPoint point) const 653 { 654 ConvertToParent(&point); 655 656 return point; 657 } 658 659 660 void 661 BView::_ConvertFromParent(BPoint *point, bool checkLock) const 662 { 663 if (!fParent) 664 return; 665 666 if (checkLock) 667 _CheckLock(); 668 669 // - our bounds location within the parent 670 // + our scrolling offset 671 point->x += -fParentOffset.x + fBounds.left; 672 point->y += -fParentOffset.y + fBounds.top; 673 } 674 675 void 676 BView::ConvertFromParent(BPoint *point) const 677 { 678 _ConvertFromParent(point, true); 679 } 680 681 682 BPoint 683 BView::ConvertFromParent(BPoint point) const 684 { 685 ConvertFromParent(&point); 686 687 return point; 688 } 689 690 691 void 692 BView::ConvertToParent(BRect *rect) const 693 { 694 if (!fParent) 695 return; 696 697 _CheckLock(); 698 699 // - our scrolling offset 700 // + our bounds location within the parent 701 rect->OffsetBy(-fBounds.left + fParentOffset.x, 702 -fBounds.top + fParentOffset.y); 703 } 704 705 706 BRect 707 BView::ConvertToParent(BRect rect) const 708 { 709 ConvertToParent(&rect); 710 711 return rect; 712 } 713 714 715 void 716 BView::ConvertFromParent(BRect *rect) const 717 { 718 if (!fParent) 719 return; 720 721 _CheckLock(); 722 723 // - our bounds location within the parent 724 // + our scrolling offset 725 rect->OffsetBy(-fParentOffset.x + fBounds.left, 726 -fParentOffset.y + fBounds.top); 727 } 728 729 730 BRect 731 BView::ConvertFromParent(BRect rect) const 732 { 733 ConvertFromParent(&rect); 734 735 return rect; 736 } 737 738 739 void 740 BView::_ConvertToScreen(BPoint *pt, bool checkLock) const 741 { 742 if (!fParent) { 743 if (fOwner) 744 fOwner->ConvertToScreen(pt); 745 746 return; 747 } 748 749 if (checkLock) 750 _CheckOwnerLock(); 751 752 _ConvertToParent(pt, false); 753 fParent->_ConvertToScreen(pt, false); 754 } 755 756 757 void 758 BView::ConvertToScreen(BPoint *pt) const 759 { 760 _ConvertToScreen(pt, true); 761 } 762 763 764 BPoint 765 BView::ConvertToScreen(BPoint pt) const 766 { 767 ConvertToScreen(&pt); 768 769 return pt; 770 } 771 772 773 void 774 BView::_ConvertFromScreen(BPoint *pt, bool checkLock) const 775 { 776 if (!fParent) { 777 if (fOwner) 778 fOwner->ConvertFromScreen(pt); 779 780 return; 781 } 782 783 if (checkLock) 784 _CheckOwnerLock(); 785 786 _ConvertFromParent(pt, false); 787 fParent->_ConvertFromScreen(pt, false); 788 } 789 790 void 791 BView::ConvertFromScreen(BPoint *pt) const 792 { 793 _ConvertFromScreen(pt, true); 794 } 795 796 797 BPoint 798 BView::ConvertFromScreen(BPoint pt) const 799 { 800 ConvertFromScreen(&pt); 801 802 return pt; 803 } 804 805 806 void 807 BView::ConvertToScreen(BRect *rect) const 808 { 809 BPoint offset(0.0, 0.0); 810 ConvertToScreen(&offset); 811 rect->OffsetBy(offset); 812 } 813 814 815 BRect 816 BView::ConvertToScreen(BRect rect) const 817 { 818 ConvertToScreen(&rect); 819 820 return rect; 821 } 822 823 824 void 825 BView::ConvertFromScreen(BRect *rect) const 826 { 827 BPoint offset(0.0, 0.0); 828 ConvertFromScreen(&offset); 829 rect->OffsetBy(offset); 830 } 831 832 833 BRect 834 BView::ConvertFromScreen(BRect rect) const 835 { 836 ConvertFromScreen(&rect); 837 838 return rect; 839 } 840 841 842 uint32 843 BView::Flags() const 844 { 845 _CheckLock(); 846 return fFlags & ~_RESIZE_MASK_; 847 } 848 849 850 void 851 BView::SetFlags(uint32 flags) 852 { 853 if (Flags() == flags) 854 return; 855 856 if (fOwner) { 857 if (flags & B_PULSE_NEEDED) { 858 _CheckLock(); 859 if (fOwner->fPulseRunner == NULL) 860 fOwner->SetPulseRate(fOwner->PulseRate()); 861 } 862 863 if (flags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 864 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) { 865 _CheckLockAndSwitchCurrent(); 866 867 fOwner->fLink->StartMessage(AS_LAYER_SET_FLAGS); 868 fOwner->fLink->Attach<uint32>(flags); 869 } 870 } 871 872 /* Some useful info: 873 fFlags is a unsigned long (32 bits) 874 * bits 1-16 are used for BView's flags 875 * bits 17-32 are used for BView' resize mask 876 * _RESIZE_MASK_ is used for that. Look into View.h to see how 877 it's defined 878 */ 879 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_); 880 881 fState->archiving_flags |= B_VIEW_FLAGS_BIT; 882 } 883 884 885 BRect 886 BView::Frame() const 887 { 888 _CheckLock(); 889 890 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y); 891 } 892 893 894 void 895 BView::Hide() 896 { 897 if (fOwner && fShowLevel == 0) { 898 _CheckLockAndSwitchCurrent(); 899 fOwner->fLink->StartMessage(AS_LAYER_HIDE); 900 } 901 fShowLevel++; 902 903 if (fShowLevel == 1 && fParent) 904 fParent->InvalidateLayout(); 905 } 906 907 908 void 909 BView::Show() 910 { 911 fShowLevel--; 912 if (fOwner && fShowLevel == 0) { 913 _CheckLockAndSwitchCurrent(); 914 fOwner->fLink->StartMessage(AS_LAYER_SHOW); 915 } 916 917 if (fShowLevel == 0 && fParent) 918 fParent->InvalidateLayout(); 919 } 920 921 922 bool 923 BView::IsFocus() const 924 { 925 if (fOwner) { 926 _CheckLock(); 927 return fOwner->CurrentFocus() == this; 928 } else 929 return false; 930 } 931 932 933 bool 934 BView::IsHidden(const BView *lookingFrom) const 935 { 936 if (fShowLevel > 0) 937 return true; 938 939 // may we be egocentric? 940 if (lookingFrom == this) 941 return false; 942 943 // we have the same visibility state as our 944 // parent, if there is one 945 if (fParent) 946 return fParent->IsHidden(lookingFrom); 947 948 // if we're the top view, and we're interested 949 // in the "global" view, we're inheriting the 950 // state of the window's visibility 951 if (fOwner && lookingFrom == NULL) 952 return fOwner->IsHidden(); 953 954 return false; 955 } 956 957 958 bool 959 BView::IsHidden() const 960 { 961 return IsHidden(NULL); 962 } 963 964 965 bool 966 BView::IsPrinting() const 967 { 968 return f_is_printing; 969 } 970 971 972 BPoint 973 BView::LeftTop() const 974 { 975 return Bounds().LeftTop(); 976 } 977 978 979 void 980 BView::SetOrigin(BPoint pt) 981 { 982 SetOrigin(pt.x, pt.y); 983 } 984 985 986 void 987 BView::SetOrigin(float x, float y) 988 { 989 if (fState->IsValid(B_VIEW_ORIGIN_BIT) 990 && x == fState->origin.x && y == fState->origin.y) 991 return; 992 993 fState->origin.x = x; 994 fState->origin.y = y; 995 996 if (_CheckOwnerLockAndSwitchCurrent()) { 997 fOwner->fLink->StartMessage(AS_LAYER_SET_ORIGIN); 998 fOwner->fLink->Attach<float>(x); 999 fOwner->fLink->Attach<float>(y); 1000 1001 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1002 } 1003 1004 // our local coord system origin has changed, so when archiving we'll add this too 1005 fState->archiving_flags |= B_VIEW_ORIGIN_BIT; 1006 } 1007 1008 1009 BPoint 1010 BView::Origin() const 1011 { 1012 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) { 1013 // we don't keep graphics state information, therefor 1014 // we need to ask the server for the origin after PopState() 1015 _CheckOwnerLockAndSwitchCurrent(); 1016 1017 fOwner->fLink->StartMessage(AS_LAYER_GET_ORIGIN); 1018 1019 int32 code; 1020 if (fOwner->fLink->FlushWithReply(code) == B_OK 1021 && code == B_OK) { 1022 fOwner->fLink->Read<BPoint>(&fState->origin); 1023 1024 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1025 } 1026 } 1027 1028 return fState->origin; 1029 } 1030 1031 1032 void 1033 BView::SetResizingMode(uint32 mode) 1034 { 1035 if (fOwner) { 1036 _CheckLockAndSwitchCurrent(); 1037 1038 fOwner->fLink->StartMessage(AS_LAYER_RESIZE_MODE); 1039 fOwner->fLink->Attach<uint32>(mode); 1040 } 1041 1042 // look at SetFlags() for more info on the below line 1043 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_); 1044 } 1045 1046 1047 uint32 1048 BView::ResizingMode() const 1049 { 1050 return fFlags & _RESIZE_MASK_; 1051 } 1052 1053 1054 void 1055 BView::SetViewCursor(const BCursor *cursor, bool sync) 1056 { 1057 if (cursor == NULL || fOwner == NULL) 1058 return; 1059 1060 _CheckLockAndSwitchCurrent(); 1061 1062 fOwner->fLink->StartMessage(AS_LAYER_SET_CURSOR); 1063 fOwner->fLink->Attach<int32>(cursor->fServerToken); 1064 fOwner->fLink->Attach<bool>(sync); 1065 1066 if (!sync) { 1067 cursor->fPendingViewCursor = true; 1068 // this avoids a race condition in case the cursor is 1069 // immediately deleted after this call, as the deletion 1070 // is handled by the application, not the window 1071 } else { 1072 // make sure the server has processed the 1073 // message and "acquired" the cursor in 1074 // the window thread before returning from 1075 // this function 1076 int32 code; 1077 fOwner->fLink->FlushWithReply(code); 1078 } 1079 } 1080 1081 1082 void 1083 BView::Flush() const 1084 { 1085 if (fOwner) 1086 fOwner->Flush(); 1087 } 1088 1089 1090 void 1091 BView::Sync() const 1092 { 1093 _CheckOwnerLock(); 1094 if (fOwner) 1095 fOwner->Sync(); 1096 } 1097 1098 1099 BWindow * 1100 BView::Window() const 1101 { 1102 return fOwner; 1103 } 1104 1105 1106 // #pragma mark - Hook Functions 1107 1108 1109 void 1110 BView::AttachedToWindow() 1111 { 1112 // Hook function 1113 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name())); 1114 } 1115 1116 1117 void 1118 BView::AllAttached() 1119 { 1120 // Hook function 1121 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name())); 1122 } 1123 1124 1125 void 1126 BView::DetachedFromWindow() 1127 { 1128 // Hook function 1129 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name())); 1130 } 1131 1132 1133 void 1134 BView::AllDetached() 1135 { 1136 // Hook function 1137 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name())); 1138 } 1139 1140 1141 void 1142 BView::Draw(BRect updateRect) 1143 { 1144 // Hook function 1145 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name())); 1146 } 1147 1148 1149 void 1150 BView::DrawAfterChildren(BRect r) 1151 { 1152 // HOOK function 1153 1154 // NOTE: DrawAfterChildren is called if the corresponding 1155 // flag is set, but it will currently not work as expected, 1156 // since the app_server does not allow views to draw *on* 1157 // their children 1158 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name())); 1159 } 1160 1161 1162 void 1163 BView::FrameMoved(BPoint newPosition) 1164 { 1165 // Hook function 1166 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name())); 1167 } 1168 1169 1170 void 1171 BView::FrameResized(float newWidth, float newHeight) 1172 { 1173 // Hook function 1174 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name())); 1175 } 1176 1177 1178 void 1179 BView::GetPreferredSize(float* _width, float* _height) 1180 { 1181 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name())); 1182 1183 *_width = fBounds.Width(); 1184 *_height = fBounds.Height(); 1185 } 1186 1187 1188 void 1189 BView::ResizeToPreferred() 1190 { 1191 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name())); 1192 1193 float width; 1194 float height; 1195 GetPreferredSize(&width, &height); 1196 1197 ResizeTo(width, height); 1198 } 1199 1200 1201 void 1202 BView::KeyDown(const char* bytes, int32 numBytes) 1203 { 1204 // Hook function 1205 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name())); 1206 1207 if (Window()) 1208 Window()->_KeyboardNavigation(); 1209 } 1210 1211 1212 void 1213 BView::KeyUp(const char* bytes, int32 numBytes) 1214 { 1215 // Hook function 1216 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name())); 1217 } 1218 1219 1220 void 1221 BView::MouseDown(BPoint where) 1222 { 1223 // Hook function 1224 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name())); 1225 } 1226 1227 1228 void 1229 BView::MouseUp(BPoint where) 1230 { 1231 // Hook function 1232 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name())); 1233 } 1234 1235 1236 void 1237 BView::MouseMoved(BPoint where, uint32 code, const BMessage* a_message) 1238 { 1239 // Hook function 1240 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name())); 1241 } 1242 1243 1244 void 1245 BView::Pulse() 1246 { 1247 // Hook function 1248 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name())); 1249 } 1250 1251 1252 void 1253 BView::TargetedByScrollView(BScrollView* scroll_view) 1254 { 1255 // Hook function 1256 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name())); 1257 } 1258 1259 1260 void 1261 BView::WindowActivated(bool state) 1262 { 1263 // Hook function 1264 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name())); 1265 } 1266 1267 1268 // #pragma mark - Input Functions 1269 1270 1271 void 1272 BView::BeginRectTracking(BRect startRect, uint32 style) 1273 { 1274 if (_CheckOwnerLockAndSwitchCurrent()) { 1275 fOwner->fLink->StartMessage(AS_LAYER_BEGIN_RECT_TRACK); 1276 fOwner->fLink->Attach<BRect>(startRect); 1277 fOwner->fLink->Attach<uint32>(style); 1278 } 1279 } 1280 1281 1282 void 1283 BView::EndRectTracking() 1284 { 1285 if (_CheckOwnerLockAndSwitchCurrent()) 1286 fOwner->fLink->StartMessage(AS_LAYER_END_RECT_TRACK); 1287 } 1288 1289 1290 void 1291 BView::DragMessage(BMessage *message, BRect dragRect, BHandler *replyTo) 1292 { 1293 if (!message) 1294 return; 1295 1296 _CheckOwnerLock(); 1297 1298 // calculate the offset 1299 BPoint offset; 1300 uint32 buttons; 1301 BMessage *current = fOwner->CurrentMessage(); 1302 if (!current || current->FindPoint("be:view_where", &offset) != B_OK) 1303 GetMouse(&offset, &buttons, false); 1304 offset -= dragRect.LeftTop(); 1305 1306 if (!dragRect.IsValid()) { 1307 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo); 1308 return; 1309 } 1310 1311 // TODO: that's not really what should happen - the app_server should take the chance 1312 // *NOT* to need to drag a whole bitmap around but just a frame. 1313 1314 // create a drag bitmap for the rect 1315 BBitmap *bitmap = new BBitmap(dragRect, B_RGBA32); 1316 uint32 *bits = (uint32*)bitmap->Bits(); 1317 uint32 bytesPerRow = bitmap->BytesPerRow(); 1318 uint32 width = dragRect.IntegerWidth() + 1; 1319 uint32 height = dragRect.IntegerHeight() + 1; 1320 uint32 lastRow = (height - 1) * width; 1321 1322 memset(bits, 0x00, height * bytesPerRow); 1323 1324 // top 1325 for (uint32 i = 0; i < width; i += 2) 1326 bits[i] = 0xff000000; 1327 1328 // bottom 1329 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2) 1330 bits[lastRow + i] = 0xff000000; 1331 1332 // left 1333 for (uint32 i = 0; i < lastRow; i += width * 2) 1334 bits[i] = 0xff000000; 1335 1336 // right 1337 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2) 1338 bits[width - 1 + i] = 0xff000000; 1339 1340 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo); 1341 } 1342 1343 1344 void 1345 BView::DragMessage(BMessage *message, BBitmap *image, BPoint offset, 1346 BHandler *replyTo) 1347 { 1348 DragMessage(message, image, B_OP_COPY, offset, replyTo); 1349 } 1350 1351 1352 void 1353 BView::DragMessage(BMessage *message, BBitmap *image, 1354 drawing_mode dragMode, BPoint offset, BHandler *replyTo) 1355 { 1356 if (message == NULL) 1357 return; 1358 1359 if (image == NULL) { 1360 // TODO: workaround for drags without a bitmap - should not be necessary if 1361 // we move the rectangle dragging into the app_server 1362 image = new (nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32); 1363 if (image == NULL) 1364 return; 1365 } 1366 1367 if (replyTo == NULL) 1368 replyTo = this; 1369 1370 if (replyTo->Looper() == NULL) 1371 debugger("DragMessage: warning - the Handler needs a looper"); 1372 1373 _CheckOwnerLock(); 1374 1375 if (!message->HasInt32("buttons")) { 1376 BMessage *msg = fOwner->CurrentMessage(); 1377 uint32 buttons; 1378 1379 if (msg == NULL || msg->FindInt32("buttons", (int32 *)&buttons) != B_OK) { 1380 BPoint point; 1381 GetMouse(&point, &buttons, false); 1382 } 1383 1384 message->AddInt32("buttons", buttons); 1385 } 1386 1387 BMessage::Private privateMessage(message); 1388 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper())); 1389 1390 // TODO: create area and flatten message into that area! 1391 // send area info over port, not the actual message! 1392 int32 bufferSize = privateMessage.NativeFlattenedSize(); 1393 char* buffer = new (nothrow) char[bufferSize]; 1394 if (buffer) { 1395 privateMessage.NativeFlatten(buffer, bufferSize); 1396 1397 fOwner->fLink->StartMessage(AS_LAYER_DRAG_IMAGE); 1398 fOwner->fLink->Attach<int32>(image->_ServerToken()); 1399 fOwner->fLink->Attach<int32>((int32)dragMode); 1400 fOwner->fLink->Attach<BPoint>(offset); 1401 fOwner->fLink->Attach<int32>(bufferSize); 1402 fOwner->fLink->Attach(buffer, bufferSize); 1403 1404 // we need to wait for the server 1405 // to actually process this message 1406 // before we can delete the bitmap 1407 int32 code; 1408 fOwner->fLink->FlushWithReply(code); 1409 1410 delete [] buffer; 1411 } else { 1412 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag message\n"); 1413 } 1414 1415 delete image; 1416 } 1417 1418 1419 void 1420 BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue) 1421 { 1422 _CheckOwnerLockAndSwitchCurrent(); 1423 1424 if (checkMessageQueue) { 1425 Window()->UpdateIfNeeded(); 1426 BMessageQueue *queue = Window()->MessageQueue(); 1427 queue->Lock(); 1428 1429 // Look out for mouse update messages 1430 1431 BMessage *message; 1432 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) { 1433 switch (message->what) { 1434 case B_MOUSE_MOVED: 1435 case B_MOUSE_UP: 1436 case B_MOUSE_DOWN: 1437 bool deleteMessage; 1438 if (!Window()->_StealMouseMessage(message, deleteMessage)) 1439 continue; 1440 1441 message->FindPoint("screen_where", location); 1442 message->FindInt32("buttons", (int32 *)buttons); 1443 queue->Unlock(); 1444 // we need to hold the queue lock until here, because 1445 // the message might still be used for something else 1446 1447 ConvertFromScreen(location); 1448 1449 if (deleteMessage) 1450 delete message; 1451 1452 return; 1453 } 1454 } 1455 queue->Unlock(); 1456 } 1457 1458 // If no mouse update message has been found in the message queue, 1459 // we get the current mouse location and buttons from the app_server 1460 1461 fOwner->fLink->StartMessage(AS_GET_MOUSE); 1462 1463 int32 code; 1464 if (fOwner->fLink->FlushWithReply(code) == B_OK 1465 && code == B_OK) { 1466 fOwner->fLink->Read<BPoint>(location); 1467 fOwner->fLink->Read<uint32>(buttons); 1468 // TODO: ServerWindow replies with an int32 here 1469 1470 ConvertFromScreen(location); 1471 // TODO: in beos R5, location is already converted to the view local coordinate system, 1472 // so if an app checks the window message queue by itself, it might not find what it expects. 1473 // NOTE: the fact that we have mouse coords in screen space in our queue avoids the problem 1474 // that messages already in the queue will be outdated as soon as a window or even the 1475 // view moves. The second situation being quite common actually, also with regards to 1476 // scrolling. An app reading these messages would have to know the locations of the window 1477 // and view for each message... otherwise it is potentially broken anyways. 1478 } else 1479 *buttons = 0; 1480 } 1481 1482 1483 void 1484 BView::MakeFocus(bool focusState) 1485 { 1486 if (fOwner) { 1487 // TODO: If this view has focus and focusState==false, 1488 // will there really be no other view with focus? No 1489 // cycling to the next one? 1490 BView *focus = fOwner->CurrentFocus(); 1491 if (focusState) { 1492 // Unfocus a previous focus view 1493 if (focus && focus != this) 1494 focus->MakeFocus(false); 1495 // if we want to make this view the current focus view 1496 fOwner->_SetFocus(this, true); 1497 } else { 1498 // we want to unfocus this view, but only if it actually has focus 1499 if (focus == this) { 1500 fOwner->_SetFocus(NULL, true); 1501 } 1502 } 1503 } 1504 } 1505 1506 1507 BScrollBar * 1508 BView::ScrollBar(orientation posture) const 1509 { 1510 switch (posture) { 1511 case B_VERTICAL: 1512 return fVerScroller; 1513 1514 case B_HORIZONTAL: 1515 return fHorScroller; 1516 1517 default: 1518 return NULL; 1519 } 1520 } 1521 1522 1523 void 1524 BView::ScrollBy(float deltaX, float deltaY) 1525 { 1526 // scrolling by fractional values is not supported 1527 deltaX = roundf(deltaX); 1528 deltaY = roundf(deltaY); 1529 1530 // no reason to process this further if no scroll is intended. 1531 if (deltaX == 0 && deltaY == 0) 1532 return; 1533 1534 // make sure scrolling is within valid bounds 1535 if (fHorScroller) { 1536 float min, max; 1537 fHorScroller->GetRange(&min, &max); 1538 1539 if (deltaX + fBounds.left < min) 1540 deltaX = min - fBounds.left; 1541 else if (deltaX + fBounds.left > max) 1542 deltaX = max - fBounds.left; 1543 } 1544 if (fVerScroller) { 1545 float min, max; 1546 fVerScroller->GetRange(&min, &max); 1547 1548 if (deltaY + fBounds.top < min) 1549 deltaY = min - fBounds.top; 1550 else if (deltaY + fBounds.top > max) 1551 deltaY = max - fBounds.top; 1552 } 1553 1554 _CheckLockAndSwitchCurrent(); 1555 1556 // if we're attached to a window tell app_server about this change 1557 if (fOwner) { 1558 fOwner->fLink->StartMessage(AS_LAYER_SCROLL); 1559 fOwner->fLink->Attach<float>(deltaX); 1560 fOwner->fLink->Attach<float>(deltaY); 1561 1562 fOwner->fLink->Flush(); 1563 1564 // fState->valid_flags &= ~B_VIEW_FRAME_BIT; 1565 } 1566 1567 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver. 1568 fBounds.OffsetBy(deltaX, deltaY); 1569 1570 // then set the new values of the scrollbars 1571 if (fHorScroller) 1572 fHorScroller->SetValue(fBounds.left); 1573 if (fVerScroller) 1574 fVerScroller->SetValue(fBounds.top); 1575 } 1576 1577 1578 void 1579 BView::ScrollTo(BPoint where) 1580 { 1581 ScrollBy(where.x - fBounds.left, where.y - fBounds.top); 1582 } 1583 1584 1585 status_t 1586 BView::SetEventMask(uint32 mask, uint32 options) 1587 { 1588 if (fEventMask == mask && fEventOptions == options) 1589 return B_OK; 1590 1591 fEventMask = mask | (fEventMask & 0xFFFF0000); 1592 fEventOptions = options; 1593 1594 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT; 1595 1596 if (fOwner) { 1597 _CheckLockAndSwitchCurrent(); 1598 1599 fOwner->fLink->StartMessage(AS_LAYER_SET_EVENT_MASK); 1600 fOwner->fLink->Attach<uint32>(mask); 1601 fOwner->fLink->Attach<uint32>(options); 1602 fOwner->fLink->Flush(); 1603 } 1604 1605 return B_OK; 1606 } 1607 1608 1609 uint32 1610 BView::EventMask() 1611 { 1612 return fEventMask; 1613 } 1614 1615 1616 status_t 1617 BView::SetMouseEventMask(uint32 mask, uint32 options) 1618 { 1619 // Just don't do anything if the view is not yet attached 1620 // or we were called outside of BView::MouseDown() 1621 if (fOwner != NULL 1622 && fOwner->CurrentMessage() != NULL 1623 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) { 1624 _CheckLockAndSwitchCurrent(); 1625 fMouseEventOptions = options; 1626 1627 fOwner->fLink->StartMessage(AS_LAYER_SET_MOUSE_EVENT_MASK); 1628 fOwner->fLink->Attach<uint32>(mask); 1629 fOwner->fLink->Attach<uint32>(options); 1630 fOwner->fLink->Flush(); 1631 return B_OK; 1632 } 1633 1634 return B_ERROR; 1635 } 1636 1637 1638 // #pragma mark - Graphic State Functions 1639 1640 1641 void 1642 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) 1643 { 1644 if (fState->IsValid(B_VIEW_LINE_MODES_BIT) 1645 && lineCap == fState->line_cap && lineJoin == fState->line_join 1646 && miterLimit == fState->miter_limit) 1647 return; 1648 1649 if (fOwner) { 1650 _CheckLockAndSwitchCurrent(); 1651 1652 fOwner->fLink->StartMessage(AS_LAYER_SET_LINE_MODE); 1653 fOwner->fLink->Attach<int8>((int8)lineCap); 1654 fOwner->fLink->Attach<int8>((int8)lineJoin); 1655 fOwner->fLink->Attach<float>(miterLimit); 1656 1657 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1658 } 1659 1660 fState->line_cap = lineCap; 1661 fState->line_join = lineJoin; 1662 fState->miter_limit = miterLimit; 1663 1664 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT; 1665 } 1666 1667 1668 join_mode 1669 BView::LineJoinMode() const 1670 { 1671 // This will update the current state, if necessary 1672 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1673 LineMiterLimit(); 1674 1675 return fState->line_join; 1676 } 1677 1678 1679 cap_mode 1680 BView::LineCapMode() const 1681 { 1682 // This will update the current state, if necessary 1683 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1684 LineMiterLimit(); 1685 1686 return fState->line_cap; 1687 } 1688 1689 1690 float 1691 BView::LineMiterLimit() const 1692 { 1693 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) { 1694 _CheckLockAndSwitchCurrent(); 1695 1696 fOwner->fLink->StartMessage(AS_LAYER_GET_LINE_MODE); 1697 1698 int32 code; 1699 if (fOwner->fLink->FlushWithReply(code) == B_OK 1700 && code == B_OK) { 1701 int8 cap, join; 1702 fOwner->fLink->Read<int8>((int8 *)&cap); 1703 fOwner->fLink->Read<int8>((int8 *)&join); 1704 fOwner->fLink->Read<float>(&fState->miter_limit); 1705 1706 fState->line_cap = (cap_mode)cap; 1707 fState->line_join = (join_mode)join; 1708 } 1709 1710 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1711 } 1712 1713 return fState->miter_limit; 1714 } 1715 1716 1717 void 1718 BView::PushState() 1719 { 1720 _CheckOwnerLockAndSwitchCurrent(); 1721 1722 fOwner->fLink->StartMessage(AS_LAYER_PUSH_STATE); 1723 1724 // initialize origin and scale 1725 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT; 1726 fState->scale = 1.0f; 1727 fState->origin.Set(0, 0); 1728 } 1729 1730 1731 void 1732 BView::PopState() 1733 { 1734 _CheckOwnerLockAndSwitchCurrent(); 1735 1736 fOwner->fLink->StartMessage(AS_LAYER_POP_STATE); 1737 1738 // invalidate all flags (except those that are not part of pop/push) 1739 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT; 1740 } 1741 1742 1743 void 1744 BView::SetScale(float scale) const 1745 { 1746 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale) 1747 return; 1748 1749 if (fOwner) { 1750 _CheckLockAndSwitchCurrent(); 1751 1752 fOwner->fLink->StartMessage(AS_LAYER_SET_SCALE); 1753 fOwner->fLink->Attach<float>(scale); 1754 1755 fState->valid_flags |= B_VIEW_SCALE_BIT; 1756 } 1757 1758 fState->scale = scale; 1759 fState->archiving_flags |= B_VIEW_SCALE_BIT; 1760 } 1761 1762 1763 float 1764 BView::Scale() const 1765 { 1766 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) { 1767 _CheckLockAndSwitchCurrent(); 1768 1769 fOwner->fLink->StartMessage(AS_LAYER_GET_SCALE); 1770 1771 int32 code; 1772 if (fOwner->fLink->FlushWithReply(code) == B_OK 1773 && code == B_OK) 1774 fOwner->fLink->Read<float>(&fState->scale); 1775 1776 fState->valid_flags |= B_VIEW_SCALE_BIT; 1777 } 1778 1779 return fState->scale; 1780 } 1781 1782 1783 void 1784 BView::SetDrawingMode(drawing_mode mode) 1785 { 1786 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT) 1787 && mode == fState->drawing_mode) 1788 return; 1789 1790 if (fOwner) { 1791 _CheckLockAndSwitchCurrent(); 1792 1793 fOwner->fLink->StartMessage(AS_LAYER_SET_DRAWING_MODE); 1794 fOwner->fLink->Attach<int8>((int8)mode); 1795 1796 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1797 } 1798 1799 fState->drawing_mode = mode; 1800 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT; 1801 } 1802 1803 1804 drawing_mode 1805 BView::DrawingMode() const 1806 { 1807 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) { 1808 _CheckLockAndSwitchCurrent(); 1809 1810 fOwner->fLink->StartMessage(AS_LAYER_GET_DRAWING_MODE); 1811 1812 int32 code; 1813 if (fOwner->fLink->FlushWithReply(code) == B_OK 1814 && code == B_OK) { 1815 int8 drawingMode; 1816 fOwner->fLink->Read<int8>(&drawingMode); 1817 1818 fState->drawing_mode = (drawing_mode)drawingMode; 1819 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1820 } 1821 } 1822 1823 return fState->drawing_mode; 1824 } 1825 1826 1827 void 1828 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction) 1829 { 1830 if (fState->IsValid(B_VIEW_BLENDING_BIT) 1831 && sourceAlpha == fState->alpha_source_mode 1832 && alphaFunction == fState->alpha_function_mode) 1833 return; 1834 1835 if (fOwner) { 1836 _CheckLockAndSwitchCurrent(); 1837 1838 fOwner->fLink->StartMessage(AS_LAYER_SET_BLENDING_MODE); 1839 fOwner->fLink->Attach<int8>((int8)sourceAlpha); 1840 fOwner->fLink->Attach<int8>((int8)alphaFunction); 1841 1842 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1843 } 1844 1845 fState->alpha_source_mode = sourceAlpha; 1846 fState->alpha_function_mode = alphaFunction; 1847 1848 fState->archiving_flags |= B_VIEW_BLENDING_BIT; 1849 } 1850 1851 1852 void 1853 BView::GetBlendingMode(source_alpha *_sourceAlpha, 1854 alpha_function *_alphaFunction) const 1855 { 1856 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) { 1857 _CheckLockAndSwitchCurrent(); 1858 1859 fOwner->fLink->StartMessage(AS_LAYER_GET_BLENDING_MODE); 1860 1861 int32 code; 1862 if (fOwner->fLink->FlushWithReply(code) == B_OK 1863 && code == B_OK) { 1864 int8 alphaSourceMode, alphaFunctionMode; 1865 fOwner->fLink->Read<int8>(&alphaSourceMode); 1866 fOwner->fLink->Read<int8>(&alphaFunctionMode); 1867 1868 fState->alpha_source_mode = (source_alpha)alphaSourceMode; 1869 fState->alpha_function_mode = (alpha_function)alphaFunctionMode; 1870 1871 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1872 } 1873 } 1874 1875 if (_sourceAlpha) 1876 *_sourceAlpha = fState->alpha_source_mode; 1877 1878 if (_alphaFunction) 1879 *_alphaFunction = fState->alpha_function_mode; 1880 } 1881 1882 1883 void 1884 BView::MovePenTo(BPoint point) 1885 { 1886 MovePenTo(point.x, point.y); 1887 } 1888 1889 1890 void 1891 BView::MovePenTo(float x, float y) 1892 { 1893 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT) 1894 && x == fState->pen_location.x && y == fState->pen_location.y) 1895 return; 1896 1897 if (fOwner) { 1898 _CheckLockAndSwitchCurrent(); 1899 1900 fOwner->fLink->StartMessage(AS_LAYER_SET_PEN_LOC); 1901 fOwner->fLink->Attach<float>(x); 1902 fOwner->fLink->Attach<float>(y); 1903 1904 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 1905 } 1906 1907 fState->pen_location.x = x; 1908 fState->pen_location.y = y; 1909 1910 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT; 1911 } 1912 1913 1914 void 1915 BView::MovePenBy(float x, float y) 1916 { 1917 // this will update the pen location if necessary 1918 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT)) 1919 PenLocation(); 1920 1921 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y); 1922 } 1923 1924 1925 BPoint 1926 BView::PenLocation() const 1927 { 1928 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) { 1929 _CheckLockAndSwitchCurrent(); 1930 1931 fOwner->fLink->StartMessage(AS_LAYER_GET_PEN_LOC); 1932 1933 int32 code; 1934 if (fOwner->fLink->FlushWithReply(code) == B_OK 1935 && code == B_OK) { 1936 fOwner->fLink->Read<BPoint>(&fState->pen_location); 1937 1938 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 1939 } 1940 } 1941 1942 return fState->pen_location; 1943 } 1944 1945 1946 void 1947 BView::SetPenSize(float size) 1948 { 1949 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size) 1950 return; 1951 1952 if (fOwner) { 1953 _CheckLockAndSwitchCurrent(); 1954 1955 fOwner->fLink->StartMessage(AS_LAYER_SET_PEN_SIZE); 1956 fOwner->fLink->Attach<float>(size); 1957 1958 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 1959 } 1960 1961 fState->pen_size = size; 1962 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT; 1963 } 1964 1965 1966 float 1967 BView::PenSize() const 1968 { 1969 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) { 1970 _CheckLockAndSwitchCurrent(); 1971 1972 fOwner->fLink->StartMessage(AS_LAYER_GET_PEN_SIZE); 1973 1974 int32 code; 1975 if (fOwner->fLink->FlushWithReply(code) == B_OK 1976 && code == B_OK) { 1977 fOwner->fLink->Read<float>(&fState->pen_size); 1978 1979 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 1980 } 1981 } 1982 1983 return fState->pen_size; 1984 } 1985 1986 1987 void 1988 BView::SetHighColor(rgb_color color) 1989 { 1990 // are we up-to-date already? 1991 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT) 1992 && fState->high_color == color) 1993 return; 1994 1995 if (fOwner) { 1996 _CheckLockAndSwitchCurrent(); 1997 1998 fOwner->fLink->StartMessage(AS_LAYER_SET_HIGH_COLOR); 1999 fOwner->fLink->Attach<rgb_color>(color); 2000 2001 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2002 } 2003 2004 fState->high_color = color; 2005 2006 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT; 2007 } 2008 2009 2010 rgb_color 2011 BView::HighColor() const 2012 { 2013 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) { 2014 _CheckLockAndSwitchCurrent(); 2015 2016 fOwner->fLink->StartMessage(AS_LAYER_GET_HIGH_COLOR); 2017 2018 int32 code; 2019 if (fOwner->fLink->FlushWithReply(code) == B_OK 2020 && code == B_OK) { 2021 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2022 2023 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2024 } 2025 } 2026 2027 return fState->high_color; 2028 } 2029 2030 2031 void 2032 BView::SetLowColor(rgb_color color) 2033 { 2034 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT) 2035 && fState->low_color == color) 2036 return; 2037 2038 if (fOwner) { 2039 _CheckLockAndSwitchCurrent(); 2040 2041 fOwner->fLink->StartMessage(AS_LAYER_SET_LOW_COLOR); 2042 fOwner->fLink->Attach<rgb_color>(color); 2043 2044 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2045 } 2046 2047 fState->low_color = color; 2048 2049 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT; 2050 } 2051 2052 2053 rgb_color 2054 BView::LowColor() const 2055 { 2056 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) { 2057 _CheckLockAndSwitchCurrent(); 2058 2059 fOwner->fLink->StartMessage(AS_LAYER_GET_LOW_COLOR); 2060 2061 int32 code; 2062 if (fOwner->fLink->FlushWithReply(code) == B_OK 2063 && code == B_OK) { 2064 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2065 2066 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2067 } 2068 } 2069 2070 return fState->low_color; 2071 } 2072 2073 2074 void 2075 BView::SetViewColor(rgb_color color) 2076 { 2077 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color) 2078 return; 2079 2080 if (fOwner) { 2081 _CheckLockAndSwitchCurrent(); 2082 2083 fOwner->fLink->StartMessage(AS_LAYER_SET_VIEW_COLOR); 2084 fOwner->fLink->Attach<rgb_color>(color); 2085 2086 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2087 } 2088 2089 fState->view_color = color; 2090 2091 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT; 2092 } 2093 2094 2095 rgb_color 2096 BView::ViewColor() const 2097 { 2098 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) { 2099 _CheckLockAndSwitchCurrent(); 2100 2101 fOwner->fLink->StartMessage(AS_LAYER_GET_VIEW_COLOR); 2102 2103 int32 code; 2104 if (fOwner->fLink->FlushWithReply(code) == B_OK 2105 && code == B_OK) { 2106 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2107 2108 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2109 } 2110 } 2111 2112 return fState->view_color; 2113 } 2114 2115 2116 void 2117 BView::ForceFontAliasing(bool enable) 2118 { 2119 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) && enable == fState->font_aliasing) 2120 return; 2121 2122 if (fOwner) { 2123 _CheckLockAndSwitchCurrent(); 2124 2125 fOwner->fLink->StartMessage(AS_LAYER_PRINT_ALIASING); 2126 fOwner->fLink->Attach<bool>(enable); 2127 2128 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT; 2129 } 2130 2131 fState->font_aliasing = enable; 2132 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT; 2133 } 2134 2135 2136 void 2137 BView::SetFont(const BFont* font, uint32 mask) 2138 { 2139 if (!font || mask == 0) 2140 return; 2141 2142 if (mask == B_FONT_ALL) { 2143 fState->font = *font; 2144 } else { 2145 // ToDo: move this into a BFont method 2146 if (mask & B_FONT_FAMILY_AND_STYLE) 2147 fState->font.SetFamilyAndStyle(font->FamilyAndStyle()); 2148 2149 if (mask & B_FONT_SIZE) 2150 fState->font.SetSize(font->Size()); 2151 2152 if (mask & B_FONT_SHEAR) 2153 fState->font.SetShear(font->Shear()); 2154 2155 if (mask & B_FONT_ROTATION) 2156 fState->font.SetRotation(font->Rotation()); 2157 2158 if (mask & B_FONT_FALSE_BOLD_WIDTH) 2159 fState->font.SetFalseBoldWidth(font->FalseBoldWidth()); 2160 2161 if (mask & B_FONT_SPACING) 2162 fState->font.SetSpacing(font->Spacing()); 2163 2164 if (mask & B_FONT_ENCODING) 2165 fState->font.SetEncoding(font->Encoding()); 2166 2167 if (mask & B_FONT_FACE) 2168 fState->font.SetFace(font->Face()); 2169 2170 if (mask & B_FONT_FLAGS) 2171 fState->font.SetFlags(font->Flags()); 2172 } 2173 2174 fState->font_flags |= mask; 2175 2176 if (fOwner) { 2177 _CheckLockAndSwitchCurrent(); 2178 2179 fState->UpdateServerFontState(*fOwner->fLink); 2180 } 2181 } 2182 2183 2184 void 2185 BView::GetFont(BFont *font) const 2186 { 2187 *font = fState->font; 2188 } 2189 2190 2191 void 2192 BView::GetFontHeight(font_height *height) const 2193 { 2194 fState->font.GetHeight(height); 2195 } 2196 2197 2198 void 2199 BView::SetFontSize(float size) 2200 { 2201 BFont font; 2202 font.SetSize(size); 2203 2204 SetFont(&font, B_FONT_SIZE); 2205 } 2206 2207 2208 float 2209 BView::StringWidth(const char *string) const 2210 { 2211 return fState->font.StringWidth(string); 2212 } 2213 2214 2215 float 2216 BView::StringWidth(const char* string, int32 length) const 2217 { 2218 return fState->font.StringWidth(string, length); 2219 } 2220 2221 2222 void 2223 BView::GetStringWidths(char *stringArray[],int32 lengthArray[], 2224 int32 numStrings, float widthArray[]) const 2225 { 2226 fState->font.GetStringWidths(const_cast<const char **>(stringArray), 2227 const_cast<const int32 *>(lengthArray), numStrings, widthArray); 2228 } 2229 2230 2231 void 2232 BView::TruncateString(BString *in_out, uint32 mode, float width) const 2233 { 2234 fState->font.TruncateString(in_out, mode, width); 2235 } 2236 2237 2238 void 2239 BView::ClipToPicture(BPicture *picture, BPoint where, bool sync) 2240 { 2241 _ClipToPicture(picture, where, false, sync); 2242 } 2243 2244 2245 void 2246 BView::ClipToInversePicture(BPicture *picture, 2247 BPoint where, bool sync) 2248 { 2249 _ClipToPicture(picture, where, true, sync); 2250 } 2251 2252 2253 void 2254 BView::GetClippingRegion(BRegion* region) const 2255 { 2256 if (!region) 2257 return; 2258 2259 // NOTE: the client has no idea when the clipping in the server 2260 // changed, so it is always read from the serber 2261 region->MakeEmpty(); 2262 2263 if (fOwner) { 2264 _CheckLockAndSwitchCurrent(); 2265 fOwner->fLink->StartMessage(AS_LAYER_GET_CLIP_REGION); 2266 2267 int32 code; 2268 if (fOwner->fLink->FlushWithReply(code) == B_OK 2269 && code == B_OK) { 2270 fOwner->fLink->ReadRegion(region); 2271 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT; 2272 } 2273 } 2274 } 2275 2276 2277 void 2278 BView::ConstrainClippingRegion(BRegion* region) 2279 { 2280 if (_CheckOwnerLockAndSwitchCurrent()) { 2281 fOwner->fLink->StartMessage(AS_LAYER_SET_CLIP_REGION); 2282 2283 if (region) { 2284 int32 count = region->CountRects(); 2285 fOwner->fLink->Attach<int32>(count); 2286 if (count > 0) 2287 fOwner->fLink->AttachRegion(*region); 2288 } else { 2289 fOwner->fLink->Attach<int32>(-1); 2290 // '-1' means that in the app_server, there won't be any 'local' 2291 // clipping region (it will be NULL) 2292 } 2293 2294 _FlushIfNotInTransaction(); 2295 2296 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 2297 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 2298 } 2299 } 2300 2301 2302 // #pragma mark - Drawing Functions 2303 //--------------------------------------------------------------------------- 2304 2305 2306 void 2307 BView::DrawBitmapAsync(const BBitmap *bitmap, BRect srcRect, BRect dstRect) 2308 { 2309 if (!bitmap || !srcRect.IsValid() || !dstRect.IsValid()) 2310 return; 2311 2312 if (fOwner) { 2313 _CheckLockAndSwitchCurrent(); 2314 2315 fOwner->fLink->StartMessage(AS_LAYER_DRAW_BITMAP); 2316 fOwner->fLink->Attach<int32>(bitmap->_ServerToken()); 2317 fOwner->fLink->Attach<BRect>(dstRect); 2318 fOwner->fLink->Attach<BRect>(srcRect); 2319 2320 _FlushIfNotInTransaction(); 2321 } 2322 } 2323 2324 2325 void 2326 BView::DrawBitmapAsync(const BBitmap *bitmap, BRect dstRect) 2327 { 2328 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), dstRect); 2329 } 2330 2331 2332 void 2333 BView::DrawBitmapAsync(const BBitmap *bitmap) 2334 { 2335 DrawBitmapAsync(bitmap, PenLocation()); 2336 } 2337 2338 2339 void 2340 BView::DrawBitmapAsync(const BBitmap *bitmap, BPoint where) 2341 { 2342 if (bitmap == NULL) 2343 return; 2344 2345 if (fOwner) { 2346 _CheckLockAndSwitchCurrent(); 2347 2348 fOwner->fLink->StartMessage(AS_LAYER_DRAW_BITMAP); 2349 fOwner->fLink->Attach<int32>(bitmap->_ServerToken()); 2350 BRect src = bitmap->Bounds().OffsetToCopy(B_ORIGIN); 2351 BRect dst = src.OffsetToCopy(where); 2352 fOwner->fLink->Attach<BRect>(dst); 2353 fOwner->fLink->Attach<BRect>(src); 2354 2355 _FlushIfNotInTransaction(); 2356 } 2357 } 2358 2359 2360 void 2361 BView::DrawBitmap(const BBitmap *bitmap) 2362 { 2363 DrawBitmap(bitmap, PenLocation()); 2364 } 2365 2366 2367 void 2368 BView::DrawBitmap(const BBitmap *bitmap, BPoint where) 2369 { 2370 if (fOwner) { 2371 DrawBitmapAsync(bitmap, where); 2372 Sync(); 2373 } 2374 } 2375 2376 2377 void 2378 BView::DrawBitmap(const BBitmap *bitmap, BRect dstRect) 2379 { 2380 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), dstRect); 2381 } 2382 2383 2384 void 2385 BView::DrawBitmap(const BBitmap *bitmap, BRect srcRect, BRect dstRect) 2386 { 2387 if (fOwner) { 2388 DrawBitmapAsync(bitmap, srcRect, dstRect); 2389 Sync(); 2390 } 2391 } 2392 2393 2394 void 2395 BView::DrawChar(char c) 2396 { 2397 DrawString(&c, 1, PenLocation()); 2398 } 2399 2400 2401 void 2402 BView::DrawChar(char c, BPoint location) 2403 { 2404 DrawString(&c, 1, location); 2405 } 2406 2407 2408 void 2409 BView::DrawString(const char *string, escapement_delta *delta) 2410 { 2411 if (string == NULL) 2412 return; 2413 2414 DrawString(string, strlen(string), PenLocation(), delta); 2415 } 2416 2417 2418 void 2419 BView::DrawString(const char *string, BPoint location, escapement_delta *delta) 2420 { 2421 if (string == NULL) 2422 return; 2423 2424 DrawString(string, strlen(string), location, delta); 2425 } 2426 2427 2428 void 2429 BView::DrawString(const char *string, int32 length, escapement_delta *delta) 2430 { 2431 DrawString(string, length, PenLocation(), delta); 2432 } 2433 2434 2435 void 2436 BView::DrawString(const char *string, int32 length, BPoint location, 2437 escapement_delta *delta) 2438 { 2439 if (string == NULL || length < 1) 2440 return; 2441 2442 if (fOwner) { 2443 _CheckLockAndSwitchCurrent(); 2444 2445 // quite often delta will be NULL 2446 if (delta) 2447 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA); 2448 else 2449 fOwner->fLink->StartMessage(AS_DRAW_STRING); 2450 fOwner->fLink->Attach<int32>(length); 2451 fOwner->fLink->Attach<BPoint>(location); 2452 2453 if (delta) 2454 fOwner->fLink->Attach<escapement_delta>(*delta); 2455 2456 fOwner->fLink->AttachString(string, length); 2457 2458 _FlushIfNotInTransaction(); 2459 2460 // this modifies our pen location, so we invalidate the flag. 2461 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 2462 } 2463 } 2464 2465 2466 void 2467 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, 2468 pattern p) 2469 { 2470 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2471 center.y + yRadius), p); 2472 } 2473 2474 2475 void 2476 BView::StrokeEllipse(BRect rect, ::pattern pattern) 2477 { 2478 if (fOwner == NULL) 2479 return; 2480 2481 _CheckLockAndSwitchCurrent(); 2482 _UpdatePattern(pattern); 2483 2484 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE); 2485 fOwner->fLink->Attach<BRect>(rect); 2486 2487 _FlushIfNotInTransaction(); 2488 } 2489 2490 2491 void 2492 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2493 ::pattern pattern) 2494 { 2495 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2496 center.x + xRadius, center.y + yRadius), pattern); 2497 } 2498 2499 2500 void 2501 BView::FillEllipse(BRect rect, ::pattern pattern) 2502 { 2503 if (fOwner == NULL) 2504 return; 2505 2506 _CheckLockAndSwitchCurrent(); 2507 _UpdatePattern(pattern); 2508 2509 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE); 2510 fOwner->fLink->Attach<BRect>(rect); 2511 2512 _FlushIfNotInTransaction(); 2513 } 2514 2515 2516 void 2517 BView::StrokeArc(BPoint center, float xRadius, float yRadius, 2518 float startAngle, float arcAngle, pattern p) 2519 { 2520 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2521 center.y + yRadius), startAngle, arcAngle, p); 2522 } 2523 2524 2525 void 2526 BView::StrokeArc(BRect rect, float startAngle, float arcAngle, 2527 ::pattern pattern) 2528 { 2529 if (fOwner == NULL) 2530 return; 2531 2532 _CheckLockAndSwitchCurrent(); 2533 _UpdatePattern(pattern); 2534 2535 fOwner->fLink->StartMessage(AS_STROKE_ARC); 2536 fOwner->fLink->Attach<BRect>(rect); 2537 fOwner->fLink->Attach<float>(startAngle); 2538 fOwner->fLink->Attach<float>(arcAngle); 2539 2540 _FlushIfNotInTransaction(); 2541 } 2542 2543 2544 void 2545 BView::FillArc(BPoint center,float xRadius, float yRadius, 2546 float startAngle, float arcAngle, ::pattern pattern) 2547 { 2548 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2549 center.y + yRadius), startAngle, arcAngle, pattern); 2550 } 2551 2552 2553 void 2554 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2555 ::pattern pattern) 2556 { 2557 if (fOwner == NULL) 2558 return; 2559 2560 _CheckLockAndSwitchCurrent(); 2561 _UpdatePattern(pattern); 2562 2563 fOwner->fLink->StartMessage(AS_FILL_ARC); 2564 fOwner->fLink->Attach<BRect>(rect); 2565 fOwner->fLink->Attach<float>(startAngle); 2566 fOwner->fLink->Attach<float>(arcAngle); 2567 2568 _FlushIfNotInTransaction(); 2569 } 2570 2571 2572 void 2573 BView::StrokeBezier(BPoint *controlPoints, ::pattern pattern) 2574 { 2575 if (fOwner == NULL) 2576 return; 2577 2578 _CheckLockAndSwitchCurrent(); 2579 _UpdatePattern(pattern); 2580 2581 fOwner->fLink->StartMessage(AS_STROKE_BEZIER); 2582 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2583 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2584 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2585 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2586 2587 _FlushIfNotInTransaction(); 2588 } 2589 2590 2591 void 2592 BView::FillBezier(BPoint *controlPoints, ::pattern pattern) 2593 { 2594 if (fOwner == NULL) 2595 return; 2596 2597 _CheckLockAndSwitchCurrent(); 2598 _UpdatePattern(pattern); 2599 2600 fOwner->fLink->StartMessage(AS_FILL_BEZIER); 2601 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2602 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2603 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2604 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2605 2606 _FlushIfNotInTransaction(); 2607 } 2608 2609 2610 void 2611 BView::StrokePolygon(const BPolygon *polygon, bool closed, pattern p) 2612 { 2613 if (!polygon) 2614 return; 2615 2616 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, p); 2617 } 2618 2619 2620 void 2621 BView::StrokePolygon(const BPoint *ptArray, int32 numPoints, bool closed, pattern p) 2622 { 2623 BPolygon polygon(ptArray, numPoints); 2624 2625 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, p); 2626 } 2627 2628 2629 void 2630 BView::StrokePolygon(const BPoint *ptArray, int32 numPoints, BRect bounds, 2631 bool closed, ::pattern pattern) 2632 { 2633 if (!ptArray 2634 || numPoints <= 1 2635 || fOwner == NULL) 2636 return; 2637 2638 _CheckLockAndSwitchCurrent(); 2639 _UpdatePattern(pattern); 2640 2641 BPolygon polygon(ptArray, numPoints); 2642 polygon.MapTo(polygon.Frame(), bounds); 2643 2644 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON, 2645 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) + sizeof(int32)) 2646 == B_OK) { 2647 fOwner->fLink->Attach<BRect>(polygon.Frame()); 2648 fOwner->fLink->Attach<bool>(closed); 2649 fOwner->fLink->Attach<int32>(polygon.fCount); 2650 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint)); 2651 2652 _FlushIfNotInTransaction(); 2653 } else { 2654 // TODO: send via an area 2655 fprintf(stderr, "ERROR: polygon to big for BPortLink!\n"); 2656 } 2657 } 2658 2659 2660 void 2661 BView::FillPolygon(const BPolygon *polygon, ::pattern pattern) 2662 { 2663 if (polygon == NULL 2664 || polygon->fCount <= 2 2665 || fOwner == NULL) 2666 return; 2667 2668 _CheckLockAndSwitchCurrent(); 2669 _UpdatePattern(pattern); 2670 2671 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON, 2672 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) == B_OK) { 2673 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2674 fOwner->fLink->Attach<int32>(polygon->fCount); 2675 fOwner->fLink->Attach(polygon->fPoints, polygon->fCount * sizeof(BPoint)); 2676 2677 _FlushIfNotInTransaction(); 2678 } else { 2679 // TODO: send via an area 2680 fprintf(stderr, "ERROR: polygon to big for BPortLink!\n"); 2681 } 2682 } 2683 2684 2685 void 2686 BView::FillPolygon(const BPoint *ptArray, int32 numPts, ::pattern pattern) 2687 { 2688 if (!ptArray) 2689 return; 2690 2691 BPolygon polygon(ptArray, numPts); 2692 FillPolygon(&polygon, pattern); 2693 } 2694 2695 2696 void 2697 BView::FillPolygon(const BPoint *ptArray, int32 numPts, BRect bounds, 2698 pattern p) 2699 { 2700 if (!ptArray) 2701 return; 2702 2703 BPolygon polygon(ptArray, numPts); 2704 2705 polygon.MapTo(polygon.Frame(), bounds); 2706 FillPolygon(&polygon, p); 2707 } 2708 2709 2710 void 2711 BView::StrokeRect(BRect rect, ::pattern pattern) 2712 { 2713 if (fOwner == NULL) 2714 return; 2715 2716 _CheckLockAndSwitchCurrent(); 2717 _UpdatePattern(pattern); 2718 2719 fOwner->fLink->StartMessage(AS_STROKE_RECT); 2720 fOwner->fLink->Attach<BRect>(rect); 2721 2722 _FlushIfNotInTransaction(); 2723 } 2724 2725 2726 void 2727 BView::FillRect(BRect rect, ::pattern pattern) 2728 { 2729 if (fOwner == NULL) 2730 return; 2731 2732 // NOTE: ensuring compatibility with R5, 2733 // invalid rects are not filled, they are stroked though! 2734 if (!rect.IsValid()) 2735 return; 2736 2737 _CheckLockAndSwitchCurrent(); 2738 _UpdatePattern(pattern); 2739 2740 fOwner->fLink->StartMessage(AS_FILL_RECT); 2741 fOwner->fLink->Attach<BRect>(rect); 2742 2743 _FlushIfNotInTransaction(); 2744 } 2745 2746 2747 void 2748 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius, 2749 ::pattern pattern) 2750 { 2751 if (fOwner == NULL) 2752 return; 2753 2754 _CheckLockAndSwitchCurrent(); 2755 _UpdatePattern(pattern); 2756 2757 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT); 2758 fOwner->fLink->Attach<BRect>(rect); 2759 fOwner->fLink->Attach<float>(xRadius); 2760 fOwner->fLink->Attach<float>(yRadius); 2761 2762 _FlushIfNotInTransaction(); 2763 } 2764 2765 2766 void 2767 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 2768 ::pattern pattern) 2769 { 2770 if (fOwner == NULL) 2771 return; 2772 2773 _CheckLockAndSwitchCurrent(); 2774 2775 _UpdatePattern(pattern); 2776 2777 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT); 2778 fOwner->fLink->Attach<BRect>(rect); 2779 fOwner->fLink->Attach<float>(xRadius); 2780 fOwner->fLink->Attach<float>(yRadius); 2781 2782 _FlushIfNotInTransaction(); 2783 } 2784 2785 2786 void 2787 BView::FillRegion(BRegion *region, ::pattern pattern) 2788 { 2789 if (region == NULL || fOwner == NULL) 2790 return; 2791 2792 _CheckLockAndSwitchCurrent(); 2793 2794 _UpdatePattern(pattern); 2795 2796 fOwner->fLink->StartMessage(AS_FILL_REGION); 2797 fOwner->fLink->AttachRegion(*region); 2798 // TODO: make this automatically chose 2799 // to send over area or handle failure here? 2800 2801 _FlushIfNotInTransaction(); 2802 } 2803 2804 2805 void 2806 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 2807 BRect bounds, ::pattern pattern) 2808 { 2809 if (fOwner == NULL) 2810 return; 2811 2812 _CheckLockAndSwitchCurrent(); 2813 2814 _UpdatePattern(pattern); 2815 2816 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE); 2817 fOwner->fLink->Attach<BPoint>(pt1); 2818 fOwner->fLink->Attach<BPoint>(pt2); 2819 fOwner->fLink->Attach<BPoint>(pt3); 2820 fOwner->fLink->Attach<BRect>(bounds); 2821 2822 _FlushIfNotInTransaction(); 2823 } 2824 2825 2826 void 2827 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 2828 { 2829 if (fOwner) { 2830 // we construct the smallest rectangle that contains the 3 points 2831 // for the 1st point 2832 BRect bounds(pt1, pt1); 2833 2834 // for the 2nd point 2835 if (pt2.x < bounds.left) 2836 bounds.left = pt2.x; 2837 2838 if (pt2.y < bounds.top) 2839 bounds.top = pt2.y; 2840 2841 if (pt2.x > bounds.right) 2842 bounds.right = pt2.x; 2843 2844 if (pt2.y > bounds.bottom) 2845 bounds.bottom = pt2.y; 2846 2847 // for the 3rd point 2848 if (pt3.x < bounds.left) 2849 bounds.left = pt3.x; 2850 2851 if (pt3.y < bounds.top) 2852 bounds.top = pt3.y; 2853 2854 if (pt3.x > bounds.right) 2855 bounds.right = pt3.x; 2856 2857 if (pt3.y > bounds.bottom) 2858 bounds.bottom = pt3.y; 2859 2860 StrokeTriangle(pt1, pt2, pt3, bounds, p); 2861 } 2862 } 2863 2864 2865 void 2866 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 2867 { 2868 if (fOwner) { 2869 // we construct the smallest rectangle that contains the 3 points 2870 // for the 1st point 2871 BRect bounds(pt1, pt1); 2872 2873 // for the 2nd point 2874 if (pt2.x < bounds.left) 2875 bounds.left = pt2.x; 2876 2877 if (pt2.y < bounds.top) 2878 bounds.top = pt2.y; 2879 2880 if (pt2.x > bounds.right) 2881 bounds.right = pt2.x; 2882 2883 if (pt2.y > bounds.bottom) 2884 bounds.bottom = pt2.y; 2885 2886 // for the 3rd point 2887 if (pt3.x < bounds.left) 2888 bounds.left = pt3.x; 2889 2890 if (pt3.y < bounds.top) 2891 bounds.top = pt3.y; 2892 2893 if (pt3.x > bounds.right) 2894 bounds.right = pt3.x; 2895 2896 if (pt3.y > bounds.bottom) 2897 bounds.bottom = pt3.y; 2898 2899 FillTriangle(pt1, pt2, pt3, bounds, p); 2900 } 2901 } 2902 2903 2904 void 2905 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 2906 BRect bounds, ::pattern pattern) 2907 { 2908 if (fOwner == NULL) 2909 return; 2910 2911 _CheckLockAndSwitchCurrent(); 2912 _UpdatePattern(pattern); 2913 2914 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 2915 fOwner->fLink->Attach<BPoint>(pt1); 2916 fOwner->fLink->Attach<BPoint>(pt2); 2917 fOwner->fLink->Attach<BPoint>(pt3); 2918 fOwner->fLink->Attach<BRect>(bounds); 2919 2920 _FlushIfNotInTransaction(); 2921 } 2922 2923 2924 void 2925 BView::StrokeLine(BPoint toPt, pattern p) 2926 { 2927 StrokeLine(PenLocation(), toPt, p); 2928 } 2929 2930 2931 void 2932 BView::StrokeLine(BPoint pt0, BPoint pt1, ::pattern pattern) 2933 { 2934 if (fOwner == NULL) 2935 return; 2936 2937 _CheckLockAndSwitchCurrent(); 2938 _UpdatePattern(pattern); 2939 2940 fOwner->fLink->StartMessage(AS_STROKE_LINE); 2941 fOwner->fLink->Attach<BPoint>(pt0); 2942 fOwner->fLink->Attach<BPoint>(pt1); 2943 2944 _FlushIfNotInTransaction(); 2945 2946 // this modifies our pen location, so we invalidate the flag. 2947 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 2948 } 2949 2950 2951 void 2952 BView::StrokeShape(BShape *shape, ::pattern pattern) 2953 { 2954 if (shape == NULL || fOwner == NULL) 2955 return; 2956 2957 shape_data *sd = (shape_data *)shape->fPrivateData; 2958 if (sd->opCount == 0 || sd->ptCount == 0) 2959 return; 2960 2961 _CheckLockAndSwitchCurrent(); 2962 _UpdatePattern(pattern); 2963 2964 if ((sd->opCount * sizeof(uint32)) + (sd->ptCount * sizeof(BPoint)) < MAX_ATTACHMENT_SIZE) { 2965 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 2966 fOwner->fLink->Attach<BRect>(shape->Bounds()); 2967 fOwner->fLink->Attach<int32>(sd->opCount); 2968 fOwner->fLink->Attach<int32>(sd->ptCount); 2969 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 2970 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 2971 2972 _FlushIfNotInTransaction(); 2973 } else { 2974 // TODO: send via an area 2975 } 2976 } 2977 2978 2979 void 2980 BView::FillShape(BShape *shape, ::pattern pattern) 2981 { 2982 if (shape == NULL || fOwner == NULL) 2983 return; 2984 2985 shape_data *sd = (shape_data *)(shape->fPrivateData); 2986 if (sd->opCount == 0 || sd->ptCount == 0) 2987 return; 2988 2989 _CheckLockAndSwitchCurrent(); 2990 _UpdatePattern(pattern); 2991 2992 if ((sd->opCount * sizeof(uint32)) + (sd->ptCount * sizeof(BPoint)) < MAX_ATTACHMENT_SIZE) { 2993 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 2994 fOwner->fLink->Attach<BRect>(shape->Bounds()); 2995 fOwner->fLink->Attach<int32>(sd->opCount); 2996 fOwner->fLink->Attach<int32>(sd->ptCount); 2997 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 2998 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 2999 3000 _FlushIfNotInTransaction(); 3001 } else { 3002 // TODO: send via an area 3003 // BTW, in a perfect world, the fLink API would take care of that -- axeld. 3004 } 3005 } 3006 3007 3008 void 3009 BView::BeginLineArray(int32 count) 3010 { 3011 if (fOwner == NULL) 3012 return; 3013 3014 if (count <= 0) 3015 debugger("Calling BeginLineArray with a count <= 0"); 3016 3017 _CheckLock(); 3018 3019 if (comm) { 3020 debugger("Can't nest BeginLineArray calls"); 3021 // not fatal, but it helps during 3022 // development of your app and is in 3023 // line with R5... 3024 delete [] comm->array; 3025 delete comm; 3026 } 3027 3028 comm = new _array_data_; 3029 3030 comm->maxCount = count; 3031 comm->count = 0; 3032 comm->array = new _array_hdr_[count]; 3033 } 3034 3035 3036 void 3037 BView::AddLine(BPoint pt0, BPoint pt1, rgb_color col) 3038 { 3039 if (fOwner == NULL) 3040 return; 3041 3042 if (!comm) 3043 debugger("BeginLineArray must be called before using AddLine"); 3044 3045 _CheckLock(); 3046 3047 if (comm->count < comm->maxCount) { 3048 comm->array[comm->count].startX = pt0.x; 3049 comm->array[comm->count].startY = pt0.y; 3050 comm->array[comm->count].endX = pt1.x; 3051 comm->array[comm->count].endY = pt1.y; 3052 comm->array[comm->count].color = col; 3053 3054 comm->count++; 3055 } 3056 } 3057 3058 3059 void 3060 BView::EndLineArray() 3061 { 3062 if (fOwner == NULL) 3063 return; 3064 3065 if (!comm) 3066 debugger("Can't call EndLineArray before BeginLineArray"); 3067 3068 _CheckLockAndSwitchCurrent(); 3069 3070 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 3071 fOwner->fLink->Attach<int32>(comm->count); 3072 fOwner->fLink->Attach(comm->array, comm->count * sizeof(_array_hdr_)); 3073 3074 _FlushIfNotInTransaction(); 3075 3076 _RemoveCommArray(); 3077 } 3078 3079 3080 void 3081 BView::SetDiskMode(char* filename, long offset) 3082 { 3083 // TODO: implement 3084 // One BeBook version has this to say about SetDiskMode(): 3085 // 3086 // "Begins recording a picture to the file with the given filename 3087 // at the given offset. Subsequent drawing commands sent to the view 3088 // will be written to the file until EndPicture() is called. The 3089 // stored commands may be played from the file with DrawPicture()." 3090 } 3091 3092 3093 void 3094 BView::BeginPicture(BPicture *picture) 3095 { 3096 if (_CheckOwnerLockAndSwitchCurrent() && picture && picture->fUsurped == NULL) { 3097 picture->Usurp(cpicture); 3098 cpicture = picture; 3099 3100 fOwner->fLink->StartMessage(AS_LAYER_BEGIN_PICTURE); 3101 } 3102 } 3103 3104 3105 void 3106 BView::AppendToPicture(BPicture *picture) 3107 { 3108 _CheckLockAndSwitchCurrent(); 3109 3110 if (picture && picture->fUsurped == NULL) { 3111 int32 token = picture->Token(); 3112 3113 if (token == -1) { 3114 BeginPicture(picture); 3115 } else { 3116 picture->SetToken(-1); 3117 picture->Usurp(cpicture); 3118 cpicture = picture; 3119 fOwner->fLink->StartMessage(AS_LAYER_APPEND_TO_PICTURE); 3120 fOwner->fLink->Attach<int32>(token); 3121 } 3122 } 3123 } 3124 3125 3126 BPicture * 3127 BView::EndPicture() 3128 { 3129 if (_CheckOwnerLockAndSwitchCurrent() && cpicture) { 3130 int32 token; 3131 3132 fOwner->fLink->StartMessage(AS_LAYER_END_PICTURE); 3133 3134 int32 code; 3135 if (fOwner->fLink->FlushWithReply(code) == B_OK 3136 && code == B_OK 3137 && fOwner->fLink->Read<int32>(&token) == B_OK) { 3138 BPicture *picture = cpicture; 3139 cpicture = picture->StepDown(); 3140 picture->SetToken(token); 3141 3142 return picture; 3143 } 3144 } 3145 3146 return NULL; 3147 } 3148 3149 3150 void 3151 BView::SetViewBitmap(const BBitmap *bitmap, BRect srcRect, BRect dstRect, 3152 uint32 followFlags, uint32 options) 3153 { 3154 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 3155 } 3156 3157 3158 void 3159 BView::SetViewBitmap(const BBitmap *bitmap, uint32 followFlags, uint32 options) 3160 { 3161 BRect rect; 3162 if (bitmap) 3163 rect = bitmap->Bounds(); 3164 3165 rect.OffsetTo(B_ORIGIN); 3166 3167 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 3168 } 3169 3170 3171 void 3172 BView::ClearViewBitmap() 3173 { 3174 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3175 } 3176 3177 3178 status_t 3179 BView::SetViewOverlay(const BBitmap *overlay, BRect srcRect, BRect dstRect, 3180 rgb_color *colorKey, uint32 followFlags, uint32 options) 3181 { 3182 if ((overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 3183 return B_BAD_VALUE; 3184 3185 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 3186 options | AS_REQUEST_COLOR_KEY); 3187 if (status == B_OK) { 3188 // read the color that will be treated as transparent 3189 fOwner->fLink->Read<rgb_color>(colorKey); 3190 } 3191 3192 return status; 3193 } 3194 3195 3196 status_t 3197 BView::SetViewOverlay(const BBitmap *overlay, rgb_color *colorKey, 3198 uint32 followFlags, uint32 options) 3199 { 3200 BRect rect; 3201 if (overlay != NULL) { 3202 rect = overlay->Bounds(); 3203 rect.OffsetTo(B_ORIGIN); 3204 } 3205 3206 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 3207 } 3208 3209 3210 void 3211 BView::ClearViewOverlay() 3212 { 3213 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3214 } 3215 3216 3217 void 3218 BView::CopyBits(BRect src, BRect dst) 3219 { 3220 if (fOwner == NULL) 3221 return; 3222 3223 if (!src.IsValid() || !dst.IsValid()) 3224 return; 3225 3226 _CheckLockAndSwitchCurrent(); 3227 3228 fOwner->fLink->StartMessage(AS_LAYER_COPY_BITS); 3229 fOwner->fLink->Attach<BRect>(src); 3230 fOwner->fLink->Attach<BRect>(dst); 3231 3232 _FlushIfNotInTransaction(); 3233 } 3234 3235 3236 void 3237 BView::DrawPicture(const BPicture *picture) 3238 { 3239 if (picture == NULL) 3240 return; 3241 3242 DrawPictureAsync(picture, PenLocation()); 3243 Sync(); 3244 } 3245 3246 3247 void 3248 BView::DrawPicture(const BPicture *picture, BPoint where) 3249 { 3250 if (picture == NULL) 3251 return; 3252 3253 DrawPictureAsync(picture, where); 3254 Sync(); 3255 } 3256 3257 3258 void 3259 BView::DrawPicture(const char *filename, long offset, BPoint where) 3260 { 3261 if (!filename) 3262 return; 3263 3264 DrawPictureAsync(filename, offset, where); 3265 Sync(); 3266 } 3267 3268 3269 void 3270 BView::DrawPictureAsync(const BPicture *picture) 3271 { 3272 if (picture == NULL) 3273 return; 3274 3275 DrawPictureAsync(picture, PenLocation()); 3276 } 3277 3278 3279 void 3280 BView::DrawPictureAsync(const BPicture *picture, BPoint where) 3281 { 3282 if (picture == NULL) 3283 return; 3284 3285 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 3286 fOwner->fLink->StartMessage(AS_LAYER_DRAW_PICTURE); 3287 fOwner->fLink->Attach<int32>(picture->Token()); 3288 fOwner->fLink->Attach<BPoint>(where); 3289 3290 _FlushIfNotInTransaction(); 3291 } 3292 } 3293 3294 3295 void 3296 BView::DrawPictureAsync(const char *filename, long offset, BPoint where) 3297 { 3298 if (!filename) 3299 return; 3300 3301 // TODO: Test 3302 BFile file(filename, B_READ_ONLY); 3303 if (file.InitCheck() < B_OK) 3304 return; 3305 3306 file.Seek(offset, SEEK_SET); 3307 3308 BPicture picture; 3309 if (picture.Unflatten(&file) < B_OK) 3310 return; 3311 3312 DrawPictureAsync(&picture, where); 3313 } 3314 3315 3316 void 3317 BView::Invalidate(BRect invalRect) 3318 { 3319 if (fOwner == NULL) 3320 return; 3321 3322 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 3323 // On the server side, the invalid rect will be converted to a BRegion, 3324 // which rounds in a different manner, so that it really includes the 3325 // fractional coordinates of a BRect (ie ceilf(rect.right) & 3326 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 3327 // different rounding here to stay compatible in both ways. 3328 invalRect.left = (int)invalRect.left; 3329 invalRect.top = (int)invalRect.top; 3330 invalRect.right = (int)invalRect.right; 3331 invalRect.bottom = (int)invalRect.bottom; 3332 if (!invalRect.IsValid()) 3333 return; 3334 3335 _CheckLockAndSwitchCurrent(); 3336 3337 fOwner->fLink->StartMessage(AS_LAYER_INVALIDATE_RECT); 3338 fOwner->fLink->Attach<BRect>(invalRect); 3339 fOwner->fLink->Flush(); 3340 } 3341 3342 3343 void 3344 BView::Invalidate(const BRegion* region) 3345 { 3346 if (region == NULL || fOwner == NULL) 3347 return; 3348 3349 _CheckLockAndSwitchCurrent(); 3350 3351 fOwner->fLink->StartMessage(AS_LAYER_INVALIDATE_REGION); 3352 fOwner->fLink->AttachRegion(*region); 3353 3354 fOwner->fLink->Flush(); 3355 } 3356 3357 3358 void 3359 BView::Invalidate() 3360 { 3361 Invalidate(Bounds()); 3362 } 3363 3364 3365 void 3366 BView::InvertRect(BRect rect) 3367 { 3368 if (fOwner) { 3369 _CheckLockAndSwitchCurrent(); 3370 3371 fOwner->fLink->StartMessage(AS_LAYER_INVERT_RECT); 3372 fOwner->fLink->Attach<BRect>(rect); 3373 3374 _FlushIfNotInTransaction(); 3375 } 3376 } 3377 3378 3379 // #pragma mark - View Hierarchy Functions 3380 3381 3382 void 3383 BView::AddChild(BView *child, BView *before) 3384 { 3385 STRACE(("BView(%s)::AddChild(child='%s' before='%s')\n", 3386 this->Name() ? this->Name(): "NULL", 3387 child && child->Name() ? child->Name(): "NULL", 3388 before && before->Name() ? before->Name(): "NULL")); 3389 3390 if (!_AddChild(child, before)) 3391 return; 3392 3393 if (fLayoutData->fLayout) 3394 fLayoutData->fLayout->AddView(child); 3395 } 3396 3397 3398 bool 3399 BView::AddChild(BLayoutItem* child) 3400 { 3401 if (!fLayoutData->fLayout) 3402 return false; 3403 return fLayoutData->fLayout->AddItem(child); 3404 } 3405 3406 3407 bool 3408 BView::_AddChild(BView *child, BView *before) 3409 { 3410 if (!child) 3411 return false; 3412 3413 if (child->fParent != NULL) { 3414 printf("BView::_AddChild(): child %p already has parent %p\n", child , child->fParent); 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_LAYER_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_LAYER_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_LAYER_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 fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4198 4199 // handle rounding 4200 frame.left = roundf(frame.left); 4201 frame.top = roundf(frame.top); 4202 frame.right = roundf(frame.right); 4203 frame.bottom = roundf(frame.bottom); 4204 4205 fParentOffset.Set(frame.left, frame.top); 4206 4207 fOwner = NULL; 4208 fParent = NULL; 4209 fNextSibling = NULL; 4210 fPreviousSibling = NULL; 4211 fFirstChild = NULL; 4212 4213 fShowLevel = 0; 4214 fTopLevelView = false; 4215 4216 cpicture = NULL; 4217 comm = NULL; 4218 4219 fVerScroller = NULL; 4220 fHorScroller = NULL; 4221 4222 f_is_printing = false; 4223 fAttached = false; 4224 4225 fState = new BPrivate::ViewState; 4226 4227 fBounds = frame.OffsetToCopy(B_ORIGIN); 4228 fShelf = NULL; 4229 4230 fEventMask = 0; 4231 fEventOptions = 0; 4232 fMouseEventOptions = 0; 4233 4234 fLayoutData = new LayoutData; 4235 } 4236 4237 4238 void 4239 BView::_RemoveCommArray() 4240 { 4241 if (comm) { 4242 delete [] comm->array; 4243 delete comm; 4244 comm = NULL; 4245 } 4246 } 4247 4248 4249 void 4250 BView::_SetOwner(BWindow *newOwner) 4251 { 4252 if (!newOwner) 4253 _RemoveCommArray(); 4254 4255 if (fOwner != newOwner && fOwner) { 4256 if (fOwner->fFocus == this) 4257 MakeFocus(false); 4258 4259 if (fOwner->fLastMouseMovedView == this) 4260 fOwner->fLastMouseMovedView = NULL; 4261 4262 fOwner->RemoveHandler(this); 4263 if (fShelf) 4264 fOwner->RemoveHandler(fShelf); 4265 } 4266 4267 if (newOwner && newOwner != fOwner) { 4268 newOwner->AddHandler(this); 4269 if (fShelf) 4270 newOwner->AddHandler(fShelf); 4271 4272 if (fTopLevelView) 4273 SetNextHandler(newOwner); 4274 else 4275 SetNextHandler(fParent); 4276 } 4277 4278 fOwner = newOwner; 4279 4280 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) 4281 child->_SetOwner(newOwner); 4282 } 4283 4284 4285 void 4286 BView::_ClipToPicture(BPicture *picture, BPoint where, 4287 bool invert, bool sync) 4288 { 4289 if (!picture) 4290 return; 4291 4292 if (_CheckOwnerLockAndSwitchCurrent()) { 4293 fOwner->fLink->StartMessage(AS_LAYER_CLIP_TO_PICTURE); 4294 fOwner->fLink->Attach<int32>(picture->Token()); 4295 fOwner->fLink->Attach<BPoint>(where); 4296 fOwner->fLink->Attach<bool>(invert); 4297 4298 // TODO: I think that "sync" means another thing here: 4299 // the bebook, at least, says so. 4300 if (sync) 4301 fOwner->fLink->Flush(); 4302 4303 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 4304 } 4305 4306 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 4307 } 4308 4309 4310 bool 4311 BView::_RemoveChildFromList(BView* child) 4312 { 4313 if (child->fParent != this) 4314 return false; 4315 4316 if (fFirstChild == child) { 4317 // it's the first view in the list 4318 fFirstChild = child->fNextSibling; 4319 } else { 4320 // there must be a previous sibling 4321 child->fPreviousSibling->fNextSibling = child->fNextSibling; 4322 } 4323 4324 if (child->fNextSibling) 4325 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 4326 4327 child->fParent = NULL; 4328 child->fNextSibling = NULL; 4329 child->fPreviousSibling = NULL; 4330 4331 return true; 4332 } 4333 4334 4335 bool 4336 BView::_AddChildToList(BView* child, BView* before) 4337 { 4338 if (!child) 4339 return false; 4340 if (child->fParent != NULL) { 4341 debugger("View already belongs to someone else"); 4342 return false; 4343 } 4344 if (before != NULL && before->fParent != this) { 4345 debugger("Invalid before view"); 4346 return false; 4347 } 4348 4349 if (before != NULL) { 4350 // add view before this one 4351 child->fNextSibling = before; 4352 child->fPreviousSibling = before->fPreviousSibling; 4353 if (child->fPreviousSibling != NULL) 4354 child->fPreviousSibling->fNextSibling = child; 4355 4356 before->fPreviousSibling = child; 4357 if (fFirstChild == before) 4358 fFirstChild = child; 4359 } else { 4360 // add view to the end of the list 4361 BView *last = fFirstChild; 4362 while (last != NULL && last->fNextSibling != NULL) { 4363 last = last->fNextSibling; 4364 } 4365 4366 if (last != NULL) { 4367 last->fNextSibling = child; 4368 child->fPreviousSibling = last; 4369 } else { 4370 fFirstChild = child; 4371 child->fPreviousSibling = NULL; 4372 } 4373 4374 child->fNextSibling = NULL; 4375 } 4376 4377 child->fParent = this; 4378 return true; 4379 } 4380 4381 4382 /*! \brief Creates the server counterpart of this view. 4383 This is only done for views that are part of the view hierarchy, ie. when 4384 they are attached to a window. 4385 RemoveSelf() deletes the server object again. 4386 */ 4387 bool 4388 BView::_CreateSelf() 4389 { 4390 // AS_LAYER_CREATE & AS_LAYER_CREATE_ROOT do not use the 4391 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 4392 // of the view and its parent are both send to the server. 4393 4394 if (fTopLevelView) 4395 fOwner->fLink->StartMessage(AS_LAYER_CREATE_ROOT); 4396 else 4397 fOwner->fLink->StartMessage(AS_LAYER_CREATE); 4398 4399 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 4400 fOwner->fLink->AttachString(Name()); 4401 fOwner->fLink->Attach<BRect>(Frame()); 4402 fOwner->fLink->Attach<BPoint>(LeftTop()); 4403 fOwner->fLink->Attach<uint32>(ResizingMode()); 4404 fOwner->fLink->Attach<uint32>(fEventMask); 4405 fOwner->fLink->Attach<uint32>(fEventOptions); 4406 fOwner->fLink->Attach<uint32>(Flags()); 4407 fOwner->fLink->Attach<bool>(IsHidden(this)); 4408 fOwner->fLink->Attach<rgb_color>(fState->view_color); 4409 if (fTopLevelView) 4410 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 4411 else 4412 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 4413 fOwner->fLink->Flush(); 4414 4415 _CheckOwnerLockAndSwitchCurrent(); 4416 fState->UpdateServerState(*fOwner->fLink); 4417 4418 // we create all its children, too 4419 4420 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 4421 child->_CreateSelf(); 4422 } 4423 4424 fOwner->fLink->Flush(); 4425 return true; 4426 } 4427 4428 4429 /*! 4430 Sets the new view position. 4431 It doesn't contact the server, though - the only case where this 4432 is called outside of MoveTo() is as reaction of moving a view 4433 in the server (a.k.a. B_WINDOW_RESIZED). 4434 It also calls the BView's FrameMoved() hook. 4435 */ 4436 void 4437 BView::_MoveTo(int32 x, int32 y) 4438 { 4439 fParentOffset.Set(x, y); 4440 4441 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 4442 BMessage moved(B_VIEW_MOVED); 4443 moved.AddInt64("when", system_time()); 4444 moved.AddPoint("where", BPoint(x, y)); 4445 4446 BMessenger target(this); 4447 target.SendMessage(&moved); 4448 } 4449 } 4450 4451 4452 /*! 4453 Computes the actual new frame size and recalculates the size of 4454 the children as well. 4455 It doesn't contact the server, though - the only case where this 4456 is called outside of ResizeBy() is as reaction of resizing a view 4457 in the server (a.k.a. B_WINDOW_RESIZED). 4458 It also calls the BView's FrameResized() hook. 4459 */ 4460 void 4461 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 4462 { 4463 fBounds.right += deltaWidth; 4464 fBounds.bottom += deltaHeight; 4465 4466 if (Window() == NULL) { 4467 // we're not supposed to exercise the resizing code in case 4468 // we haven't been attached to a window yet 4469 return; 4470 } 4471 4472 // layout the children 4473 if (fFlags & B_SUPPORTS_LAYOUT) { 4474 Relayout(); 4475 } else { 4476 for (BView* child = fFirstChild; child; child = child->fNextSibling) 4477 child->_ParentResizedBy(deltaWidth, deltaHeight); 4478 } 4479 4480 if (fFlags & B_FRAME_EVENTS) { 4481 BMessage resized(B_VIEW_RESIZED); 4482 resized.AddInt64("when", system_time()); 4483 resized.AddFloat("width", fBounds.Width()); 4484 resized.AddFloat("height", fBounds.Height()); 4485 4486 BMessenger target(this); 4487 target.SendMessage(&resized); 4488 } 4489 } 4490 4491 4492 /*! 4493 Relayouts the view according to its resizing mode. 4494 */ 4495 void 4496 BView::_ParentResizedBy(int32 x, int32 y) 4497 { 4498 uint32 resizingMode = fFlags & _RESIZE_MASK_; 4499 BRect newFrame = Frame(); 4500 4501 // follow with left side 4502 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 4503 newFrame.left += x; 4504 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 4505 newFrame.left += x / 2; 4506 4507 // follow with right side 4508 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 4509 newFrame.right += x; 4510 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 4511 newFrame.right += x / 2; 4512 4513 // follow with top side 4514 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 4515 newFrame.top += y; 4516 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 4517 newFrame.top += y / 2; 4518 4519 // follow with bottom side 4520 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 4521 newFrame.bottom += y; 4522 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 4523 newFrame.bottom += y / 2; 4524 4525 if (newFrame.LeftTop() != fParentOffset) { 4526 // move view 4527 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 4528 } 4529 4530 if (newFrame != Frame()) { 4531 // resize view 4532 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 4533 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 4534 _ResizeBy(widthDiff, heightDiff); 4535 } 4536 } 4537 4538 4539 void 4540 BView::_Activate(bool active) 4541 { 4542 WindowActivated(active); 4543 4544 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 4545 child->_Activate(active); 4546 } 4547 } 4548 4549 4550 void 4551 BView::_Attach() 4552 { 4553 AttachedToWindow(); 4554 fAttached = true; 4555 4556 // after giving the view a chance to do this itself, 4557 // check for the B_PULSE_NEEDED flag and make sure the 4558 // window set's up the pulse messaging 4559 if (fOwner) { 4560 if (fFlags & B_PULSE_NEEDED) { 4561 _CheckLock(); 4562 if (fOwner->fPulseRunner == NULL) 4563 fOwner->SetPulseRate(fOwner->PulseRate()); 4564 } 4565 4566 if (!fOwner->IsHidden()) 4567 Invalidate(); 4568 } 4569 4570 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) { 4571 // we need to check for fAttached as new views could have been 4572 // added in AttachedToWindow() - and those are already attached 4573 if (!child->fAttached) 4574 child->_Attach(); 4575 } 4576 4577 AllAttached(); 4578 } 4579 4580 4581 void 4582 BView::_Detach() 4583 { 4584 DetachedFromWindow(); 4585 fAttached = false; 4586 4587 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) { 4588 child->_Detach(); 4589 } 4590 4591 AllDetached(); 4592 4593 if (fOwner) { 4594 _CheckLock(); 4595 4596 if (!fOwner->IsHidden()) 4597 Invalidate(); 4598 4599 // make sure our owner doesn't need us anymore 4600 4601 if (fOwner->CurrentFocus() == this) 4602 MakeFocus(false); 4603 4604 if (fOwner->fDefaultButton == this) 4605 fOwner->SetDefaultButton(NULL); 4606 4607 if (fOwner->fKeyMenuBar == this) 4608 fOwner->fKeyMenuBar = NULL; 4609 4610 if (fOwner->fLastMouseMovedView == this) 4611 fOwner->fLastMouseMovedView = NULL; 4612 4613 if (fOwner->fLastViewToken == _get_object_token_(this)) 4614 fOwner->fLastViewToken = B_NULL_TOKEN; 4615 4616 _SetOwner(NULL); 4617 } 4618 } 4619 4620 4621 void 4622 BView::_Draw(BRect updateRect) 4623 { 4624 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 4625 return; 4626 4627 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 4628 // -> View is simply not drawn at all 4629 4630 _SwitchServerCurrentView(); 4631 4632 ConvertFromScreen(&updateRect); 4633 updateRect = Bounds() & updateRect; 4634 4635 // TODO: make states robust (the hook implementation could 4636 // mess things up if it uses non-matching Push- and PopState(), 4637 // we would not be guaranteed to still have the same state on 4638 // the stack after having called Draw()) 4639 PushState(); 4640 Draw(updateRect); 4641 PopState(); 4642 Flush(); 4643 } 4644 4645 void 4646 BView::_DrawAfterChildren(BRect updateRect) 4647 { 4648 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 4649 || !(Flags() & B_DRAW_ON_CHILDREN)) 4650 return; 4651 4652 _SwitchServerCurrentView(); 4653 4654 ConvertFromScreen(&updateRect); 4655 updateRect = Bounds() & updateRect; 4656 4657 // TODO: make states robust (see above) 4658 PushState(); 4659 DrawAfterChildren(updateRect); 4660 PopState(); 4661 Flush(); 4662 } 4663 4664 4665 void 4666 BView::_Pulse() 4667 { 4668 if (Flags() & B_PULSE_NEEDED) 4669 Pulse(); 4670 4671 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 4672 child->_Pulse(); 4673 } 4674 } 4675 4676 4677 void 4678 BView::_UpdateStateForRemove() 4679 { 4680 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 4681 if (!_CheckOwnerLockAndSwitchCurrent()) 4682 return; 4683 4684 fState->UpdateFrom(*fOwner->fLink); 4685 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 4686 // fOwner->fLink->StartMessage(AS_LAYER_GET_COORD); 4687 // 4688 // status_t code; 4689 // if (fOwner->fLink->FlushWithReply(code) == B_OK 4690 // && code == B_OK) { 4691 // fOwner->fLink->Read<BPoint>(&fParentOffset); 4692 // fOwner->fLink->Read<BRect>(&fBounds); 4693 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4694 // } 4695 // } 4696 4697 // update children as well 4698 4699 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 4700 if (child->fOwner) 4701 child->_UpdateStateForRemove(); 4702 } 4703 } 4704 4705 4706 inline void 4707 BView::_UpdatePattern(::pattern pattern) 4708 { 4709 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 4710 return; 4711 4712 if (fOwner) { 4713 _CheckLockAndSwitchCurrent(); 4714 4715 fOwner->fLink->StartMessage(AS_LAYER_SET_PATTERN); 4716 fOwner->fLink->Attach< ::pattern>(pattern); 4717 4718 fState->valid_flags |= B_VIEW_PATTERN_BIT; 4719 } 4720 4721 fState->pattern = pattern; 4722 } 4723 4724 4725 void 4726 BView::_FlushIfNotInTransaction() 4727 { 4728 if (!fOwner->fInTransaction) { 4729 fOwner->Flush(); 4730 } 4731 } 4732 4733 4734 BShelf * 4735 BView::_Shelf() const 4736 { 4737 return fShelf; 4738 } 4739 4740 4741 void 4742 BView::_SetShelf(BShelf *shelf) 4743 { 4744 if (fShelf != NULL && fOwner != NULL) 4745 fOwner->RemoveHandler(fShelf); 4746 4747 fShelf = shelf; 4748 4749 if (fShelf != NULL && fOwner != NULL) 4750 fOwner->AddHandler(fShelf); 4751 } 4752 4753 4754 status_t 4755 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, 4756 BRect dstRect, uint32 followFlags, uint32 options) 4757 { 4758 if (!_CheckOwnerLockAndSwitchCurrent()) 4759 return B_ERROR; 4760 4761 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 4762 4763 fOwner->fLink->StartMessage(AS_LAYER_SET_VIEW_BITMAP); 4764 fOwner->fLink->Attach<int32>(serverToken); 4765 fOwner->fLink->Attach<BRect>(srcRect); 4766 fOwner->fLink->Attach<BRect>(dstRect); 4767 fOwner->fLink->Attach<int32>(followFlags); 4768 fOwner->fLink->Attach<int32>(options); 4769 4770 status_t status = B_ERROR; 4771 fOwner->fLink->FlushWithReply(status); 4772 4773 return status; 4774 } 4775 4776 4777 bool 4778 BView::_CheckOwnerLockAndSwitchCurrent() const 4779 { 4780 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()...", Name())); 4781 4782 if (fOwner == NULL) { 4783 debugger("View method requires owner and doesn't have one."); 4784 return false; 4785 } 4786 4787 _CheckLockAndSwitchCurrent(); 4788 4789 return true; 4790 } 4791 4792 4793 bool 4794 BView::_CheckOwnerLock() const 4795 { 4796 if (fOwner) { 4797 fOwner->check_lock(); 4798 return true; 4799 } else { 4800 debugger("View method requires owner and doesn't have one."); 4801 return false; 4802 } 4803 } 4804 4805 4806 void 4807 BView::_CheckLockAndSwitchCurrent() const 4808 { 4809 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()...", Name() ? Name(): "NULL")); 4810 4811 if (!fOwner) 4812 return; 4813 4814 fOwner->check_lock(); 4815 4816 _SwitchServerCurrentView(); 4817 } 4818 4819 4820 void 4821 BView::_CheckLock() const 4822 { 4823 if (fOwner) 4824 fOwner->check_lock(); 4825 } 4826 4827 4828 void 4829 BView::_SwitchServerCurrentView() const 4830 { 4831 int32 serverToken = _get_object_token_(this); 4832 4833 if (fOwner->fLastViewToken != serverToken) { 4834 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 4835 fOwner->fLink->StartMessage(AS_SET_CURRENT_LAYER); 4836 fOwner->fLink->Attach<int32>(serverToken); 4837 4838 fOwner->fLastViewToken = serverToken; 4839 } else { 4840 STRACE(("quiet2\n")); 4841 } 4842 } 4843 4844 4845 extern "C" void _ReservedView1__5BView() {} 4846 extern "C" void _ReservedView2__5BView() {} 4847 extern "C" void _ReservedView3__5BView() {} 4848 extern "C" void _ReservedView4__5BView() {} 4849 extern "C" void _ReservedView5__5BView() {} 4850 extern "C" void _ReservedView6__5BView() {} 4851 extern "C" void _ReservedView7__5BView() {} 4852 extern "C" void _ReservedView8__5BView() {} 4853 extern "C" void _ReservedView9__5BView() {} 4854 extern "C" void _ReservedView10__5BView() {} 4855 void BView::_ReservedView11(){} 4856 void BView::_ReservedView12(){} 4857 void BView::_ReservedView13(){} 4858 void BView::_ReservedView14(){} 4859 void BView::_ReservedView15(){} 4860 void BView::_ReservedView16(){} 4861 4862 4863 BView::BView(const BView &other) 4864 : BHandler() 4865 { 4866 // this is private and not functional, but exported 4867 } 4868 4869 4870 BView & 4871 BView::operator=(const BView &other) 4872 { 4873 // this is private and not functional, but exported 4874 return *this; 4875 } 4876 4877 4878 void 4879 BView::_PrintToStream() 4880 { 4881 printf("BView::_PrintToStream()\n"); 4882 printf("\tName: %s\n" 4883 "\tParent: %s\n" 4884 "\tFirstChild: %s\n" 4885 "\tNextSibling: %s\n" 4886 "\tPrevSibling: %s\n" 4887 "\tOwner(Window): %s\n" 4888 "\tToken: %ld\n" 4889 "\tFlags: %ld\n" 4890 "\tView origin: (%f,%f)\n" 4891 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 4892 "\tShow level: %d\n" 4893 "\tTopView?: %s\n" 4894 "\tBPicture: %s\n" 4895 "\tVertical Scrollbar %s\n" 4896 "\tHorizontal Scrollbar %s\n" 4897 "\tIs Printing?: %s\n" 4898 "\tShelf?: %s\n" 4899 "\tEventMask: %ld\n" 4900 "\tEventOptions: %ld\n", 4901 Name(), 4902 fParent ? fParent->Name() : "NULL", 4903 fFirstChild ? fFirstChild->Name() : "NULL", 4904 fNextSibling ? fNextSibling->Name() : "NULL", 4905 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 4906 fOwner ? fOwner->Name() : "NULL", 4907 _get_object_token_(this), 4908 fFlags, 4909 fParentOffset.x, fParentOffset.y, 4910 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 4911 fShowLevel, 4912 fTopLevelView ? "YES" : "NO", 4913 cpicture? "YES" : "NULL", 4914 fVerScroller? "YES" : "NULL", 4915 fHorScroller? "YES" : "NULL", 4916 f_is_printing? "YES" : "NO", 4917 fShelf? "YES" : "NO", 4918 fEventMask, 4919 fEventOptions); 4920 4921 printf("\tState status:\n" 4922 "\t\tLocalCoordianteSystem: (%f,%f)\n" 4923 "\t\tPenLocation: (%f,%f)\n" 4924 "\t\tPenSize: %f\n" 4925 "\t\tHighColor: [%d,%d,%d,%d]\n" 4926 "\t\tLowColor: [%d,%d,%d,%d]\n" 4927 "\t\tViewColor: [%d,%d,%d,%d]\n" 4928 "\t\tPattern: %llx\n" 4929 "\t\tDrawingMode: %d\n" 4930 "\t\tLineJoinMode: %d\n" 4931 "\t\tLineCapMode: %d\n" 4932 "\t\tMiterLimit: %f\n" 4933 "\t\tAlphaSource: %d\n" 4934 "\t\tAlphaFuntion: %d\n" 4935 "\t\tScale: %f\n" 4936 "\t\t(Print)FontAliasing: %s\n" 4937 "\t\tFont Info:\n", 4938 fState->origin.x, fState->origin.y, 4939 fState->pen_location.x, fState->pen_location.y, 4940 fState->pen_size, 4941 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 4942 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 4943 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 4944 *((uint64*)&(fState->pattern)), 4945 fState->drawing_mode, 4946 fState->line_join, 4947 fState->line_cap, 4948 fState->miter_limit, 4949 fState->alpha_source_mode, 4950 fState->alpha_function_mode, 4951 fState->scale, 4952 fState->font_aliasing? "YES" : "NO"); 4953 4954 fState->font.PrintToStream(); 4955 4956 // TODO: also print the line array. 4957 } 4958 4959 4960 void 4961 BView::_PrintTree() 4962 { 4963 int32 spaces = 2; 4964 BView *c = fFirstChild; //c = short for: current 4965 printf( "'%s'\n", Name() ); 4966 if (c != NULL) { 4967 while(true) { 4968 // action block 4969 { 4970 for (int i = 0; i < spaces; i++) 4971 printf(" "); 4972 4973 printf( "'%s'\n", c->Name() ); 4974 } 4975 4976 // go deep 4977 if (c->fFirstChild) { 4978 c = c->fFirstChild; 4979 spaces += 2; 4980 } else { 4981 // go right 4982 if (c->fNextSibling) { 4983 c = c->fNextSibling; 4984 } else { 4985 // go up 4986 while (!c->fParent->fNextSibling && c->fParent != this) { 4987 c = c->fParent; 4988 spaces -= 2; 4989 } 4990 4991 // that enough! We've reached this view. 4992 if (c->fParent == this) 4993 break; 4994 4995 c = c->fParent->fNextSibling; 4996 spaces -= 2; 4997 } 4998 } 4999 } 5000 } 5001 } 5002 5003 5004