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