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