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