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