1 /* 2 * Copyright 2001-2017 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus, superstippi@gmx.de 7 * Axel Dörfler, axeld@pinc-software.de 8 * Adrian Oanca, adioanca@cotty.iren.ro 9 * Ingo Weinhold. ingo_weinhold@gmx.de 10 * Julian Harnath, julian.harnath@rwth-aachen.de 11 * Joseph Groover, looncraz@looncraz.net 12 */ 13 14 15 #include <View.h> 16 17 #include <algorithm> 18 #include <new> 19 20 #include <math.h> 21 #include <stdio.h> 22 23 #include <Application.h> 24 #include <Bitmap.h> 25 #include <Button.h> 26 #include <Cursor.h> 27 #include <File.h> 28 #include <GradientLinear.h> 29 #include <GradientRadial.h> 30 #include <GradientRadialFocus.h> 31 #include <GradientDiamond.h> 32 #include <GradientConic.h> 33 #include <InterfaceDefs.h> 34 #include <Layout.h> 35 #include <LayoutContext.h> 36 #include <LayoutUtils.h> 37 #include <MenuBar.h> 38 #include <Message.h> 39 #include <MessageQueue.h> 40 #include <ObjectList.h> 41 #include <Picture.h> 42 #include <Point.h> 43 #include <Polygon.h> 44 #include <PropertyInfo.h> 45 #include <Region.h> 46 #include <ScrollBar.h> 47 #include <Shape.h> 48 #include <Shelf.h> 49 #include <String.h> 50 #include <Window.h> 51 52 #include <AppMisc.h> 53 #include <AppServerLink.h> 54 #include <binary_compatibility/Interface.h> 55 #include <binary_compatibility/Support.h> 56 #include <MessagePrivate.h> 57 #include <MessageUtils.h> 58 #include <PortLink.h> 59 #include <ServerProtocol.h> 60 #include <ServerProtocolStructs.h> 61 #include <ShapePrivate.h> 62 #include <ToolTip.h> 63 #include <ToolTipManager.h> 64 #include <TokenSpace.h> 65 #include <ViewPrivate.h> 66 67 using std::nothrow; 68 69 //#define DEBUG_BVIEW 70 #ifdef DEBUG_BVIEW 71 # include <stdio.h> 72 # define STRACE(x) printf x 73 # define BVTRACE _PrintToStream() 74 #else 75 # define STRACE(x) ; 76 # define BVTRACE ; 77 #endif 78 79 80 static property_info sViewPropInfo[] = { 81 { "Frame", { B_GET_PROPERTY, B_SET_PROPERTY }, 82 { B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0, 83 { B_RECT_TYPE } 84 }, 85 { "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY }, 86 { B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.", 87 0, { B_BOOL_TYPE } 88 }, 89 { "Shelf", { 0 }, 90 { B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the " 91 "shelf.", 0 92 }, 93 { "View", { B_COUNT_PROPERTIES, 0 }, 94 { B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0, 95 { B_INT32_TYPE } 96 }, 97 { "View", { 0 }, 98 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 }, 99 "Directs the scripting message to the specified view.", 0 100 }, 101 102 { 0 } 103 }; 104 105 106 // #pragma mark - 107 108 109 static inline uint32 110 get_uint32_color(rgb_color color) 111 { 112 return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color); 113 // rgb_color is always in rgba format, no matter what endian; 114 // we always return the int32 value in host endian. 115 } 116 117 118 static inline rgb_color 119 get_rgb_color(uint32 value) 120 { 121 value = B_HOST_TO_BENDIAN_INT32(value); 122 return *(rgb_color*)&value; 123 } 124 125 126 // #pragma mark - 127 128 129 namespace BPrivate { 130 131 ViewState::ViewState() 132 { 133 pen_location.Set(0, 0); 134 pen_size = 1.0; 135 136 // NOTE: the clipping_region is empty 137 // on construction but it is not used yet, 138 // we avoid having to keep track of it via 139 // this flag 140 clipping_region_used = false; 141 142 high_color = (rgb_color){ 0, 0, 0, 255 }; 143 low_color = (rgb_color){ 255, 255, 255, 255 }; 144 view_color = low_color; 145 which_view_color = B_NO_COLOR; 146 which_view_color_tint = B_NO_TINT; 147 148 which_high_color = B_NO_COLOR; 149 which_high_color_tint = B_NO_TINT; 150 151 which_low_color = B_NO_COLOR; 152 which_low_color_tint = B_NO_TINT; 153 154 pattern = B_SOLID_HIGH; 155 drawing_mode = B_OP_COPY; 156 157 origin.Set(0, 0); 158 159 line_join = B_MITER_JOIN; 160 line_cap = B_BUTT_CAP; 161 miter_limit = B_DEFAULT_MITER_LIMIT; 162 fill_rule = B_NONZERO; 163 164 alpha_source_mode = B_PIXEL_ALPHA; 165 alpha_function_mode = B_ALPHA_OVERLAY; 166 167 scale = 1.0; 168 169 font = *be_plain_font; 170 font_flags = font.Flags(); 171 font_aliasing = false; 172 173 // We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated, 174 // because we should get the clipping region from app_server. 175 // The other flags do not need to be included because the data they 176 // represent is already in sync with app_server - app_server uses the 177 // same init (default) values. 178 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 179 180 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT; 181 } 182 183 184 void 185 ViewState::UpdateServerFontState(BPrivate::PortLink &link) 186 { 187 link.StartMessage(AS_VIEW_SET_FONT_STATE); 188 link.Attach<uint16>(font_flags); 189 // always present 190 191 if (font_flags & B_FONT_FAMILY_AND_STYLE) 192 link.Attach<uint32>(font.FamilyAndStyle()); 193 194 if (font_flags & B_FONT_SIZE) 195 link.Attach<float>(font.Size()); 196 197 if (font_flags & B_FONT_SHEAR) 198 link.Attach<float>(font.Shear()); 199 200 if (font_flags & B_FONT_ROTATION) 201 link.Attach<float>(font.Rotation()); 202 203 if (font_flags & B_FONT_FALSE_BOLD_WIDTH) 204 link.Attach<float>(font.FalseBoldWidth()); 205 206 if (font_flags & B_FONT_SPACING) 207 link.Attach<uint8>(font.Spacing()); 208 209 if (font_flags & B_FONT_ENCODING) 210 link.Attach<uint8>(font.Encoding()); 211 212 if (font_flags & B_FONT_FACE) 213 link.Attach<uint16>(font.Face()); 214 215 if (font_flags & B_FONT_FLAGS) 216 link.Attach<uint32>(font.Flags()); 217 } 218 219 220 void 221 ViewState::UpdateServerState(BPrivate::PortLink &link) 222 { 223 UpdateServerFontState(link); 224 225 link.StartMessage(AS_VIEW_SET_STATE); 226 227 ViewSetStateInfo info; 228 info.penLocation = pen_location; 229 info.penSize = pen_size; 230 info.highColor = high_color; 231 info.lowColor = low_color; 232 info.whichHighColor = which_high_color; 233 info.whichLowColor = which_low_color; 234 info.whichHighColorTint = which_high_color_tint; 235 info.whichLowColorTint = which_low_color_tint; 236 info.pattern = pattern; 237 info.drawingMode = drawing_mode; 238 info.origin = origin; 239 info.scale = scale; 240 info.lineJoin = line_join; 241 info.lineCap = line_cap; 242 info.miterLimit = miter_limit; 243 info.fillRule = fill_rule; 244 info.alphaSourceMode = alpha_source_mode; 245 info.alphaFunctionMode = alpha_function_mode; 246 info.fontAntialiasing = font_aliasing; 247 link.Attach<ViewSetStateInfo>(info); 248 249 // BAffineTransform is transmitted as a double array 250 double _transform[6]; 251 if (transform.Flatten(_transform, sizeof(_transform)) != B_OK) 252 return; 253 link.Attach<double[6]>(_transform); 254 255 // we send the 'local' clipping region... if we have one... 256 // TODO: Could be optimized, but is low prio, since most views won't 257 // have a custom clipping region. 258 if (clipping_region_used) { 259 int32 count = clipping_region.CountRects(); 260 link.Attach<int32>(count); 261 for (int32 i = 0; i < count; i++) 262 link.Attach<BRect>(clipping_region.RectAt(i)); 263 } else { 264 // no clipping region 265 link.Attach<int32>(-1); 266 } 267 268 // Although we might have a 'local' clipping region, when we call 269 // BView::GetClippingRegion() we ask for the 'global' one and it 270 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag 271 272 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 273 } 274 275 276 void 277 ViewState::UpdateFrom(BPrivate::PortLink &link) 278 { 279 link.StartMessage(AS_VIEW_GET_STATE); 280 281 int32 code; 282 if (link.FlushWithReply(code) != B_OK 283 || code != B_OK) 284 return; 285 286 ViewGetStateInfo info; 287 link.Read<ViewGetStateInfo>(&info); 288 289 // set view's font state 290 font_flags = B_FONT_ALL; 291 font.SetFamilyAndStyle(info.fontID); 292 font.SetSize(info.fontSize); 293 font.SetShear(info.fontShear); 294 font.SetRotation(info.fontRotation); 295 font.SetFalseBoldWidth(info.fontFalseBoldWidth); 296 font.SetSpacing(info.fontSpacing); 297 font.SetEncoding(info.fontEncoding); 298 font.SetFace(info.fontFace); 299 font.SetFlags(info.fontFlags); 300 301 // set view's state 302 pen_location = info.viewStateInfo.penLocation; 303 pen_size = info.viewStateInfo.penSize; 304 high_color = info.viewStateInfo.highColor; 305 low_color = info.viewStateInfo.lowColor; 306 pattern = info.viewStateInfo.pattern; 307 drawing_mode = info.viewStateInfo.drawingMode; 308 origin = info.viewStateInfo.origin; 309 scale = info.viewStateInfo.scale; 310 line_join = info.viewStateInfo.lineJoin; 311 line_cap = info.viewStateInfo.lineCap; 312 miter_limit = info.viewStateInfo.miterLimit; 313 fill_rule = info.viewStateInfo.fillRule; 314 alpha_source_mode = info.viewStateInfo.alphaSourceMode; 315 alpha_function_mode = info.viewStateInfo.alphaFunctionMode; 316 font_aliasing = info.viewStateInfo.fontAntialiasing; 317 318 // BAffineTransform is transmitted as a double array 319 double _transform[6]; 320 link.Read<double[6]>(&_transform); 321 if (transform.Unflatten(B_AFFINE_TRANSFORM_TYPE, _transform, 322 sizeof(_transform)) != B_OK) { 323 return; 324 } 325 326 // read the user clipping 327 // (that's NOT the current View visible clipping but the additional 328 // user specified clipping!) 329 int32 clippingRectCount; 330 link.Read<int32>(&clippingRectCount); 331 if (clippingRectCount >= 0) { 332 clipping_region.MakeEmpty(); 333 for (int32 i = 0; i < clippingRectCount; i++) { 334 BRect rect; 335 link.Read<BRect>(&rect); 336 clipping_region.Include(rect); 337 } 338 } else { 339 // no user clipping used 340 clipping_region_used = false; 341 } 342 343 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 344 } 345 346 } // namespace BPrivate 347 348 349 // #pragma mark - 350 351 352 // archiving constants 353 namespace { 354 const char* const kSizesField = "BView:sizes"; 355 // kSizesField = {min, max, pref} 356 const char* const kAlignmentField = "BView:alignment"; 357 const char* const kLayoutField = "BView:layout"; 358 } 359 360 361 struct BView::LayoutData { 362 LayoutData() 363 : 364 fMinSize(), 365 fMaxSize(), 366 fPreferredSize(), 367 fAlignment(), 368 fLayoutInvalidationDisabled(0), 369 fLayout(NULL), 370 fLayoutContext(NULL), 371 fLayoutItems(5, false), 372 fLayoutValid(true), // TODO: Rethink these initial values! 373 fMinMaxValid(true), // 374 fLayoutInProgress(false), 375 fNeedsRelayout(true) 376 { 377 } 378 379 status_t 380 AddDataToArchive(BMessage* archive) 381 { 382 status_t err = archive->AddSize(kSizesField, fMinSize); 383 384 if (err == B_OK) 385 err = archive->AddSize(kSizesField, fMaxSize); 386 387 if (err == B_OK) 388 err = archive->AddSize(kSizesField, fPreferredSize); 389 390 if (err == B_OK) 391 err = archive->AddAlignment(kAlignmentField, fAlignment); 392 393 return err; 394 } 395 396 void 397 PopulateFromArchive(BMessage* archive) 398 { 399 archive->FindSize(kSizesField, 0, &fMinSize); 400 archive->FindSize(kSizesField, 1, &fMaxSize); 401 archive->FindSize(kSizesField, 2, &fPreferredSize); 402 archive->FindAlignment(kAlignmentField, &fAlignment); 403 } 404 405 BSize fMinSize; 406 BSize fMaxSize; 407 BSize fPreferredSize; 408 BAlignment fAlignment; 409 int fLayoutInvalidationDisabled; 410 BLayout* fLayout; 411 BLayoutContext* fLayoutContext; 412 BObjectList<BLayoutItem> fLayoutItems; 413 bool fLayoutValid; 414 bool fMinMaxValid; 415 bool fLayoutInProgress; 416 bool fNeedsRelayout; 417 }; 418 419 420 BView::BView(const char* name, uint32 flags, BLayout* layout) 421 : 422 BHandler(name) 423 { 424 _InitData(BRect(0, 0, -1, -1), name, B_FOLLOW_NONE, 425 flags | B_SUPPORTS_LAYOUT); 426 SetLayout(layout); 427 } 428 429 430 BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags) 431 : 432 BHandler(name) 433 { 434 _InitData(frame, name, resizingMode, flags); 435 } 436 437 438 BView::BView(BMessage* archive) 439 : 440 BHandler(BUnarchiver::PrepareArchive(archive)) 441 { 442 BUnarchiver unarchiver(archive); 443 if (!archive) 444 debugger("BView cannot be constructed from a NULL archive."); 445 446 BRect frame; 447 archive->FindRect("_frame", &frame); 448 449 uint32 resizingMode; 450 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK) 451 resizingMode = 0; 452 453 uint32 flags; 454 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK) 455 flags = 0; 456 457 _InitData(frame, Name(), resizingMode, flags); 458 459 font_family family; 460 font_style style; 461 if (archive->FindString("_fname", 0, (const char**)&family) == B_OK 462 && archive->FindString("_fname", 1, (const char**)&style) == B_OK) { 463 BFont font; 464 font.SetFamilyAndStyle(family, style); 465 466 float size; 467 if (archive->FindFloat("_fflt", 0, &size) == B_OK) 468 font.SetSize(size); 469 470 float shear; 471 if (archive->FindFloat("_fflt", 1, &shear) == B_OK 472 && shear >= 45.0 && shear <= 135.0) 473 font.SetShear(shear); 474 475 float rotation; 476 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK 477 && rotation >=0 && rotation <= 360) 478 font.SetRotation(rotation); 479 480 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE 481 | B_FONT_SHEAR | B_FONT_ROTATION); 482 } 483 484 int32 color = 0; 485 if (archive->FindInt32("_color", 0, &color) == B_OK) 486 SetHighColor(get_rgb_color(color)); 487 if (archive->FindInt32("_color", 1, &color) == B_OK) 488 SetLowColor(get_rgb_color(color)); 489 if (archive->FindInt32("_color", 2, &color) == B_OK) 490 SetViewColor(get_rgb_color(color)); 491 492 float tint = B_NO_TINT; 493 if (archive->FindInt32("_uicolor", 0, &color) == B_OK 494 && color != B_NO_COLOR) { 495 if (archive->FindFloat("_uitint", 0, &tint) != B_OK) 496 tint = B_NO_TINT; 497 498 SetHighUIColor((color_which)color, tint); 499 } 500 if (archive->FindInt32("_uicolor", 1, &color) == B_OK 501 && color != B_NO_COLOR) { 502 if (archive->FindFloat("_uitint", 1, &tint) != B_OK) 503 tint = B_NO_TINT; 504 505 SetLowUIColor((color_which)color, tint); 506 } 507 if (archive->FindInt32("_uicolor", 2, &color) == B_OK 508 && color != B_NO_COLOR) { 509 if (archive->FindFloat("_uitint", 2, &tint) != B_OK) 510 tint = B_NO_TINT; 511 512 SetViewUIColor((color_which)color, tint); 513 } 514 515 uint32 evMask; 516 uint32 options; 517 if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK 518 && archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK) 519 SetEventMask(evMask, options); 520 521 BPoint origin; 522 if (archive->FindPoint("_origin", &origin) == B_OK) 523 SetOrigin(origin); 524 525 float scale; 526 if (archive->FindFloat("_scale", &scale) == B_OK) 527 SetScale(scale); 528 529 BAffineTransform transform; 530 if (archive->FindFlat("_transform", &transform) == B_OK) 531 SetTransform(transform); 532 533 float penSize; 534 if (archive->FindFloat("_psize", &penSize) == B_OK) 535 SetPenSize(penSize); 536 537 BPoint penLocation; 538 if (archive->FindPoint("_ploc", &penLocation) == B_OK) 539 MovePenTo(penLocation); 540 541 int16 lineCap; 542 int16 lineJoin; 543 float lineMiter; 544 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK 545 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK 546 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK) 547 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter); 548 549 int16 fillRule; 550 if (archive->FindInt16("_fillrule", &fillRule) == B_OK) 551 SetFillRule(fillRule); 552 553 int16 alphaBlend; 554 int16 modeBlend; 555 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK 556 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK) 557 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend); 558 559 uint32 drawingMode; 560 if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK) 561 SetDrawingMode((drawing_mode)drawingMode); 562 563 fLayoutData->PopulateFromArchive(archive); 564 565 if (archive->FindInt16("_show", &fShowLevel) != B_OK) 566 fShowLevel = 0; 567 568 if (BUnarchiver::IsArchiveManaged(archive)) { 569 int32 i = 0; 570 while (unarchiver.EnsureUnarchived("_views", i++) == B_OK) 571 ; 572 unarchiver.EnsureUnarchived(kLayoutField); 573 574 } else { 575 BMessage msg; 576 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK; 577 i++) { 578 BArchivable* object = instantiate_object(&msg); 579 if (BView* child = dynamic_cast<BView*>(object)) 580 AddChild(child); 581 } 582 } 583 } 584 585 586 BArchivable* 587 BView::Instantiate(BMessage* data) 588 { 589 if (!validate_instantiation(data , "BView")) 590 return NULL; 591 592 return new(std::nothrow) BView(data); 593 } 594 595 596 status_t 597 BView::Archive(BMessage* data, bool deep) const 598 { 599 BArchiver archiver(data); 600 status_t ret = BHandler::Archive(data, deep); 601 602 if (ret != B_OK) 603 return ret; 604 605 if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0) 606 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset)); 607 608 if (ret == B_OK) 609 ret = data->AddInt32("_resize_mode", ResizingMode()); 610 611 if (ret == B_OK) 612 ret = data->AddInt32("_flags", Flags()); 613 614 if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) { 615 ret = data->AddInt32("_evmask", fEventMask); 616 if (ret == B_OK) 617 ret = data->AddInt32("_evmask", fEventOptions); 618 } 619 620 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) { 621 BFont font; 622 GetFont(&font); 623 624 font_family family; 625 font_style style; 626 font.GetFamilyAndStyle(&family, &style); 627 ret = data->AddString("_fname", family); 628 if (ret == B_OK) 629 ret = data->AddString("_fname", style); 630 if (ret == B_OK) 631 ret = data->AddFloat("_fflt", font.Size()); 632 if (ret == B_OK) 633 ret = data->AddFloat("_fflt", font.Shear()); 634 if (ret == B_OK) 635 ret = data->AddFloat("_fflt", font.Rotation()); 636 } 637 638 // colors 639 if (ret == B_OK) 640 ret = data->AddInt32("_color", get_uint32_color(HighColor())); 641 if (ret == B_OK) 642 ret = data->AddInt32("_color", get_uint32_color(LowColor())); 643 if (ret == B_OK) 644 ret = data->AddInt32("_color", get_uint32_color(ViewColor())); 645 646 if (ret == B_OK) 647 ret = data->AddInt32("_uicolor", (int32)HighUIColor()); 648 if (ret == B_OK) 649 ret = data->AddInt32("_uicolor", (int32)LowUIColor()); 650 if (ret == B_OK) 651 ret = data->AddInt32("_uicolor", (int32)ViewUIColor()); 652 653 if (ret == B_OK) 654 ret = data->AddFloat("_uitint", fState->which_high_color_tint); 655 if (ret == B_OK) 656 ret = data->AddFloat("_uitint", fState->which_low_color_tint); 657 if (ret == B_OK) 658 ret = data->AddFloat("_uitint", fState->which_view_color_tint); 659 660 // NOTE: we do not use this flag any more 661 // if ( 1 ){ 662 // ret = data->AddInt32("_dbuf", 1); 663 // } 664 665 if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0) 666 ret = data->AddPoint("_origin", Origin()); 667 668 if (ret == B_OK && (fState->archiving_flags & B_VIEW_SCALE_BIT) != 0) 669 ret = data->AddFloat("_scale", Scale()); 670 671 if (ret == B_OK && (fState->archiving_flags & B_VIEW_TRANSFORM_BIT) != 0) { 672 BAffineTransform transform = Transform(); 673 ret = data->AddFlat("_transform", &transform); 674 } 675 676 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0) 677 ret = data->AddFloat("_psize", PenSize()); 678 679 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0) 680 ret = data->AddPoint("_ploc", PenLocation()); 681 682 if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) { 683 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode()); 684 if (ret == B_OK) 685 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode()); 686 if (ret == B_OK) 687 ret = data->AddFloat("_lmmiter", LineMiterLimit()); 688 } 689 690 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FILL_RULE_BIT) != 0) 691 ret = data->AddInt16("_fillrule", (int16)FillRule()); 692 693 if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) { 694 source_alpha alphaSourceMode; 695 alpha_function alphaFunctionMode; 696 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode); 697 698 ret = data->AddInt16("_blend", (int16)alphaSourceMode); 699 if (ret == B_OK) 700 ret = data->AddInt16("_blend", (int16)alphaFunctionMode); 701 } 702 703 if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0) 704 ret = data->AddInt32("_dmod", DrawingMode()); 705 706 if (ret == B_OK) 707 ret = fLayoutData->AddDataToArchive(data); 708 709 if (ret == B_OK) 710 ret = data->AddInt16("_show", fShowLevel); 711 712 if (deep && ret == B_OK) { 713 for (BView* child = fFirstChild; child != NULL && ret == B_OK; 714 child = child->fNextSibling) 715 ret = archiver.AddArchivable("_views", child, deep); 716 717 if (ret == B_OK) 718 ret = archiver.AddArchivable(kLayoutField, GetLayout(), deep); 719 } 720 721 return archiver.Finish(ret); 722 } 723 724 725 status_t 726 BView::AllUnarchived(const BMessage* from) 727 { 728 BUnarchiver unarchiver(from); 729 status_t err = B_OK; 730 731 int32 count; 732 from->GetInfo("_views", NULL, &count); 733 734 for (int32 i = 0; err == B_OK && i < count; i++) { 735 BView* child; 736 err = unarchiver.FindObject<BView>("_views", i, child); 737 if (err == B_OK) 738 err = _AddChild(child, NULL) ? B_OK : B_ERROR; 739 } 740 741 if (err == B_OK) { 742 BLayout*& layout = fLayoutData->fLayout; 743 err = unarchiver.FindObject(kLayoutField, layout); 744 if (err == B_OK && layout) { 745 fFlags |= B_SUPPORTS_LAYOUT; 746 fLayoutData->fLayout->SetOwner(this); 747 } 748 } 749 750 return err; 751 } 752 753 754 status_t 755 BView::AllArchived(BMessage* into) const 756 { 757 return BHandler::AllArchived(into); 758 } 759 760 761 BView::~BView() 762 { 763 STRACE(("BView(%s)::~BView()\n", this->Name())); 764 765 if (fOwner != NULL) { 766 debugger("Trying to delete a view that belongs to a window. " 767 "Call RemoveSelf first."); 768 } 769 770 // we also delete all our children 771 772 BView* child = fFirstChild; 773 while (child) { 774 BView* nextChild = child->fNextSibling; 775 776 delete child; 777 child = nextChild; 778 } 779 780 SetLayout(NULL); 781 _RemoveLayoutItemsFromLayout(true); 782 783 delete fLayoutData; 784 785 _RemoveSelf(); 786 787 if (fToolTip != NULL) 788 fToolTip->ReleaseReference(); 789 790 if (fVerScroller != NULL) 791 fVerScroller->SetTarget((BView*)NULL); 792 if (fHorScroller != NULL) 793 fHorScroller->SetTarget((BView*)NULL); 794 795 SetName(NULL); 796 797 _RemoveCommArray(); 798 delete fState; 799 } 800 801 802 BRect 803 BView::Bounds() const 804 { 805 _CheckLock(); 806 807 if (fIsPrinting) 808 return fState->print_rect; 809 810 return fBounds; 811 } 812 813 814 void 815 BView::_ConvertToParent(BPoint* point, bool checkLock) const 816 { 817 if (!fParent) 818 return; 819 820 if (checkLock) 821 _CheckLock(); 822 823 // - our scrolling offset 824 // + our bounds location within the parent 825 point->x += -fBounds.left + fParentOffset.x; 826 point->y += -fBounds.top + fParentOffset.y; 827 } 828 829 830 void 831 BView::ConvertToParent(BPoint* point) const 832 { 833 _ConvertToParent(point, true); 834 } 835 836 837 BPoint 838 BView::ConvertToParent(BPoint point) const 839 { 840 ConvertToParent(&point); 841 842 return point; 843 } 844 845 846 void 847 BView::_ConvertFromParent(BPoint* point, bool checkLock) const 848 { 849 if (!fParent) 850 return; 851 852 if (checkLock) 853 _CheckLock(); 854 855 // - our bounds location within the parent 856 // + our scrolling offset 857 point->x += -fParentOffset.x + fBounds.left; 858 point->y += -fParentOffset.y + fBounds.top; 859 } 860 861 862 void 863 BView::ConvertFromParent(BPoint* point) const 864 { 865 _ConvertFromParent(point, true); 866 } 867 868 869 BPoint 870 BView::ConvertFromParent(BPoint point) const 871 { 872 ConvertFromParent(&point); 873 874 return point; 875 } 876 877 878 void 879 BView::ConvertToParent(BRect* rect) const 880 { 881 if (!fParent) 882 return; 883 884 _CheckLock(); 885 886 // - our scrolling offset 887 // + our bounds location within the parent 888 rect->OffsetBy(-fBounds.left + fParentOffset.x, 889 -fBounds.top + fParentOffset.y); 890 } 891 892 893 BRect 894 BView::ConvertToParent(BRect rect) const 895 { 896 ConvertToParent(&rect); 897 898 return rect; 899 } 900 901 902 void 903 BView::ConvertFromParent(BRect* rect) const 904 { 905 if (!fParent) 906 return; 907 908 _CheckLock(); 909 910 // - our bounds location within the parent 911 // + our scrolling offset 912 rect->OffsetBy(-fParentOffset.x + fBounds.left, 913 -fParentOffset.y + fBounds.top); 914 } 915 916 917 BRect 918 BView::ConvertFromParent(BRect rect) const 919 { 920 ConvertFromParent(&rect); 921 922 return rect; 923 } 924 925 926 void 927 BView::_ConvertToScreen(BPoint* point, bool checkLock) const 928 { 929 if (!fParent) { 930 if (fOwner) 931 fOwner->ConvertToScreen(point); 932 933 return; 934 } 935 936 if (checkLock) 937 _CheckOwnerLock(); 938 939 _ConvertToParent(point, false); 940 fParent->_ConvertToScreen(point, false); 941 } 942 943 944 void 945 BView::ConvertToScreen(BPoint* point) const 946 { 947 _ConvertToScreen(point, true); 948 } 949 950 951 BPoint 952 BView::ConvertToScreen(BPoint point) const 953 { 954 ConvertToScreen(&point); 955 956 return point; 957 } 958 959 960 void 961 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const 962 { 963 if (!fParent) { 964 if (fOwner) 965 fOwner->ConvertFromScreen(point); 966 967 return; 968 } 969 970 if (checkLock) 971 _CheckOwnerLock(); 972 973 _ConvertFromParent(point, false); 974 fParent->_ConvertFromScreen(point, false); 975 } 976 977 978 void 979 BView::ConvertFromScreen(BPoint* point) const 980 { 981 _ConvertFromScreen(point, true); 982 } 983 984 985 BPoint 986 BView::ConvertFromScreen(BPoint point) const 987 { 988 ConvertFromScreen(&point); 989 990 return point; 991 } 992 993 994 void 995 BView::ConvertToScreen(BRect* rect) const 996 { 997 BPoint offset(0.0, 0.0); 998 ConvertToScreen(&offset); 999 rect->OffsetBy(offset); 1000 } 1001 1002 1003 BRect 1004 BView::ConvertToScreen(BRect rect) const 1005 { 1006 ConvertToScreen(&rect); 1007 1008 return rect; 1009 } 1010 1011 1012 void 1013 BView::ConvertFromScreen(BRect* rect) const 1014 { 1015 BPoint offset(0.0, 0.0); 1016 ConvertFromScreen(&offset); 1017 rect->OffsetBy(offset); 1018 } 1019 1020 1021 BRect 1022 BView::ConvertFromScreen(BRect rect) const 1023 { 1024 ConvertFromScreen(&rect); 1025 1026 return rect; 1027 } 1028 1029 1030 uint32 1031 BView::Flags() const 1032 { 1033 _CheckLock(); 1034 return fFlags & ~_RESIZE_MASK_; 1035 } 1036 1037 1038 void 1039 BView::SetFlags(uint32 flags) 1040 { 1041 if (Flags() == flags) 1042 return; 1043 1044 if (fOwner) { 1045 if (flags & B_PULSE_NEEDED) { 1046 _CheckLock(); 1047 if (fOwner->fPulseRunner == NULL) 1048 fOwner->SetPulseRate(fOwner->PulseRate()); 1049 } 1050 1051 uint32 changesFlags = flags ^ fFlags; 1052 if (changesFlags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 1053 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) { 1054 _CheckLockAndSwitchCurrent(); 1055 1056 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS); 1057 fOwner->fLink->Attach<uint32>(flags); 1058 fOwner->fLink->Flush(); 1059 } 1060 } 1061 1062 /* Some useful info: 1063 fFlags is a unsigned long (32 bits) 1064 * bits 1-16 are used for BView's flags 1065 * bits 17-32 are used for BView' resize mask 1066 * _RESIZE_MASK_ is used for that. Look into View.h to see how 1067 it's defined 1068 */ 1069 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_); 1070 1071 fState->archiving_flags |= B_VIEW_FLAGS_BIT; 1072 } 1073 1074 1075 BRect 1076 BView::Frame() const 1077 { 1078 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y); 1079 } 1080 1081 1082 void 1083 BView::Hide() 1084 { 1085 if (fOwner && fShowLevel == 0) { 1086 _CheckLockAndSwitchCurrent(); 1087 fOwner->fLink->StartMessage(AS_VIEW_HIDE); 1088 fOwner->fLink->Flush(); 1089 } 1090 fShowLevel++; 1091 1092 if (fShowLevel == 1) 1093 _InvalidateParentLayout(); 1094 } 1095 1096 1097 void 1098 BView::Show() 1099 { 1100 fShowLevel--; 1101 if (fOwner && fShowLevel == 0) { 1102 _CheckLockAndSwitchCurrent(); 1103 fOwner->fLink->StartMessage(AS_VIEW_SHOW); 1104 fOwner->fLink->Flush(); 1105 } 1106 1107 if (fShowLevel == 0) 1108 _InvalidateParentLayout(); 1109 } 1110 1111 1112 bool 1113 BView::IsFocus() const 1114 { 1115 if (fOwner) { 1116 _CheckLock(); 1117 return fOwner->CurrentFocus() == this; 1118 } else 1119 return false; 1120 } 1121 1122 1123 bool 1124 BView::IsHidden(const BView* lookingFrom) const 1125 { 1126 if (fShowLevel > 0) 1127 return true; 1128 1129 // may we be egocentric? 1130 if (lookingFrom == this) 1131 return false; 1132 1133 // we have the same visibility state as our 1134 // parent, if there is one 1135 if (fParent) 1136 return fParent->IsHidden(lookingFrom); 1137 1138 // if we're the top view, and we're interested 1139 // in the "global" view, we're inheriting the 1140 // state of the window's visibility 1141 if (fOwner && lookingFrom == NULL) 1142 return fOwner->IsHidden(); 1143 1144 return false; 1145 } 1146 1147 1148 bool 1149 BView::IsHidden() const 1150 { 1151 return IsHidden(NULL); 1152 } 1153 1154 1155 bool 1156 BView::IsPrinting() const 1157 { 1158 return fIsPrinting; 1159 } 1160 1161 1162 BPoint 1163 BView::LeftTop() const 1164 { 1165 return Bounds().LeftTop(); 1166 } 1167 1168 1169 void 1170 BView::SetResizingMode(uint32 mode) 1171 { 1172 if (fOwner) { 1173 _CheckLockAndSwitchCurrent(); 1174 1175 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE); 1176 fOwner->fLink->Attach<uint32>(mode); 1177 } 1178 1179 // look at SetFlags() for more info on the below line 1180 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_); 1181 } 1182 1183 1184 uint32 1185 BView::ResizingMode() const 1186 { 1187 return fFlags & _RESIZE_MASK_; 1188 } 1189 1190 1191 void 1192 BView::SetViewCursor(const BCursor* cursor, bool sync) 1193 { 1194 if (cursor == NULL || fOwner == NULL) 1195 return; 1196 1197 _CheckLock(); 1198 1199 ViewSetViewCursorInfo info; 1200 info.cursorToken = cursor->fServerToken; 1201 info.viewToken = _get_object_token_(this); 1202 info.sync = sync; 1203 1204 BPrivate::AppServerLink link; 1205 link.StartMessage(AS_SET_VIEW_CURSOR); 1206 link.Attach<ViewSetViewCursorInfo>(info); 1207 1208 if (sync) { 1209 // Make sure the server has processed the message. 1210 int32 code; 1211 link.FlushWithReply(code); 1212 } 1213 } 1214 1215 1216 void 1217 BView::Flush() const 1218 { 1219 if (fOwner) 1220 fOwner->Flush(); 1221 } 1222 1223 1224 void 1225 BView::Sync() const 1226 { 1227 _CheckOwnerLock(); 1228 if (fOwner) 1229 fOwner->Sync(); 1230 } 1231 1232 1233 BWindow* 1234 BView::Window() const 1235 { 1236 return fOwner; 1237 } 1238 1239 1240 // #pragma mark - Hook Functions 1241 1242 1243 void 1244 BView::AttachedToWindow() 1245 { 1246 // Hook function 1247 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name())); 1248 } 1249 1250 1251 void 1252 BView::AllAttached() 1253 { 1254 // Hook function 1255 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name())); 1256 } 1257 1258 1259 void 1260 BView::DetachedFromWindow() 1261 { 1262 // Hook function 1263 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name())); 1264 } 1265 1266 1267 void 1268 BView::AllDetached() 1269 { 1270 // Hook function 1271 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name())); 1272 } 1273 1274 1275 void 1276 BView::Draw(BRect updateRect) 1277 { 1278 // Hook function 1279 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name())); 1280 } 1281 1282 1283 void 1284 BView::DrawAfterChildren(BRect updateRect) 1285 { 1286 // Hook function 1287 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name())); 1288 } 1289 1290 1291 void 1292 BView::FrameMoved(BPoint newPosition) 1293 { 1294 // Hook function 1295 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name())); 1296 } 1297 1298 1299 void 1300 BView::FrameResized(float newWidth, float newHeight) 1301 { 1302 // Hook function 1303 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name())); 1304 } 1305 1306 1307 void 1308 BView::GetPreferredSize(float* _width, float* _height) 1309 { 1310 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name())); 1311 1312 if (_width != NULL) 1313 *_width = fBounds.Width(); 1314 if (_height != NULL) 1315 *_height = fBounds.Height(); 1316 } 1317 1318 1319 void 1320 BView::ResizeToPreferred() 1321 { 1322 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name())); 1323 1324 float width; 1325 float height; 1326 GetPreferredSize(&width, &height); 1327 1328 ResizeTo(width, height); 1329 } 1330 1331 1332 void 1333 BView::KeyDown(const char* bytes, int32 numBytes) 1334 { 1335 // Hook function 1336 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name())); 1337 1338 if (Window()) 1339 Window()->_KeyboardNavigation(); 1340 } 1341 1342 1343 void 1344 BView::KeyUp(const char* bytes, int32 numBytes) 1345 { 1346 // Hook function 1347 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name())); 1348 } 1349 1350 1351 void 1352 BView::MouseDown(BPoint where) 1353 { 1354 // Hook function 1355 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name())); 1356 } 1357 1358 1359 void 1360 BView::MouseUp(BPoint where) 1361 { 1362 // Hook function 1363 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name())); 1364 } 1365 1366 1367 void 1368 BView::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) 1369 { 1370 // Hook function 1371 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name())); 1372 } 1373 1374 1375 void 1376 BView::Pulse() 1377 { 1378 // Hook function 1379 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name())); 1380 } 1381 1382 1383 void 1384 BView::TargetedByScrollView(BScrollView* scroll_view) 1385 { 1386 // Hook function 1387 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name())); 1388 } 1389 1390 1391 void 1392 BView::WindowActivated(bool active) 1393 { 1394 // Hook function 1395 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name())); 1396 } 1397 1398 1399 // #pragma mark - Input Functions 1400 1401 1402 void 1403 BView::BeginRectTracking(BRect startRect, uint32 style) 1404 { 1405 if (_CheckOwnerLockAndSwitchCurrent()) { 1406 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK); 1407 fOwner->fLink->Attach<BRect>(startRect); 1408 fOwner->fLink->Attach<uint32>(style); 1409 fOwner->fLink->Flush(); 1410 } 1411 } 1412 1413 1414 void 1415 BView::EndRectTracking() 1416 { 1417 if (_CheckOwnerLockAndSwitchCurrent()) { 1418 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK); 1419 fOwner->fLink->Flush(); 1420 } 1421 } 1422 1423 1424 void 1425 BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo) 1426 { 1427 if (!message) 1428 return; 1429 1430 _CheckOwnerLock(); 1431 1432 // calculate the offset 1433 BPoint offset; 1434 uint32 buttons; 1435 BMessage* current = fOwner->CurrentMessage(); 1436 if (!current || current->FindPoint("be:view_where", &offset) != B_OK) 1437 GetMouse(&offset, &buttons, false); 1438 offset -= dragRect.LeftTop(); 1439 1440 if (!dragRect.IsValid()) { 1441 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo); 1442 return; 1443 } 1444 1445 // TODO: that's not really what should happen - the app_server should take 1446 // the chance *NOT* to need to drag a whole bitmap around but just a frame. 1447 1448 // create a drag bitmap for the rect 1449 BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32); 1450 if (bitmap == NULL) 1451 return; 1452 1453 uint32* bits = (uint32*)bitmap->Bits(); 1454 uint32 bytesPerRow = bitmap->BytesPerRow(); 1455 uint32 width = dragRect.IntegerWidth() + 1; 1456 uint32 height = dragRect.IntegerHeight() + 1; 1457 uint32 lastRow = (height - 1) * width; 1458 1459 memset(bits, 0x00, height * bytesPerRow); 1460 1461 // top 1462 for (uint32 i = 0; i < width; i += 2) 1463 bits[i] = 0xff000000; 1464 1465 // bottom 1466 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2) 1467 bits[lastRow + i] = 0xff000000; 1468 1469 // left 1470 for (uint32 i = 0; i < lastRow; i += width * 2) 1471 bits[i] = 0xff000000; 1472 1473 // right 1474 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2) 1475 bits[width - 1 + i] = 0xff000000; 1476 1477 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo); 1478 } 1479 1480 1481 void 1482 BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset, 1483 BHandler* replyTo) 1484 { 1485 DragMessage(message, image, B_OP_COPY, offset, replyTo); 1486 } 1487 1488 1489 void 1490 BView::DragMessage(BMessage* message, BBitmap* image, 1491 drawing_mode dragMode, BPoint offset, BHandler* replyTo) 1492 { 1493 if (message == NULL) 1494 return; 1495 1496 if (image == NULL) { 1497 // TODO: workaround for drags without a bitmap - should not be necessary if 1498 // we move the rectangle dragging into the app_server 1499 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32); 1500 if (image == NULL) 1501 return; 1502 } 1503 1504 if (replyTo == NULL) 1505 replyTo = this; 1506 1507 if (replyTo->Looper() == NULL) 1508 debugger("DragMessage: warning - the Handler needs a looper"); 1509 1510 _CheckOwnerLock(); 1511 1512 if (!message->HasInt32("buttons")) { 1513 BMessage* msg = fOwner->CurrentMessage(); 1514 uint32 buttons; 1515 1516 if (msg == NULL 1517 || msg->FindInt32("buttons", (int32*)&buttons) != B_OK) { 1518 BPoint point; 1519 GetMouse(&point, &buttons, false); 1520 } 1521 1522 message->AddInt32("buttons", buttons); 1523 } 1524 1525 BMessage::Private privateMessage(message); 1526 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper())); 1527 1528 int32 bufferSize = message->FlattenedSize(); 1529 char* buffer = new(std::nothrow) char[bufferSize]; 1530 if (buffer != NULL) { 1531 message->Flatten(buffer, bufferSize); 1532 1533 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE); 1534 fOwner->fLink->Attach<int32>(image->_ServerToken()); 1535 fOwner->fLink->Attach<int32>((int32)dragMode); 1536 fOwner->fLink->Attach<BPoint>(offset); 1537 fOwner->fLink->Attach<int32>(bufferSize); 1538 fOwner->fLink->Attach(buffer, bufferSize); 1539 1540 // we need to wait for the server 1541 // to actually process this message 1542 // before we can delete the bitmap 1543 int32 code; 1544 fOwner->fLink->FlushWithReply(code); 1545 1546 delete [] buffer; 1547 } else { 1548 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag " 1549 "message\n"); 1550 } 1551 1552 delete image; 1553 } 1554 1555 1556 void 1557 BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue) 1558 { 1559 if (_location == NULL && _buttons == NULL) 1560 return; 1561 1562 _CheckOwnerLockAndSwitchCurrent(); 1563 1564 uint32 eventOptions = fEventOptions | fMouseEventOptions; 1565 bool noHistory = eventOptions & B_NO_POINTER_HISTORY; 1566 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY; 1567 1568 if (checkMessageQueue && !noHistory) { 1569 Window()->UpdateIfNeeded(); 1570 BMessageQueue* queue = Window()->MessageQueue(); 1571 queue->Lock(); 1572 1573 // Look out for mouse update messages 1574 1575 BMessage* message; 1576 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) { 1577 switch (message->what) { 1578 case B_MOUSE_MOVED: 1579 case B_MOUSE_UP: 1580 case B_MOUSE_DOWN: 1581 bool deleteMessage; 1582 if (!Window()->_StealMouseMessage(message, deleteMessage)) 1583 continue; 1584 1585 if (!fullHistory && message->what == B_MOUSE_MOVED) { 1586 // Check if the message is too old. Some applications 1587 // check the message queue in such a way that mouse 1588 // messages *must* pile up. This check makes them work 1589 // as intended, although these applications could simply 1590 // use the version of BView::GetMouse() that does not 1591 // check the history. Also note that it isn't a problem 1592 // to delete the message in case there is not a newer 1593 // one. If we don't find a message in the queue, we will 1594 // just fall back to asking the app_sever directly. So 1595 // the imposed delay will not be a problem on slower 1596 // computers. This check also prevents another problem, 1597 // when the message that we use is *not* removed from 1598 // the queue. Subsequent calls to GetMouse() would find 1599 // this message over and over! 1600 bigtime_t eventTime; 1601 if (message->FindInt64("when", &eventTime) == B_OK 1602 && system_time() - eventTime > 10000) { 1603 // just discard the message 1604 if (deleteMessage) 1605 delete message; 1606 continue; 1607 } 1608 } 1609 if (_location != NULL) 1610 message->FindPoint("screen_where", _location); 1611 if (_buttons != NULL) 1612 message->FindInt32("buttons", (int32*)_buttons); 1613 queue->Unlock(); 1614 // we need to hold the queue lock until here, because 1615 // the message might still be used for something else 1616 1617 if (_location != NULL) 1618 ConvertFromScreen(_location); 1619 1620 if (deleteMessage) 1621 delete message; 1622 1623 return; 1624 } 1625 } 1626 queue->Unlock(); 1627 } 1628 1629 // If no mouse update message has been found in the message queue, 1630 // we get the current mouse location and buttons from the app_server 1631 1632 fOwner->fLink->StartMessage(AS_GET_MOUSE); 1633 1634 int32 code; 1635 if (fOwner->fLink->FlushWithReply(code) == B_OK 1636 && code == B_OK) { 1637 BPoint location; 1638 uint32 buttons; 1639 fOwner->fLink->Read<BPoint>(&location); 1640 fOwner->fLink->Read<uint32>(&buttons); 1641 // TODO: ServerWindow replies with an int32 here 1642 1643 ConvertFromScreen(&location); 1644 // TODO: in beos R5, location is already converted to the view 1645 // local coordinate system, so if an app checks the window message 1646 // queue by itself, it might not find what it expects. 1647 // NOTE: the fact that we have mouse coords in screen space in our 1648 // queue avoids the problem that messages already in the queue will 1649 // be outdated as soon as a window or even the view moves. The 1650 // second situation being quite common actually, also with regards 1651 // to scrolling. An app reading these messages would have to know 1652 // the locations of the window and view for each message... 1653 // otherwise it is potentially broken anyways. 1654 if (_location != NULL) 1655 *_location = location; 1656 if (_buttons != NULL) 1657 *_buttons = buttons; 1658 } else { 1659 if (_location != NULL) 1660 _location->Set(0, 0); 1661 if (_buttons != NULL) 1662 *_buttons = 0; 1663 } 1664 } 1665 1666 1667 void 1668 BView::MakeFocus(bool focus) 1669 { 1670 if (fOwner == NULL) 1671 return; 1672 1673 // TODO: If this view has focus and focus == false, 1674 // will there really be no other view with focus? No 1675 // cycling to the next one? 1676 BView* focusView = fOwner->CurrentFocus(); 1677 if (focus) { 1678 // Unfocus a previous focus view 1679 if (focusView != NULL && focusView != this) 1680 focusView->MakeFocus(false); 1681 1682 // if we want to make this view the current focus view 1683 fOwner->_SetFocus(this, true); 1684 } else { 1685 // we want to unfocus this view, but only if it actually has focus 1686 if (focusView == this) 1687 fOwner->_SetFocus(NULL, true); 1688 } 1689 } 1690 1691 1692 BScrollBar* 1693 BView::ScrollBar(orientation direction) const 1694 { 1695 switch (direction) { 1696 case B_VERTICAL: 1697 return fVerScroller; 1698 1699 case B_HORIZONTAL: 1700 return fHorScroller; 1701 1702 default: 1703 return NULL; 1704 } 1705 } 1706 1707 1708 void 1709 BView::ScrollBy(float deltaX, float deltaY) 1710 { 1711 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY)); 1712 } 1713 1714 1715 void 1716 BView::ScrollTo(BPoint where) 1717 { 1718 // scrolling by fractional values is not supported 1719 where.x = roundf(where.x); 1720 where.y = roundf(where.y); 1721 1722 // no reason to process this further if no scroll is intended. 1723 if (where.x == fBounds.left && where.y == fBounds.top) 1724 return; 1725 1726 // make sure scrolling is within valid bounds 1727 if (fHorScroller) { 1728 float min, max; 1729 fHorScroller->GetRange(&min, &max); 1730 1731 if (where.x < min) 1732 where.x = min; 1733 else if (where.x > max) 1734 where.x = max; 1735 } 1736 if (fVerScroller) { 1737 float min, max; 1738 fVerScroller->GetRange(&min, &max); 1739 1740 if (where.y < min) 1741 where.y = min; 1742 else if (where.y > max) 1743 where.y = max; 1744 } 1745 1746 _CheckLockAndSwitchCurrent(); 1747 1748 float xDiff = where.x - fBounds.left; 1749 float yDiff = where.y - fBounds.top; 1750 1751 // if we're attached to a window tell app_server about this change 1752 if (fOwner) { 1753 fOwner->fLink->StartMessage(AS_VIEW_SCROLL); 1754 fOwner->fLink->Attach<float>(xDiff); 1755 fOwner->fLink->Attach<float>(yDiff); 1756 1757 fOwner->fLink->Flush(); 1758 1759 // fState->valid_flags &= ~B_VIEW_FRAME_BIT; 1760 } 1761 1762 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver. 1763 fBounds.OffsetTo(where.x, where.y); 1764 1765 // then set the new values of the scrollbars 1766 if (fHorScroller && xDiff != 0.0) 1767 fHorScroller->SetValue(fBounds.left); 1768 if (fVerScroller && yDiff != 0.0) 1769 fVerScroller->SetValue(fBounds.top); 1770 1771 } 1772 1773 1774 status_t 1775 BView::SetEventMask(uint32 mask, uint32 options) 1776 { 1777 if (fEventMask == mask && fEventOptions == options) 1778 return B_OK; 1779 1780 // don't change the mask if it's zero and we've got options 1781 if (mask != 0 || options == 0) 1782 fEventMask = mask | (fEventMask & 0xffff0000); 1783 fEventOptions = options; 1784 1785 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT; 1786 1787 if (fOwner) { 1788 _CheckLockAndSwitchCurrent(); 1789 1790 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK); 1791 fOwner->fLink->Attach<uint32>(mask); 1792 fOwner->fLink->Attach<uint32>(options); 1793 fOwner->fLink->Flush(); 1794 } 1795 1796 return B_OK; 1797 } 1798 1799 1800 uint32 1801 BView::EventMask() 1802 { 1803 return fEventMask; 1804 } 1805 1806 1807 status_t 1808 BView::SetMouseEventMask(uint32 mask, uint32 options) 1809 { 1810 // Just don't do anything if the view is not yet attached 1811 // or we were called outside of BView::MouseDown() 1812 if (fOwner != NULL 1813 && fOwner->CurrentMessage() != NULL 1814 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) { 1815 _CheckLockAndSwitchCurrent(); 1816 fMouseEventOptions = options; 1817 1818 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK); 1819 fOwner->fLink->Attach<uint32>(mask); 1820 fOwner->fLink->Attach<uint32>(options); 1821 fOwner->fLink->Flush(); 1822 return B_OK; 1823 } 1824 1825 return B_ERROR; 1826 } 1827 1828 1829 // #pragma mark - Graphic State Functions 1830 1831 1832 void 1833 BView::PushState() 1834 { 1835 _CheckOwnerLockAndSwitchCurrent(); 1836 1837 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE); 1838 1839 // initialize origin, scale and transform, new states start "clean". 1840 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT 1841 | B_VIEW_TRANSFORM_BIT; 1842 fState->scale = 1.0f; 1843 fState->origin.Set(0, 0); 1844 fState->transform.Reset(); 1845 } 1846 1847 1848 void 1849 BView::PopState() 1850 { 1851 _CheckOwnerLockAndSwitchCurrent(); 1852 1853 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE); 1854 _FlushIfNotInTransaction(); 1855 1856 // invalidate all flags (except those that are not part of pop/push) 1857 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT; 1858 } 1859 1860 1861 void 1862 BView::SetOrigin(BPoint where) 1863 { 1864 SetOrigin(where.x, where.y); 1865 } 1866 1867 1868 void 1869 BView::SetOrigin(float x, float y) 1870 { 1871 if (fState->IsValid(B_VIEW_ORIGIN_BIT) 1872 && x == fState->origin.x && y == fState->origin.y) 1873 return; 1874 1875 fState->origin.x = x; 1876 fState->origin.y = y; 1877 1878 if (_CheckOwnerLockAndSwitchCurrent()) { 1879 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN); 1880 fOwner->fLink->Attach<float>(x); 1881 fOwner->fLink->Attach<float>(y); 1882 1883 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1884 } 1885 1886 // our local coord system origin has changed, so when archiving we'll add 1887 // this too 1888 fState->archiving_flags |= B_VIEW_ORIGIN_BIT; 1889 } 1890 1891 1892 BPoint 1893 BView::Origin() const 1894 { 1895 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) { 1896 // we don't keep graphics state information, therefor 1897 // we need to ask the server for the origin after PopState() 1898 _CheckOwnerLockAndSwitchCurrent(); 1899 1900 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN); 1901 1902 int32 code; 1903 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) 1904 fOwner->fLink->Read<BPoint>(&fState->origin); 1905 1906 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1907 } 1908 1909 return fState->origin; 1910 } 1911 1912 1913 void 1914 BView::SetScale(float scale) const 1915 { 1916 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale) 1917 return; 1918 1919 if (fOwner) { 1920 _CheckLockAndSwitchCurrent(); 1921 1922 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE); 1923 fOwner->fLink->Attach<float>(scale); 1924 1925 fState->valid_flags |= B_VIEW_SCALE_BIT; 1926 } 1927 1928 fState->scale = scale; 1929 fState->archiving_flags |= B_VIEW_SCALE_BIT; 1930 } 1931 1932 1933 float 1934 BView::Scale() const 1935 { 1936 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) { 1937 _CheckLockAndSwitchCurrent(); 1938 1939 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE); 1940 1941 int32 code; 1942 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) 1943 fOwner->fLink->Read<float>(&fState->scale); 1944 1945 fState->valid_flags |= B_VIEW_SCALE_BIT; 1946 } 1947 1948 return fState->scale; 1949 } 1950 1951 1952 void 1953 BView::SetTransform(BAffineTransform transform) 1954 { 1955 if (fState->IsValid(B_VIEW_TRANSFORM_BIT) && transform == fState->transform) 1956 return; 1957 1958 if (fOwner != NULL) { 1959 _CheckLockAndSwitchCurrent(); 1960 1961 fOwner->fLink->StartMessage(AS_VIEW_SET_TRANSFORM); 1962 fOwner->fLink->Attach<BAffineTransform>(transform); 1963 1964 fState->valid_flags |= B_VIEW_TRANSFORM_BIT; 1965 } 1966 1967 fState->transform = transform; 1968 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 1969 } 1970 1971 1972 BAffineTransform 1973 BView::Transform() const 1974 { 1975 if (!fState->IsValid(B_VIEW_TRANSFORM_BIT) && fOwner != NULL) { 1976 _CheckLockAndSwitchCurrent(); 1977 1978 fOwner->fLink->StartMessage(AS_VIEW_GET_TRANSFORM); 1979 1980 int32 code; 1981 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) 1982 fOwner->fLink->Read<BAffineTransform>(&fState->transform); 1983 1984 fState->valid_flags |= B_VIEW_TRANSFORM_BIT; 1985 } 1986 1987 return fState->transform; 1988 } 1989 1990 1991 void 1992 BView::TranslateBy(double x, double y) 1993 { 1994 if (fOwner != NULL) { 1995 _CheckLockAndSwitchCurrent(); 1996 1997 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_TRANSLATE); 1998 fOwner->fLink->Attach<double>(x); 1999 fOwner->fLink->Attach<double>(y); 2000 2001 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; 2002 } 2003 2004 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 2005 } 2006 2007 2008 void 2009 BView::ScaleBy(double x, double y) 2010 { 2011 if (fOwner != NULL) { 2012 _CheckLockAndSwitchCurrent(); 2013 2014 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_SCALE); 2015 fOwner->fLink->Attach<double>(x); 2016 fOwner->fLink->Attach<double>(y); 2017 2018 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; 2019 } 2020 2021 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 2022 } 2023 2024 2025 void 2026 BView::RotateBy(double angleRadians) 2027 { 2028 if (fOwner != NULL) { 2029 _CheckLockAndSwitchCurrent(); 2030 2031 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_ROTATE); 2032 fOwner->fLink->Attach<double>(angleRadians); 2033 2034 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; 2035 } 2036 2037 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 2038 } 2039 2040 2041 void 2042 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) 2043 { 2044 if (fState->IsValid(B_VIEW_LINE_MODES_BIT) 2045 && lineCap == fState->line_cap && lineJoin == fState->line_join 2046 && miterLimit == fState->miter_limit) 2047 return; 2048 2049 if (fOwner) { 2050 _CheckLockAndSwitchCurrent(); 2051 2052 ViewSetLineModeInfo info; 2053 info.lineJoin = lineJoin; 2054 info.lineCap = lineCap; 2055 info.miterLimit = miterLimit; 2056 2057 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE); 2058 fOwner->fLink->Attach<ViewSetLineModeInfo>(info); 2059 2060 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 2061 } 2062 2063 fState->line_cap = lineCap; 2064 fState->line_join = lineJoin; 2065 fState->miter_limit = miterLimit; 2066 2067 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT; 2068 } 2069 2070 2071 join_mode 2072 BView::LineJoinMode() const 2073 { 2074 // This will update the current state, if necessary 2075 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 2076 LineMiterLimit(); 2077 2078 return fState->line_join; 2079 } 2080 2081 2082 cap_mode 2083 BView::LineCapMode() const 2084 { 2085 // This will update the current state, if necessary 2086 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 2087 LineMiterLimit(); 2088 2089 return fState->line_cap; 2090 } 2091 2092 2093 float 2094 BView::LineMiterLimit() const 2095 { 2096 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) { 2097 _CheckLockAndSwitchCurrent(); 2098 2099 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE); 2100 2101 int32 code; 2102 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 2103 2104 ViewSetLineModeInfo info; 2105 fOwner->fLink->Read<ViewSetLineModeInfo>(&info); 2106 2107 fState->line_cap = info.lineCap; 2108 fState->line_join = info.lineJoin; 2109 fState->miter_limit = info.miterLimit; 2110 } 2111 2112 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 2113 } 2114 2115 return fState->miter_limit; 2116 } 2117 2118 2119 void 2120 BView::SetFillRule(int32 fillRule) 2121 { 2122 if (fState->IsValid(B_VIEW_FILL_RULE_BIT) && fillRule == fState->fill_rule) 2123 return; 2124 2125 if (fOwner) { 2126 _CheckLockAndSwitchCurrent(); 2127 2128 fOwner->fLink->StartMessage(AS_VIEW_SET_FILL_RULE); 2129 fOwner->fLink->Attach<int32>(fillRule); 2130 2131 fState->valid_flags |= B_VIEW_FILL_RULE_BIT; 2132 } 2133 2134 fState->fill_rule = fillRule; 2135 2136 fState->archiving_flags |= B_VIEW_FILL_RULE_BIT; 2137 } 2138 2139 2140 int32 2141 BView::FillRule() const 2142 { 2143 if (!fState->IsValid(B_VIEW_FILL_RULE_BIT) && fOwner) { 2144 _CheckLockAndSwitchCurrent(); 2145 2146 fOwner->fLink->StartMessage(AS_VIEW_GET_FILL_RULE); 2147 2148 int32 code; 2149 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 2150 2151 int32 fillRule; 2152 fOwner->fLink->Read<int32>(&fillRule); 2153 2154 fState->fill_rule = fillRule; 2155 } 2156 2157 fState->valid_flags |= B_VIEW_FILL_RULE_BIT; 2158 } 2159 2160 return fState->fill_rule; 2161 } 2162 2163 2164 void 2165 BView::SetDrawingMode(drawing_mode mode) 2166 { 2167 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT) 2168 && mode == fState->drawing_mode) 2169 return; 2170 2171 if (fOwner) { 2172 _CheckLockAndSwitchCurrent(); 2173 2174 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE); 2175 fOwner->fLink->Attach<int8>((int8)mode); 2176 2177 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 2178 } 2179 2180 fState->drawing_mode = mode; 2181 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT; 2182 } 2183 2184 2185 drawing_mode 2186 BView::DrawingMode() const 2187 { 2188 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) { 2189 _CheckLockAndSwitchCurrent(); 2190 2191 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE); 2192 2193 int32 code; 2194 if (fOwner->fLink->FlushWithReply(code) == B_OK 2195 && code == B_OK) { 2196 int8 drawingMode; 2197 fOwner->fLink->Read<int8>(&drawingMode); 2198 2199 fState->drawing_mode = (drawing_mode)drawingMode; 2200 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 2201 } 2202 } 2203 2204 return fState->drawing_mode; 2205 } 2206 2207 2208 void 2209 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction) 2210 { 2211 if (fState->IsValid(B_VIEW_BLENDING_BIT) 2212 && sourceAlpha == fState->alpha_source_mode 2213 && alphaFunction == fState->alpha_function_mode) 2214 return; 2215 2216 if (fOwner) { 2217 _CheckLockAndSwitchCurrent(); 2218 2219 ViewBlendingModeInfo info; 2220 info.sourceAlpha = sourceAlpha; 2221 info.alphaFunction = alphaFunction; 2222 2223 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE); 2224 fOwner->fLink->Attach<ViewBlendingModeInfo>(info); 2225 2226 fState->valid_flags |= B_VIEW_BLENDING_BIT; 2227 } 2228 2229 fState->alpha_source_mode = sourceAlpha; 2230 fState->alpha_function_mode = alphaFunction; 2231 2232 fState->archiving_flags |= B_VIEW_BLENDING_BIT; 2233 } 2234 2235 2236 void 2237 BView::GetBlendingMode(source_alpha* _sourceAlpha, 2238 alpha_function* _alphaFunction) const 2239 { 2240 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) { 2241 _CheckLockAndSwitchCurrent(); 2242 2243 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE); 2244 2245 int32 code; 2246 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 2247 ViewBlendingModeInfo info; 2248 fOwner->fLink->Read<ViewBlendingModeInfo>(&info); 2249 2250 fState->alpha_source_mode = info.sourceAlpha; 2251 fState->alpha_function_mode = info.alphaFunction; 2252 2253 fState->valid_flags |= B_VIEW_BLENDING_BIT; 2254 } 2255 } 2256 2257 if (_sourceAlpha) 2258 *_sourceAlpha = fState->alpha_source_mode; 2259 2260 if (_alphaFunction) 2261 *_alphaFunction = fState->alpha_function_mode; 2262 } 2263 2264 2265 void 2266 BView::MovePenTo(BPoint point) 2267 { 2268 MovePenTo(point.x, point.y); 2269 } 2270 2271 2272 void 2273 BView::MovePenTo(float x, float y) 2274 { 2275 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT) 2276 && x == fState->pen_location.x && y == fState->pen_location.y) 2277 return; 2278 2279 if (fOwner) { 2280 _CheckLockAndSwitchCurrent(); 2281 2282 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC); 2283 fOwner->fLink->Attach<BPoint>(BPoint(x, y)); 2284 2285 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 2286 } 2287 2288 fState->pen_location.x = x; 2289 fState->pen_location.y = y; 2290 2291 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT; 2292 } 2293 2294 2295 void 2296 BView::MovePenBy(float x, float y) 2297 { 2298 // this will update the pen location if necessary 2299 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT)) 2300 PenLocation(); 2301 2302 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y); 2303 } 2304 2305 2306 BPoint 2307 BView::PenLocation() const 2308 { 2309 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) { 2310 _CheckLockAndSwitchCurrent(); 2311 2312 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC); 2313 2314 int32 code; 2315 if (fOwner->fLink->FlushWithReply(code) == B_OK 2316 && code == B_OK) { 2317 fOwner->fLink->Read<BPoint>(&fState->pen_location); 2318 2319 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 2320 } 2321 } 2322 2323 return fState->pen_location; 2324 } 2325 2326 2327 void 2328 BView::SetPenSize(float size) 2329 { 2330 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size) 2331 return; 2332 2333 if (fOwner) { 2334 _CheckLockAndSwitchCurrent(); 2335 2336 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE); 2337 fOwner->fLink->Attach<float>(size); 2338 2339 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2340 } 2341 2342 fState->pen_size = size; 2343 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT; 2344 } 2345 2346 2347 float 2348 BView::PenSize() const 2349 { 2350 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) { 2351 _CheckLockAndSwitchCurrent(); 2352 2353 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE); 2354 2355 int32 code; 2356 if (fOwner->fLink->FlushWithReply(code) == B_OK 2357 && code == B_OK) { 2358 fOwner->fLink->Read<float>(&fState->pen_size); 2359 2360 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2361 } 2362 } 2363 2364 return fState->pen_size; 2365 } 2366 2367 2368 void 2369 BView::SetHighColor(rgb_color color) 2370 { 2371 SetHighUIColor(B_NO_COLOR); 2372 2373 // are we up-to-date already? 2374 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT) 2375 && fState->high_color == color) 2376 return; 2377 2378 if (fOwner) { 2379 _CheckLockAndSwitchCurrent(); 2380 2381 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR); 2382 fOwner->fLink->Attach<rgb_color>(color); 2383 2384 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2385 } 2386 2387 fState->high_color = color; 2388 2389 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT; 2390 } 2391 2392 2393 rgb_color 2394 BView::HighColor() const 2395 { 2396 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) { 2397 _CheckLockAndSwitchCurrent(); 2398 2399 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR); 2400 2401 int32 code; 2402 if (fOwner->fLink->FlushWithReply(code) == B_OK 2403 && code == B_OK) { 2404 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2405 2406 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2407 } 2408 } 2409 2410 return fState->high_color; 2411 } 2412 2413 2414 void 2415 BView::SetHighUIColor(color_which which, float tint) 2416 { 2417 if (fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT) 2418 && fState->which_high_color == which 2419 && fState->which_high_color_tint == tint) 2420 return; 2421 2422 if (fOwner != NULL) { 2423 _CheckLockAndSwitchCurrent(); 2424 2425 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_UI_COLOR); 2426 fOwner->fLink->Attach<color_which>(which); 2427 fOwner->fLink->Attach<float>(tint); 2428 2429 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT; 2430 } 2431 2432 fState->which_high_color = which; 2433 fState->which_high_color_tint = tint; 2434 2435 if (which != B_NO_COLOR) { 2436 fState->archiving_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT; 2437 fState->archiving_flags &= ~B_VIEW_HIGH_COLOR_BIT; 2438 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2439 2440 fState->high_color = tint_color(ui_color(which), tint); 2441 } else { 2442 fState->valid_flags &= ~B_VIEW_HIGH_COLOR_BIT; 2443 fState->archiving_flags &= ~B_VIEW_WHICH_HIGH_COLOR_BIT; 2444 } 2445 } 2446 2447 2448 color_which 2449 BView::HighUIColor(float* tint) const 2450 { 2451 if (!fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT) 2452 && fOwner != NULL) { 2453 _CheckLockAndSwitchCurrent(); 2454 2455 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_UI_COLOR); 2456 2457 int32 code; 2458 if (fOwner->fLink->FlushWithReply(code) == B_OK 2459 && code == B_OK) { 2460 fOwner->fLink->Read<color_which>(&fState->which_high_color); 2461 fOwner->fLink->Read<float>(&fState->which_high_color_tint); 2462 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2463 2464 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT; 2465 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2466 } 2467 } 2468 2469 if (tint != NULL) 2470 *tint = fState->which_high_color_tint; 2471 2472 return fState->which_high_color; 2473 } 2474 2475 2476 void 2477 BView::SetLowColor(rgb_color color) 2478 { 2479 SetLowUIColor(B_NO_COLOR); 2480 2481 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT) 2482 && fState->low_color == color) 2483 return; 2484 2485 if (fOwner) { 2486 _CheckLockAndSwitchCurrent(); 2487 2488 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR); 2489 fOwner->fLink->Attach<rgb_color>(color); 2490 2491 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2492 } 2493 2494 fState->low_color = color; 2495 2496 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT; 2497 } 2498 2499 2500 rgb_color 2501 BView::LowColor() const 2502 { 2503 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) { 2504 _CheckLockAndSwitchCurrent(); 2505 2506 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR); 2507 2508 int32 code; 2509 if (fOwner->fLink->FlushWithReply(code) == B_OK 2510 && code == B_OK) { 2511 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2512 2513 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2514 } 2515 } 2516 2517 return fState->low_color; 2518 } 2519 2520 2521 void 2522 BView::SetLowUIColor(color_which which, float tint) 2523 { 2524 if (fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT) 2525 && fState->which_low_color == which 2526 && fState->which_low_color_tint == tint) 2527 return; 2528 2529 if (fOwner != NULL) { 2530 _CheckLockAndSwitchCurrent(); 2531 2532 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_UI_COLOR); 2533 fOwner->fLink->Attach<color_which>(which); 2534 fOwner->fLink->Attach<float>(tint); 2535 2536 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT; 2537 } 2538 2539 fState->which_low_color = which; 2540 fState->which_low_color_tint = tint; 2541 2542 if (which != B_NO_COLOR) { 2543 fState->archiving_flags |= B_VIEW_WHICH_LOW_COLOR_BIT; 2544 fState->archiving_flags &= ~B_VIEW_LOW_COLOR_BIT; 2545 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2546 2547 fState->low_color = tint_color(ui_color(which), tint); 2548 } else { 2549 fState->valid_flags &= ~B_VIEW_LOW_COLOR_BIT; 2550 fState->archiving_flags &= ~B_VIEW_WHICH_LOW_COLOR_BIT; 2551 } 2552 } 2553 2554 2555 color_which 2556 BView::LowUIColor(float* tint) const 2557 { 2558 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT) 2559 && fOwner != NULL) { 2560 _CheckLockAndSwitchCurrent(); 2561 2562 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_UI_COLOR); 2563 2564 int32 code; 2565 if (fOwner->fLink->FlushWithReply(code) == B_OK 2566 && code == B_OK) { 2567 fOwner->fLink->Read<color_which>(&fState->which_low_color); 2568 fOwner->fLink->Read<float>(&fState->which_low_color_tint); 2569 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2570 2571 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT; 2572 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2573 } 2574 } 2575 2576 if (tint != NULL) 2577 *tint = fState->which_low_color_tint; 2578 2579 return fState->which_low_color; 2580 } 2581 2582 2583 bool 2584 BView::HasDefaultColors() const 2585 { 2586 // If we don't have any of these flags, then we have default colors 2587 uint32 testMask = B_VIEW_VIEW_COLOR_BIT | B_VIEW_HIGH_COLOR_BIT 2588 | B_VIEW_LOW_COLOR_BIT | B_VIEW_WHICH_VIEW_COLOR_BIT 2589 | B_VIEW_WHICH_HIGH_COLOR_BIT | B_VIEW_WHICH_LOW_COLOR_BIT; 2590 2591 return (fState->archiving_flags & testMask) == 0; 2592 } 2593 2594 2595 bool 2596 BView::HasSystemColors() const 2597 { 2598 return fState->which_view_color == B_PANEL_BACKGROUND_COLOR 2599 && fState->which_high_color == B_PANEL_TEXT_COLOR 2600 && fState->which_low_color == B_PANEL_BACKGROUND_COLOR 2601 && fState->which_view_color_tint == B_NO_TINT 2602 && fState->which_high_color_tint == B_NO_TINT 2603 && fState->which_low_color_tint == B_NO_TINT; 2604 } 2605 2606 2607 void 2608 BView::AdoptParentColors() 2609 { 2610 AdoptViewColors(Parent()); 2611 } 2612 2613 2614 void 2615 BView::AdoptSystemColors() 2616 { 2617 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 2618 SetLowUIColor(B_PANEL_BACKGROUND_COLOR); 2619 SetHighUIColor(B_PANEL_TEXT_COLOR); 2620 } 2621 2622 2623 void 2624 BView::AdoptViewColors(BView* view) 2625 { 2626 if (view == NULL || (view->Window() != NULL && !view->LockLooper())) 2627 return; 2628 2629 float tint = B_NO_TINT; 2630 float viewTint = tint; 2631 color_which viewWhich = view->ViewUIColor(&viewTint); 2632 2633 // View color 2634 if (viewWhich != B_NO_COLOR) 2635 SetViewUIColor(viewWhich, viewTint); 2636 else 2637 SetViewColor(view->ViewColor()); 2638 2639 // Low color 2640 color_which which = view->LowUIColor(&tint); 2641 if (which != B_NO_COLOR) 2642 SetLowUIColor(which, tint); 2643 else if (viewWhich != B_NO_COLOR) 2644 SetLowUIColor(viewWhich, viewTint); 2645 else 2646 SetLowColor(view->LowColor()); 2647 2648 // High color 2649 which = view->HighUIColor(&tint); 2650 if (which != B_NO_COLOR) 2651 SetHighUIColor(which, tint); 2652 else 2653 SetHighColor(view->HighColor()); 2654 2655 if (view->Window() != NULL) 2656 view->UnlockLooper(); 2657 } 2658 2659 2660 void 2661 BView::SetViewColor(rgb_color color) 2662 { 2663 SetViewUIColor(B_NO_COLOR); 2664 2665 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) 2666 && fState->view_color == color) 2667 return; 2668 2669 if (fOwner) { 2670 _CheckLockAndSwitchCurrent(); 2671 2672 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR); 2673 fOwner->fLink->Attach<rgb_color>(color); 2674 fOwner->fLink->Flush(); 2675 2676 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2677 } 2678 2679 fState->view_color = color; 2680 2681 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT; 2682 } 2683 2684 2685 rgb_color 2686 BView::ViewColor() const 2687 { 2688 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) { 2689 _CheckLockAndSwitchCurrent(); 2690 2691 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR); 2692 2693 int32 code; 2694 if (fOwner->fLink->FlushWithReply(code) == B_OK 2695 && code == B_OK) { 2696 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2697 2698 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2699 } 2700 } 2701 2702 return fState->view_color; 2703 } 2704 2705 2706 void 2707 BView::SetViewUIColor(color_which which, float tint) 2708 { 2709 if (fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT) 2710 && fState->which_view_color == which 2711 && fState->which_view_color_tint == tint) 2712 return; 2713 2714 if (fOwner != NULL) { 2715 _CheckLockAndSwitchCurrent(); 2716 2717 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_UI_COLOR); 2718 fOwner->fLink->Attach<color_which>(which); 2719 fOwner->fLink->Attach<float>(tint); 2720 2721 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT; 2722 } 2723 2724 fState->which_view_color = which; 2725 fState->which_view_color_tint = tint; 2726 2727 if (which != B_NO_COLOR) { 2728 fState->archiving_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT; 2729 fState->archiving_flags &= ~B_VIEW_VIEW_COLOR_BIT; 2730 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2731 2732 fState->view_color = tint_color(ui_color(which), tint); 2733 } else { 2734 fState->valid_flags &= ~B_VIEW_VIEW_COLOR_BIT; 2735 fState->archiving_flags &= ~B_VIEW_WHICH_VIEW_COLOR_BIT; 2736 } 2737 2738 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT)) 2739 SetLowUIColor(which, tint); 2740 } 2741 2742 2743 color_which 2744 BView::ViewUIColor(float* tint) const 2745 { 2746 if (!fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT) 2747 && fOwner != NULL) { 2748 _CheckLockAndSwitchCurrent(); 2749 2750 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_UI_COLOR); 2751 2752 int32 code; 2753 if (fOwner->fLink->FlushWithReply(code) == B_OK 2754 && code == B_OK) { 2755 fOwner->fLink->Read<color_which>(&fState->which_view_color); 2756 fOwner->fLink->Read<float>(&fState->which_view_color_tint); 2757 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2758 2759 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT; 2760 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2761 } 2762 } 2763 2764 if (tint != NULL) 2765 *tint = fState->which_view_color_tint; 2766 2767 return fState->which_view_color; 2768 } 2769 2770 2771 void 2772 BView::ForceFontAliasing(bool enable) 2773 { 2774 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) 2775 && enable == fState->font_aliasing) 2776 return; 2777 2778 if (fOwner) { 2779 _CheckLockAndSwitchCurrent(); 2780 2781 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING); 2782 fOwner->fLink->Attach<bool>(enable); 2783 2784 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT; 2785 } 2786 2787 fState->font_aliasing = enable; 2788 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT; 2789 } 2790 2791 2792 void 2793 BView::SetFont(const BFont* font, uint32 mask) 2794 { 2795 if (!font || mask == 0) 2796 return; 2797 2798 if (mask == B_FONT_ALL) { 2799 fState->font = *font; 2800 } else { 2801 // TODO: move this into a BFont method 2802 if (mask & B_FONT_FAMILY_AND_STYLE) 2803 fState->font.SetFamilyAndStyle(font->FamilyAndStyle()); 2804 2805 if (mask & B_FONT_SIZE) 2806 fState->font.SetSize(font->Size()); 2807 2808 if (mask & B_FONT_SHEAR) 2809 fState->font.SetShear(font->Shear()); 2810 2811 if (mask & B_FONT_ROTATION) 2812 fState->font.SetRotation(font->Rotation()); 2813 2814 if (mask & B_FONT_FALSE_BOLD_WIDTH) 2815 fState->font.SetFalseBoldWidth(font->FalseBoldWidth()); 2816 2817 if (mask & B_FONT_SPACING) 2818 fState->font.SetSpacing(font->Spacing()); 2819 2820 if (mask & B_FONT_ENCODING) 2821 fState->font.SetEncoding(font->Encoding()); 2822 2823 if (mask & B_FONT_FACE) 2824 fState->font.SetFace(font->Face()); 2825 2826 if (mask & B_FONT_FLAGS) 2827 fState->font.SetFlags(font->Flags()); 2828 } 2829 2830 fState->font_flags |= mask; 2831 2832 if (fOwner) { 2833 _CheckLockAndSwitchCurrent(); 2834 2835 fState->UpdateServerFontState(*fOwner->fLink); 2836 fState->valid_flags |= B_VIEW_FONT_BIT; 2837 } 2838 2839 fState->archiving_flags |= B_VIEW_FONT_BIT; 2840 // TODO: InvalidateLayout() here for convenience? 2841 } 2842 2843 2844 void 2845 BView::GetFont(BFont* font) const 2846 { 2847 if (!fState->IsValid(B_VIEW_FONT_BIT)) { 2848 // we don't keep graphics state information, therefor 2849 // we need to ask the server for the origin after PopState() 2850 _CheckOwnerLockAndSwitchCurrent(); 2851 2852 // TODO: add a font getter! 2853 fState->UpdateFrom(*fOwner->fLink); 2854 } 2855 2856 *font = fState->font; 2857 } 2858 2859 2860 void 2861 BView::GetFontHeight(font_height* height) const 2862 { 2863 fState->font.GetHeight(height); 2864 } 2865 2866 2867 void 2868 BView::SetFontSize(float size) 2869 { 2870 BFont font; 2871 font.SetSize(size); 2872 2873 SetFont(&font, B_FONT_SIZE); 2874 } 2875 2876 2877 float 2878 BView::StringWidth(const char* string) const 2879 { 2880 return fState->font.StringWidth(string); 2881 } 2882 2883 2884 float 2885 BView::StringWidth(const char* string, int32 length) const 2886 { 2887 return fState->font.StringWidth(string, length); 2888 } 2889 2890 2891 void 2892 BView::GetStringWidths(char* stringArray[], int32 lengthArray[], 2893 int32 numStrings, float widthArray[]) const 2894 { 2895 fState->font.GetStringWidths(const_cast<const char**>(stringArray), 2896 const_cast<const int32*>(lengthArray), numStrings, widthArray); 2897 } 2898 2899 2900 void 2901 BView::TruncateString(BString* string, uint32 mode, float width) const 2902 { 2903 fState->font.TruncateString(string, mode, width); 2904 } 2905 2906 2907 void 2908 BView::ClipToPicture(BPicture* picture, BPoint where, bool sync) 2909 { 2910 _ClipToPicture(picture, where, false, sync); 2911 } 2912 2913 2914 void 2915 BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync) 2916 { 2917 _ClipToPicture(picture, where, true, sync); 2918 } 2919 2920 2921 void 2922 BView::GetClippingRegion(BRegion* region) const 2923 { 2924 if (!region) 2925 return; 2926 2927 // NOTE: the client has no idea when the clipping in the server 2928 // changed, so it is always read from the server 2929 region->MakeEmpty(); 2930 2931 2932 if (fOwner) { 2933 if (fIsPrinting && _CheckOwnerLock()) { 2934 region->Set(fState->print_rect); 2935 return; 2936 } 2937 2938 _CheckLockAndSwitchCurrent(); 2939 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION); 2940 2941 int32 code; 2942 if (fOwner->fLink->FlushWithReply(code) == B_OK 2943 && code == B_OK) { 2944 fOwner->fLink->ReadRegion(region); 2945 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT; 2946 } 2947 } 2948 } 2949 2950 2951 void 2952 BView::ConstrainClippingRegion(BRegion* region) 2953 { 2954 if (_CheckOwnerLockAndSwitchCurrent()) { 2955 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION); 2956 2957 if (region) { 2958 int32 count = region->CountRects(); 2959 fOwner->fLink->Attach<int32>(count); 2960 if (count > 0) 2961 fOwner->fLink->AttachRegion(*region); 2962 } else { 2963 fOwner->fLink->Attach<int32>(-1); 2964 // '-1' means that in the app_server, there won't be any 'local' 2965 // clipping region (it will be NULL) 2966 } 2967 2968 _FlushIfNotInTransaction(); 2969 2970 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 2971 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 2972 } 2973 } 2974 2975 2976 void 2977 BView::ClipToRect(BRect rect) 2978 { 2979 _ClipToRect(rect, false); 2980 } 2981 2982 2983 void 2984 BView::ClipToInverseRect(BRect rect) 2985 { 2986 _ClipToRect(rect, true); 2987 } 2988 2989 2990 void 2991 BView::ClipToShape(BShape* shape) 2992 { 2993 _ClipToShape(shape, false); 2994 } 2995 2996 2997 void 2998 BView::ClipToInverseShape(BShape* shape) 2999 { 3000 _ClipToShape(shape, true); 3001 } 3002 3003 3004 // #pragma mark - Drawing Functions 3005 3006 3007 void 3008 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 3009 uint32 options) 3010 { 3011 if (bitmap == NULL || fOwner == NULL 3012 || !bitmapRect.IsValid() || !viewRect.IsValid()) 3013 return; 3014 3015 _CheckLockAndSwitchCurrent(); 3016 3017 ViewDrawBitmapInfo info; 3018 info.bitmapToken = bitmap->_ServerToken(); 3019 info.options = options; 3020 info.viewRect = viewRect; 3021 info.bitmapRect = bitmapRect; 3022 3023 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 3024 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 3025 3026 _FlushIfNotInTransaction(); 3027 } 3028 3029 3030 void 3031 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 3032 { 3033 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 3034 } 3035 3036 3037 void 3038 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect) 3039 { 3040 if (bitmap && fOwner) { 3041 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), 3042 viewRect, 0); 3043 } 3044 } 3045 3046 3047 void 3048 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where) 3049 { 3050 if (bitmap == NULL || fOwner == NULL) 3051 return; 3052 3053 _CheckLockAndSwitchCurrent(); 3054 3055 ViewDrawBitmapInfo info; 3056 info.bitmapToken = bitmap->_ServerToken(); 3057 info.options = 0; 3058 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN); 3059 info.viewRect = info.bitmapRect.OffsetToCopy(where); 3060 3061 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 3062 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 3063 3064 _FlushIfNotInTransaction(); 3065 } 3066 3067 3068 void 3069 BView::DrawBitmapAsync(const BBitmap* bitmap) 3070 { 3071 DrawBitmapAsync(bitmap, PenLocation()); 3072 } 3073 3074 3075 void 3076 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 3077 uint32 options) 3078 { 3079 if (fOwner) { 3080 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options); 3081 Sync(); 3082 } 3083 } 3084 3085 3086 void 3087 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 3088 { 3089 if (fOwner) { 3090 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 3091 Sync(); 3092 } 3093 } 3094 3095 3096 void 3097 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect) 3098 { 3099 if (bitmap && fOwner) { 3100 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect, 3101 0); 3102 } 3103 } 3104 3105 3106 void 3107 BView::DrawBitmap(const BBitmap* bitmap, BPoint where) 3108 { 3109 if (fOwner) { 3110 DrawBitmapAsync(bitmap, where); 3111 Sync(); 3112 } 3113 } 3114 3115 3116 void 3117 BView::DrawBitmap(const BBitmap* bitmap) 3118 { 3119 DrawBitmap(bitmap, PenLocation()); 3120 } 3121 3122 3123 void 3124 BView::DrawChar(char c) 3125 { 3126 DrawString(&c, 1, PenLocation()); 3127 } 3128 3129 3130 void 3131 BView::DrawChar(char c, BPoint location) 3132 { 3133 DrawString(&c, 1, location); 3134 } 3135 3136 3137 void 3138 BView::DrawString(const char* string, escapement_delta* delta) 3139 { 3140 if (string == NULL) 3141 return; 3142 3143 DrawString(string, strlen(string), PenLocation(), delta); 3144 } 3145 3146 3147 void 3148 BView::DrawString(const char* string, BPoint location, escapement_delta* delta) 3149 { 3150 if (string == NULL) 3151 return; 3152 3153 DrawString(string, strlen(string), location, delta); 3154 } 3155 3156 3157 void 3158 BView::DrawString(const char* string, int32 length, escapement_delta* delta) 3159 { 3160 DrawString(string, length, PenLocation(), delta); 3161 } 3162 3163 3164 void 3165 BView::DrawString(const char* string, int32 length, BPoint location, 3166 escapement_delta* delta) 3167 { 3168 if (fOwner == NULL || string == NULL || length < 1) 3169 return; 3170 3171 _CheckLockAndSwitchCurrent(); 3172 3173 ViewDrawStringInfo info; 3174 info.stringLength = length; 3175 info.location = location; 3176 if (delta != NULL) 3177 info.delta = *delta; 3178 3179 // quite often delta will be NULL 3180 if (delta) 3181 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA); 3182 else 3183 fOwner->fLink->StartMessage(AS_DRAW_STRING); 3184 3185 fOwner->fLink->Attach<ViewDrawStringInfo>(info); 3186 fOwner->fLink->Attach(string, length); 3187 3188 _FlushIfNotInTransaction(); 3189 3190 // this modifies our pen location, so we invalidate the flag. 3191 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3192 } 3193 3194 3195 void 3196 BView::DrawString(const char* string, const BPoint* locations, 3197 int32 locationCount) 3198 { 3199 if (string == NULL) 3200 return; 3201 3202 DrawString(string, strlen(string), locations, locationCount); 3203 } 3204 3205 3206 void 3207 BView::DrawString(const char* string, int32 length, const BPoint* locations, 3208 int32 locationCount) 3209 { 3210 if (fOwner == NULL || string == NULL || length < 1 || locations == NULL) 3211 return; 3212 3213 _CheckLockAndSwitchCurrent(); 3214 3215 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS); 3216 3217 fOwner->fLink->Attach<int32>(length); 3218 fOwner->fLink->Attach<int32>(locationCount); 3219 fOwner->fLink->Attach(string, length); 3220 fOwner->fLink->Attach(locations, locationCount * sizeof(BPoint)); 3221 3222 _FlushIfNotInTransaction(); 3223 3224 // this modifies our pen location, so we invalidate the flag. 3225 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3226 } 3227 3228 3229 void 3230 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, 3231 ::pattern pattern) 3232 { 3233 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, 3234 center.x + xRadius, center.y + yRadius), pattern); 3235 } 3236 3237 3238 void 3239 BView::StrokeEllipse(BRect rect, ::pattern pattern) 3240 { 3241 if (fOwner == NULL) 3242 return; 3243 3244 _CheckLockAndSwitchCurrent(); 3245 _UpdatePattern(pattern); 3246 3247 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE); 3248 fOwner->fLink->Attach<BRect>(rect); 3249 3250 _FlushIfNotInTransaction(); 3251 } 3252 3253 3254 void 3255 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 3256 ::pattern pattern) 3257 { 3258 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 3259 center.x + xRadius, center.y + yRadius), pattern); 3260 } 3261 3262 3263 void 3264 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 3265 const BGradient& gradient) 3266 { 3267 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 3268 center.x + xRadius, center.y + yRadius), gradient); 3269 } 3270 3271 3272 void 3273 BView::FillEllipse(BRect rect, ::pattern pattern) 3274 { 3275 if (fOwner == NULL) 3276 return; 3277 3278 _CheckLockAndSwitchCurrent(); 3279 _UpdatePattern(pattern); 3280 3281 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE); 3282 fOwner->fLink->Attach<BRect>(rect); 3283 3284 _FlushIfNotInTransaction(); 3285 } 3286 3287 3288 void 3289 BView::FillEllipse(BRect rect, const BGradient& gradient) 3290 { 3291 if (fOwner == NULL) 3292 return; 3293 3294 _CheckLockAndSwitchCurrent(); 3295 3296 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT); 3297 fOwner->fLink->Attach<BRect>(rect); 3298 fOwner->fLink->AttachGradient(gradient); 3299 3300 _FlushIfNotInTransaction(); 3301 } 3302 3303 3304 void 3305 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle, 3306 float arcAngle, ::pattern pattern) 3307 { 3308 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 3309 center.y + yRadius), startAngle, arcAngle, pattern); 3310 } 3311 3312 3313 void 3314 BView::StrokeArc(BRect rect, float startAngle, float arcAngle, 3315 ::pattern pattern) 3316 { 3317 if (fOwner == NULL) 3318 return; 3319 3320 _CheckLockAndSwitchCurrent(); 3321 _UpdatePattern(pattern); 3322 3323 fOwner->fLink->StartMessage(AS_STROKE_ARC); 3324 fOwner->fLink->Attach<BRect>(rect); 3325 fOwner->fLink->Attach<float>(startAngle); 3326 fOwner->fLink->Attach<float>(arcAngle); 3327 3328 _FlushIfNotInTransaction(); 3329 } 3330 3331 3332 void 3333 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 3334 float arcAngle, ::pattern pattern) 3335 { 3336 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 3337 center.y + yRadius), startAngle, arcAngle, pattern); 3338 } 3339 3340 3341 void 3342 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 3343 float arcAngle, const BGradient& gradient) 3344 { 3345 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 3346 center.y + yRadius), startAngle, arcAngle, gradient); 3347 } 3348 3349 3350 void 3351 BView::FillArc(BRect rect, float startAngle, float arcAngle, 3352 ::pattern pattern) 3353 { 3354 if (fOwner == NULL) 3355 return; 3356 3357 _CheckLockAndSwitchCurrent(); 3358 _UpdatePattern(pattern); 3359 3360 fOwner->fLink->StartMessage(AS_FILL_ARC); 3361 fOwner->fLink->Attach<BRect>(rect); 3362 fOwner->fLink->Attach<float>(startAngle); 3363 fOwner->fLink->Attach<float>(arcAngle); 3364 3365 _FlushIfNotInTransaction(); 3366 } 3367 3368 3369 void 3370 BView::FillArc(BRect rect, float startAngle, float arcAngle, 3371 const BGradient& gradient) 3372 { 3373 if (fOwner == NULL) 3374 return; 3375 3376 _CheckLockAndSwitchCurrent(); 3377 3378 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT); 3379 fOwner->fLink->Attach<BRect>(rect); 3380 fOwner->fLink->Attach<float>(startAngle); 3381 fOwner->fLink->Attach<float>(arcAngle); 3382 fOwner->fLink->AttachGradient(gradient); 3383 3384 _FlushIfNotInTransaction(); 3385 } 3386 3387 3388 void 3389 BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern) 3390 { 3391 if (fOwner == NULL) 3392 return; 3393 3394 _CheckLockAndSwitchCurrent(); 3395 _UpdatePattern(pattern); 3396 3397 fOwner->fLink->StartMessage(AS_STROKE_BEZIER); 3398 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 3399 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 3400 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 3401 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 3402 3403 _FlushIfNotInTransaction(); 3404 } 3405 3406 3407 void 3408 BView::FillBezier(BPoint* controlPoints, ::pattern pattern) 3409 { 3410 if (fOwner == NULL) 3411 return; 3412 3413 _CheckLockAndSwitchCurrent(); 3414 _UpdatePattern(pattern); 3415 3416 fOwner->fLink->StartMessage(AS_FILL_BEZIER); 3417 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 3418 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 3419 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 3420 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 3421 3422 _FlushIfNotInTransaction(); 3423 } 3424 3425 3426 void 3427 BView::FillBezier(BPoint* controlPoints, const BGradient& gradient) 3428 { 3429 if (fOwner == NULL) 3430 return; 3431 3432 _CheckLockAndSwitchCurrent(); 3433 3434 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT); 3435 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 3436 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 3437 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 3438 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 3439 fOwner->fLink->AttachGradient(gradient); 3440 3441 _FlushIfNotInTransaction(); 3442 } 3443 3444 3445 void 3446 BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern) 3447 { 3448 if (polygon == NULL) 3449 return; 3450 3451 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, 3452 pattern); 3453 } 3454 3455 3456 void 3457 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed, 3458 ::pattern pattern) 3459 { 3460 BPolygon polygon(pointArray, numPoints); 3461 3462 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, 3463 pattern); 3464 } 3465 3466 3467 void 3468 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3469 bool closed, ::pattern pattern) 3470 { 3471 if (pointArray == NULL 3472 || numPoints <= 1 3473 || fOwner == NULL) 3474 return; 3475 3476 _CheckLockAndSwitchCurrent(); 3477 _UpdatePattern(pattern); 3478 3479 BPolygon polygon(pointArray, numPoints); 3480 polygon.MapTo(polygon.Frame(), bounds); 3481 3482 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON, 3483 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) 3484 + sizeof(int32)) == B_OK) { 3485 fOwner->fLink->Attach<BRect>(polygon.Frame()); 3486 fOwner->fLink->Attach<bool>(closed); 3487 fOwner->fLink->Attach<int32>(polygon.fCount); 3488 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint)); 3489 3490 _FlushIfNotInTransaction(); 3491 } else { 3492 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 3493 } 3494 } 3495 3496 3497 void 3498 BView::FillPolygon(const BPolygon* polygon, ::pattern pattern) 3499 { 3500 if (polygon == NULL 3501 || polygon->fCount <= 2 3502 || fOwner == NULL) 3503 return; 3504 3505 _CheckLockAndSwitchCurrent(); 3506 _UpdatePattern(pattern); 3507 3508 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON, 3509 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 3510 == B_OK) { 3511 fOwner->fLink->Attach<BRect>(polygon->Frame()); 3512 fOwner->fLink->Attach<int32>(polygon->fCount); 3513 fOwner->fLink->Attach(polygon->fPoints, 3514 polygon->fCount * sizeof(BPoint)); 3515 3516 _FlushIfNotInTransaction(); 3517 } else { 3518 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 3519 } 3520 } 3521 3522 3523 void 3524 BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient) 3525 { 3526 if (polygon == NULL 3527 || polygon->fCount <= 2 3528 || fOwner == NULL) 3529 return; 3530 3531 _CheckLockAndSwitchCurrent(); 3532 3533 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT, 3534 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 3535 == B_OK) { 3536 fOwner->fLink->Attach<BRect>(polygon->Frame()); 3537 fOwner->fLink->Attach<int32>(polygon->fCount); 3538 fOwner->fLink->Attach(polygon->fPoints, 3539 polygon->fCount * sizeof(BPoint)); 3540 fOwner->fLink->AttachGradient(gradient); 3541 3542 _FlushIfNotInTransaction(); 3543 } else { 3544 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 3545 } 3546 } 3547 3548 3549 void 3550 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, ::pattern pattern) 3551 { 3552 if (pointArray == NULL) 3553 return; 3554 3555 BPolygon polygon(pointArray, numPoints); 3556 FillPolygon(&polygon, pattern); 3557 } 3558 3559 3560 void 3561 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, 3562 const BGradient& gradient) 3563 { 3564 if (pointArray == NULL) 3565 return; 3566 3567 BPolygon polygon(pointArray, numPoints); 3568 FillPolygon(&polygon, gradient); 3569 } 3570 3571 3572 void 3573 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3574 ::pattern pattern) 3575 { 3576 if (pointArray == NULL) 3577 return; 3578 3579 BPolygon polygon(pointArray, numPoints); 3580 3581 polygon.MapTo(polygon.Frame(), bounds); 3582 FillPolygon(&polygon, pattern); 3583 } 3584 3585 3586 void 3587 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3588 const BGradient& gradient) 3589 { 3590 if (pointArray == NULL) 3591 return; 3592 3593 BPolygon polygon(pointArray, numPoints); 3594 3595 polygon.MapTo(polygon.Frame(), bounds); 3596 FillPolygon(&polygon, gradient); 3597 } 3598 3599 3600 void 3601 BView::StrokeRect(BRect rect, ::pattern pattern) 3602 { 3603 if (fOwner == NULL) 3604 return; 3605 3606 _CheckLockAndSwitchCurrent(); 3607 _UpdatePattern(pattern); 3608 3609 fOwner->fLink->StartMessage(AS_STROKE_RECT); 3610 fOwner->fLink->Attach<BRect>(rect); 3611 3612 _FlushIfNotInTransaction(); 3613 } 3614 3615 3616 void 3617 BView::FillRect(BRect rect, ::pattern pattern) 3618 { 3619 if (fOwner == NULL) 3620 return; 3621 3622 // NOTE: ensuring compatibility with R5, 3623 // invalid rects are not filled, they are stroked though! 3624 if (!rect.IsValid()) 3625 return; 3626 3627 _CheckLockAndSwitchCurrent(); 3628 _UpdatePattern(pattern); 3629 3630 fOwner->fLink->StartMessage(AS_FILL_RECT); 3631 fOwner->fLink->Attach<BRect>(rect); 3632 3633 _FlushIfNotInTransaction(); 3634 } 3635 3636 3637 void 3638 BView::FillRect(BRect rect, const BGradient& gradient) 3639 { 3640 if (fOwner == NULL) 3641 return; 3642 3643 // NOTE: ensuring compatibility with R5, 3644 // invalid rects are not filled, they are stroked though! 3645 if (!rect.IsValid()) 3646 return; 3647 3648 _CheckLockAndSwitchCurrent(); 3649 3650 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT); 3651 fOwner->fLink->Attach<BRect>(rect); 3652 fOwner->fLink->AttachGradient(gradient); 3653 3654 _FlushIfNotInTransaction(); 3655 } 3656 3657 3658 void 3659 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius, 3660 ::pattern pattern) 3661 { 3662 if (fOwner == NULL) 3663 return; 3664 3665 _CheckLockAndSwitchCurrent(); 3666 _UpdatePattern(pattern); 3667 3668 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT); 3669 fOwner->fLink->Attach<BRect>(rect); 3670 fOwner->fLink->Attach<float>(xRadius); 3671 fOwner->fLink->Attach<float>(yRadius); 3672 3673 _FlushIfNotInTransaction(); 3674 } 3675 3676 3677 void 3678 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3679 ::pattern pattern) 3680 { 3681 if (fOwner == NULL) 3682 return; 3683 3684 _CheckLockAndSwitchCurrent(); 3685 3686 _UpdatePattern(pattern); 3687 3688 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT); 3689 fOwner->fLink->Attach<BRect>(rect); 3690 fOwner->fLink->Attach<float>(xRadius); 3691 fOwner->fLink->Attach<float>(yRadius); 3692 3693 _FlushIfNotInTransaction(); 3694 } 3695 3696 3697 void 3698 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3699 const BGradient& gradient) 3700 { 3701 if (fOwner == NULL) 3702 return; 3703 3704 _CheckLockAndSwitchCurrent(); 3705 3706 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT); 3707 fOwner->fLink->Attach<BRect>(rect); 3708 fOwner->fLink->Attach<float>(xRadius); 3709 fOwner->fLink->Attach<float>(yRadius); 3710 fOwner->fLink->AttachGradient(gradient); 3711 3712 _FlushIfNotInTransaction(); 3713 } 3714 3715 3716 void 3717 BView::FillRegion(BRegion* region, ::pattern pattern) 3718 { 3719 if (region == NULL || fOwner == NULL) 3720 return; 3721 3722 _CheckLockAndSwitchCurrent(); 3723 3724 _UpdatePattern(pattern); 3725 3726 fOwner->fLink->StartMessage(AS_FILL_REGION); 3727 fOwner->fLink->AttachRegion(*region); 3728 3729 _FlushIfNotInTransaction(); 3730 } 3731 3732 3733 void 3734 BView::FillRegion(BRegion* region, const BGradient& gradient) 3735 { 3736 if (region == NULL || fOwner == NULL) 3737 return; 3738 3739 _CheckLockAndSwitchCurrent(); 3740 3741 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT); 3742 fOwner->fLink->AttachRegion(*region); 3743 fOwner->fLink->AttachGradient(gradient); 3744 3745 _FlushIfNotInTransaction(); 3746 } 3747 3748 3749 void 3750 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds, 3751 ::pattern pattern) 3752 { 3753 if (fOwner == NULL) 3754 return; 3755 3756 _CheckLockAndSwitchCurrent(); 3757 3758 _UpdatePattern(pattern); 3759 3760 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE); 3761 fOwner->fLink->Attach<BPoint>(point1); 3762 fOwner->fLink->Attach<BPoint>(point2); 3763 fOwner->fLink->Attach<BPoint>(point3); 3764 fOwner->fLink->Attach<BRect>(bounds); 3765 3766 _FlushIfNotInTransaction(); 3767 } 3768 3769 3770 void 3771 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, 3772 ::pattern pattern) 3773 { 3774 if (fOwner) { 3775 // we construct the smallest rectangle that contains the 3 points 3776 // for the 1st point 3777 BRect bounds(point1, point1); 3778 3779 // for the 2nd point 3780 if (point2.x < bounds.left) 3781 bounds.left = point2.x; 3782 3783 if (point2.y < bounds.top) 3784 bounds.top = point2.y; 3785 3786 if (point2.x > bounds.right) 3787 bounds.right = point2.x; 3788 3789 if (point2.y > bounds.bottom) 3790 bounds.bottom = point2.y; 3791 3792 // for the 3rd point 3793 if (point3.x < bounds.left) 3794 bounds.left = point3.x; 3795 3796 if (point3.y < bounds.top) 3797 bounds.top = point3.y; 3798 3799 if (point3.x > bounds.right) 3800 bounds.right = point3.x; 3801 3802 if (point3.y > bounds.bottom) 3803 bounds.bottom = point3.y; 3804 3805 StrokeTriangle(point1, point2, point3, bounds, pattern); 3806 } 3807 } 3808 3809 3810 void 3811 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3812 ::pattern pattern) 3813 { 3814 if (fOwner) { 3815 // we construct the smallest rectangle that contains the 3 points 3816 // for the 1st point 3817 BRect bounds(point1, point1); 3818 3819 // for the 2nd point 3820 if (point2.x < bounds.left) 3821 bounds.left = point2.x; 3822 3823 if (point2.y < bounds.top) 3824 bounds.top = point2.y; 3825 3826 if (point2.x > bounds.right) 3827 bounds.right = point2.x; 3828 3829 if (point2.y > bounds.bottom) 3830 bounds.bottom = point2.y; 3831 3832 // for the 3rd point 3833 if (point3.x < bounds.left) 3834 bounds.left = point3.x; 3835 3836 if (point3.y < bounds.top) 3837 bounds.top = point3.y; 3838 3839 if (point3.x > bounds.right) 3840 bounds.right = point3.x; 3841 3842 if (point3.y > bounds.bottom) 3843 bounds.bottom = point3.y; 3844 3845 FillTriangle(point1, point2, point3, bounds, pattern); 3846 } 3847 } 3848 3849 3850 void 3851 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3852 const BGradient& gradient) 3853 { 3854 if (fOwner) { 3855 // we construct the smallest rectangle that contains the 3 points 3856 // for the 1st point 3857 BRect bounds(point1, point1); 3858 3859 // for the 2nd point 3860 if (point2.x < bounds.left) 3861 bounds.left = point2.x; 3862 3863 if (point2.y < bounds.top) 3864 bounds.top = point2.y; 3865 3866 if (point2.x > bounds.right) 3867 bounds.right = point2.x; 3868 3869 if (point2.y > bounds.bottom) 3870 bounds.bottom = point2.y; 3871 3872 // for the 3rd point 3873 if (point3.x < bounds.left) 3874 bounds.left = point3.x; 3875 3876 if (point3.y < bounds.top) 3877 bounds.top = point3.y; 3878 3879 if (point3.x > bounds.right) 3880 bounds.right = point3.x; 3881 3882 if (point3.y > bounds.bottom) 3883 bounds.bottom = point3.y; 3884 3885 FillTriangle(point1, point2, point3, bounds, gradient); 3886 } 3887 } 3888 3889 3890 void 3891 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3892 BRect bounds, ::pattern pattern) 3893 { 3894 if (fOwner == NULL) 3895 return; 3896 3897 _CheckLockAndSwitchCurrent(); 3898 _UpdatePattern(pattern); 3899 3900 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 3901 fOwner->fLink->Attach<BPoint>(point1); 3902 fOwner->fLink->Attach<BPoint>(point2); 3903 fOwner->fLink->Attach<BPoint>(point3); 3904 fOwner->fLink->Attach<BRect>(bounds); 3905 3906 _FlushIfNotInTransaction(); 3907 } 3908 3909 3910 void 3911 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds, 3912 const BGradient& gradient) 3913 { 3914 if (fOwner == NULL) 3915 return; 3916 3917 _CheckLockAndSwitchCurrent(); 3918 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT); 3919 fOwner->fLink->Attach<BPoint>(point1); 3920 fOwner->fLink->Attach<BPoint>(point2); 3921 fOwner->fLink->Attach<BPoint>(point3); 3922 fOwner->fLink->Attach<BRect>(bounds); 3923 fOwner->fLink->AttachGradient(gradient); 3924 3925 _FlushIfNotInTransaction(); 3926 } 3927 3928 3929 void 3930 BView::StrokeLine(BPoint toPoint, ::pattern pattern) 3931 { 3932 StrokeLine(PenLocation(), toPoint, pattern); 3933 } 3934 3935 3936 void 3937 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern) 3938 { 3939 if (fOwner == NULL) 3940 return; 3941 3942 _CheckLockAndSwitchCurrent(); 3943 _UpdatePattern(pattern); 3944 3945 ViewStrokeLineInfo info; 3946 info.startPoint = start; 3947 info.endPoint = end; 3948 3949 fOwner->fLink->StartMessage(AS_STROKE_LINE); 3950 fOwner->fLink->Attach<ViewStrokeLineInfo>(info); 3951 3952 _FlushIfNotInTransaction(); 3953 3954 // this modifies our pen location, so we invalidate the flag. 3955 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3956 } 3957 3958 3959 void 3960 BView::StrokeShape(BShape* shape, ::pattern pattern) 3961 { 3962 if (shape == NULL || fOwner == NULL) 3963 return; 3964 3965 shape_data* sd = (shape_data*)shape->fPrivateData; 3966 if (sd->opCount == 0 || sd->ptCount == 0) 3967 return; 3968 3969 _CheckLockAndSwitchCurrent(); 3970 _UpdatePattern(pattern); 3971 3972 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 3973 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3974 fOwner->fLink->Attach<int32>(sd->opCount); 3975 fOwner->fLink->Attach<int32>(sd->ptCount); 3976 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 3977 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3978 3979 _FlushIfNotInTransaction(); 3980 } 3981 3982 3983 void 3984 BView::FillShape(BShape* shape, ::pattern pattern) 3985 { 3986 if (shape == NULL || fOwner == NULL) 3987 return; 3988 3989 shape_data* sd = (shape_data*)(shape->fPrivateData); 3990 if (sd->opCount == 0 || sd->ptCount == 0) 3991 return; 3992 3993 _CheckLockAndSwitchCurrent(); 3994 _UpdatePattern(pattern); 3995 3996 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 3997 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3998 fOwner->fLink->Attach<int32>(sd->opCount); 3999 fOwner->fLink->Attach<int32>(sd->ptCount); 4000 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 4001 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 4002 4003 _FlushIfNotInTransaction(); 4004 } 4005 4006 4007 void 4008 BView::FillShape(BShape* shape, const BGradient& gradient) 4009 { 4010 if (shape == NULL || fOwner == NULL) 4011 return; 4012 4013 shape_data* sd = (shape_data*)(shape->fPrivateData); 4014 if (sd->opCount == 0 || sd->ptCount == 0) 4015 return; 4016 4017 _CheckLockAndSwitchCurrent(); 4018 4019 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT); 4020 fOwner->fLink->Attach<BRect>(shape->Bounds()); 4021 fOwner->fLink->Attach<int32>(sd->opCount); 4022 fOwner->fLink->Attach<int32>(sd->ptCount); 4023 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 4024 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 4025 fOwner->fLink->AttachGradient(gradient); 4026 4027 _FlushIfNotInTransaction(); 4028 } 4029 4030 4031 void 4032 BView::BeginLineArray(int32 count) 4033 { 4034 if (fOwner == NULL) 4035 return; 4036 4037 if (count <= 0) 4038 debugger("Calling BeginLineArray with a count <= 0"); 4039 4040 _CheckLock(); 4041 4042 if (fCommArray) { 4043 debugger("Can't nest BeginLineArray calls"); 4044 // not fatal, but it helps during 4045 // development of your app and is in 4046 // line with R5... 4047 delete[] fCommArray->array; 4048 delete fCommArray; 4049 } 4050 4051 // TODO: since this method cannot return failure, and further AddLine() 4052 // calls with a NULL fCommArray would drop into the debugger anyway, 4053 // we allow the possible std::bad_alloc exceptions here... 4054 fCommArray = new _array_data_; 4055 fCommArray->count = 0; 4056 4057 // Make sure the fCommArray is initialized to reasonable values in cases of 4058 // bad_alloc. At least the exception can be caught and EndLineArray won't 4059 // crash. 4060 fCommArray->array = NULL; 4061 fCommArray->maxCount = 0; 4062 4063 fCommArray->array = new ViewLineArrayInfo[count]; 4064 fCommArray->maxCount = count; 4065 } 4066 4067 4068 void 4069 BView::AddLine(BPoint start, BPoint end, rgb_color color) 4070 { 4071 if (fOwner == NULL) 4072 return; 4073 4074 if (!fCommArray) 4075 debugger("BeginLineArray must be called before using AddLine"); 4076 4077 _CheckLock(); 4078 4079 const uint32 &arrayCount = fCommArray->count; 4080 if (arrayCount < fCommArray->maxCount) { 4081 fCommArray->array[arrayCount].startPoint = start; 4082 fCommArray->array[arrayCount].endPoint = end; 4083 fCommArray->array[arrayCount].color = color; 4084 4085 fCommArray->count++; 4086 } 4087 } 4088 4089 4090 void 4091 BView::EndLineArray() 4092 { 4093 if (fOwner == NULL) 4094 return; 4095 4096 if (fCommArray == NULL) 4097 debugger("Can't call EndLineArray before BeginLineArray"); 4098 4099 _CheckLockAndSwitchCurrent(); 4100 4101 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 4102 fOwner->fLink->Attach<int32>(fCommArray->count); 4103 fOwner->fLink->Attach(fCommArray->array, 4104 fCommArray->count * sizeof(ViewLineArrayInfo)); 4105 4106 _FlushIfNotInTransaction(); 4107 4108 _RemoveCommArray(); 4109 } 4110 4111 4112 void 4113 BView::SetDiskMode(char* filename, long offset) 4114 { 4115 // TODO: implement 4116 // One BeBook version has this to say about SetDiskMode(): 4117 // 4118 // "Begins recording a picture to the file with the given filename 4119 // at the given offset. Subsequent drawing commands sent to the view 4120 // will be written to the file until EndPicture() is called. The 4121 // stored commands may be played from the file with DrawPicture()." 4122 } 4123 4124 4125 void 4126 BView::BeginPicture(BPicture* picture) 4127 { 4128 if (_CheckOwnerLockAndSwitchCurrent() 4129 && picture && picture->fUsurped == NULL) { 4130 picture->Usurp(fCurrentPicture); 4131 fCurrentPicture = picture; 4132 4133 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE); 4134 } 4135 } 4136 4137 4138 void 4139 BView::AppendToPicture(BPicture* picture) 4140 { 4141 _CheckLockAndSwitchCurrent(); 4142 4143 if (picture && picture->fUsurped == NULL) { 4144 int32 token = picture->Token(); 4145 4146 if (token == -1) { 4147 BeginPicture(picture); 4148 } else { 4149 picture->SetToken(-1); 4150 picture->Usurp(fCurrentPicture); 4151 fCurrentPicture = picture; 4152 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE); 4153 fOwner->fLink->Attach<int32>(token); 4154 } 4155 } 4156 } 4157 4158 4159 BPicture* 4160 BView::EndPicture() 4161 { 4162 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) { 4163 int32 token; 4164 4165 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE); 4166 4167 int32 code; 4168 if (fOwner->fLink->FlushWithReply(code) == B_OK 4169 && code == B_OK 4170 && fOwner->fLink->Read<int32>(&token) == B_OK) { 4171 BPicture* picture = fCurrentPicture; 4172 fCurrentPicture = picture->StepDown(); 4173 picture->SetToken(token); 4174 4175 // TODO do this more efficient e.g. use a shared area and let the 4176 // client write into it 4177 picture->_Download(); 4178 return picture; 4179 } 4180 } 4181 4182 return NULL; 4183 } 4184 4185 4186 void 4187 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 4188 uint32 followFlags, uint32 options) 4189 { 4190 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 4191 } 4192 4193 4194 void 4195 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options) 4196 { 4197 BRect rect; 4198 if (bitmap) 4199 rect = bitmap->Bounds(); 4200 4201 rect.OffsetTo(B_ORIGIN); 4202 4203 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 4204 } 4205 4206 4207 void 4208 BView::ClearViewBitmap() 4209 { 4210 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 4211 } 4212 4213 4214 status_t 4215 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect, 4216 rgb_color* colorKey, uint32 followFlags, uint32 options) 4217 { 4218 if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 4219 return B_BAD_VALUE; 4220 4221 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 4222 options | AS_REQUEST_COLOR_KEY); 4223 if (status == B_OK) { 4224 // read the color that will be treated as transparent 4225 fOwner->fLink->Read<rgb_color>(colorKey); 4226 } 4227 4228 return status; 4229 } 4230 4231 4232 status_t 4233 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, 4234 uint32 followFlags, uint32 options) 4235 { 4236 if (overlay == NULL) 4237 return B_BAD_VALUE; 4238 4239 BRect rect = overlay->Bounds(); 4240 rect.OffsetTo(B_ORIGIN); 4241 4242 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 4243 } 4244 4245 4246 void 4247 BView::ClearViewOverlay() 4248 { 4249 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 4250 } 4251 4252 4253 void 4254 BView::CopyBits(BRect src, BRect dst) 4255 { 4256 if (fOwner == NULL) 4257 return; 4258 4259 if (!src.IsValid() || !dst.IsValid()) 4260 return; 4261 4262 _CheckLockAndSwitchCurrent(); 4263 4264 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS); 4265 fOwner->fLink->Attach<BRect>(src); 4266 fOwner->fLink->Attach<BRect>(dst); 4267 4268 _FlushIfNotInTransaction(); 4269 } 4270 4271 4272 void 4273 BView::DrawPicture(const BPicture* picture) 4274 { 4275 if (picture == NULL) 4276 return; 4277 4278 DrawPictureAsync(picture, PenLocation()); 4279 Sync(); 4280 } 4281 4282 4283 void 4284 BView::DrawPicture(const BPicture* picture, BPoint where) 4285 { 4286 if (picture == NULL) 4287 return; 4288 4289 DrawPictureAsync(picture, where); 4290 Sync(); 4291 } 4292 4293 4294 void 4295 BView::DrawPicture(const char* filename, long offset, BPoint where) 4296 { 4297 if (!filename) 4298 return; 4299 4300 DrawPictureAsync(filename, offset, where); 4301 Sync(); 4302 } 4303 4304 4305 void 4306 BView::DrawPictureAsync(const BPicture* picture) 4307 { 4308 if (picture == NULL) 4309 return; 4310 4311 DrawPictureAsync(picture, PenLocation()); 4312 } 4313 4314 4315 void 4316 BView::DrawPictureAsync(const BPicture* picture, BPoint where) 4317 { 4318 if (picture == NULL) 4319 return; 4320 4321 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 4322 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE); 4323 fOwner->fLink->Attach<int32>(picture->Token()); 4324 fOwner->fLink->Attach<BPoint>(where); 4325 4326 _FlushIfNotInTransaction(); 4327 } 4328 } 4329 4330 4331 void 4332 BView::DrawPictureAsync(const char* filename, long offset, BPoint where) 4333 { 4334 if (!filename) 4335 return; 4336 4337 // TODO: Test 4338 BFile file(filename, B_READ_ONLY); 4339 if (file.InitCheck() < B_OK) 4340 return; 4341 4342 file.Seek(offset, SEEK_SET); 4343 4344 BPicture picture; 4345 if (picture.Unflatten(&file) < B_OK) 4346 return; 4347 4348 DrawPictureAsync(&picture, where); 4349 } 4350 4351 4352 void 4353 BView::BeginLayer(uint8 opacity) 4354 { 4355 if (_CheckOwnerLockAndSwitchCurrent()) { 4356 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_LAYER); 4357 fOwner->fLink->Attach<uint8>(opacity); 4358 _FlushIfNotInTransaction(); 4359 } 4360 } 4361 4362 4363 void 4364 BView::EndLayer() 4365 { 4366 if (_CheckOwnerLockAndSwitchCurrent()) { 4367 fOwner->fLink->StartMessage(AS_VIEW_END_LAYER); 4368 _FlushIfNotInTransaction(); 4369 } 4370 } 4371 4372 4373 void 4374 BView::Invalidate(BRect invalRect) 4375 { 4376 if (fOwner == NULL) 4377 return; 4378 4379 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 4380 // On the server side, the invalid rect will be converted to a BRegion, 4381 // which rounds in a different manner, so that it really includes the 4382 // fractional coordinates of a BRect (ie ceilf(rect.right) & 4383 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 4384 // different rounding here to stay compatible in both ways. 4385 invalRect.left = (int)invalRect.left; 4386 invalRect.top = (int)invalRect.top; 4387 invalRect.right = (int)invalRect.right; 4388 invalRect.bottom = (int)invalRect.bottom; 4389 if (!invalRect.IsValid()) 4390 return; 4391 4392 _CheckLockAndSwitchCurrent(); 4393 4394 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT); 4395 fOwner->fLink->Attach<BRect>(invalRect); 4396 4397 // TODO: determine why this check isn't working correctly. 4398 #if 0 4399 if (!fOwner->fUpdateRequested) { 4400 fOwner->fLink->Flush(); 4401 fOwner->fUpdateRequested = true; 4402 } 4403 #else 4404 fOwner->fLink->Flush(); 4405 #endif 4406 } 4407 4408 4409 void 4410 BView::Invalidate(const BRegion* region) 4411 { 4412 if (region == NULL || fOwner == NULL) 4413 return; 4414 4415 _CheckLockAndSwitchCurrent(); 4416 4417 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION); 4418 fOwner->fLink->AttachRegion(*region); 4419 4420 // TODO: See above. 4421 #if 0 4422 if (!fOwner->fUpdateRequested) { 4423 fOwner->fLink->Flush(); 4424 fOwner->fUpdateRequested = true; 4425 } 4426 #else 4427 fOwner->fLink->Flush(); 4428 #endif 4429 } 4430 4431 4432 void 4433 BView::Invalidate() 4434 { 4435 Invalidate(Bounds()); 4436 } 4437 4438 4439 void 4440 BView::DelayedInvalidate(bigtime_t delay) 4441 { 4442 DelayedInvalidate(delay, Bounds()); 4443 } 4444 4445 4446 void 4447 BView::DelayedInvalidate(bigtime_t delay, BRect invalRect) 4448 { 4449 if (fOwner == NULL) 4450 return; 4451 4452 invalRect.left = (int)invalRect.left; 4453 invalRect.top = (int)invalRect.top; 4454 invalRect.right = (int)invalRect.right; 4455 invalRect.bottom = (int)invalRect.bottom; 4456 if (!invalRect.IsValid()) 4457 return; 4458 4459 _CheckLockAndSwitchCurrent(); 4460 4461 fOwner->fLink->StartMessage(AS_VIEW_DELAYED_INVALIDATE_RECT); 4462 fOwner->fLink->Attach<bigtime_t>(system_time() + delay); 4463 fOwner->fLink->Attach<BRect>(invalRect); 4464 fOwner->fLink->Flush(); 4465 } 4466 4467 4468 void 4469 BView::InvertRect(BRect rect) 4470 { 4471 if (fOwner) { 4472 _CheckLockAndSwitchCurrent(); 4473 4474 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT); 4475 fOwner->fLink->Attach<BRect>(rect); 4476 4477 _FlushIfNotInTransaction(); 4478 } 4479 } 4480 4481 4482 // #pragma mark - View Hierarchy Functions 4483 4484 4485 void 4486 BView::AddChild(BView* child, BView* before) 4487 { 4488 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n", 4489 this->Name(), 4490 child != NULL && child->Name() ? child->Name() : "NULL", 4491 before != NULL && before->Name() ? before->Name() : "NULL")); 4492 4493 if (!_AddChild(child, before)) 4494 return; 4495 4496 if (fLayoutData->fLayout) 4497 fLayoutData->fLayout->AddView(child); 4498 } 4499 4500 4501 bool 4502 BView::AddChild(BLayoutItem* child) 4503 { 4504 if (!fLayoutData->fLayout) 4505 return false; 4506 return fLayoutData->fLayout->AddItem(child); 4507 } 4508 4509 4510 bool 4511 BView::_AddChild(BView* child, BView* before) 4512 { 4513 if (!child) 4514 return false; 4515 4516 if (child->fParent != NULL) { 4517 debugger("AddChild failed - the view already has a parent."); 4518 return false; 4519 } 4520 4521 if (child == this) { 4522 debugger("AddChild failed - cannot add a view to itself."); 4523 return false; 4524 } 4525 4526 bool lockedOwner = false; 4527 if (fOwner && !fOwner->IsLocked()) { 4528 fOwner->Lock(); 4529 lockedOwner = true; 4530 } 4531 4532 if (!_AddChildToList(child, before)) { 4533 debugger("AddChild failed!"); 4534 if (lockedOwner) 4535 fOwner->Unlock(); 4536 return false; 4537 } 4538 4539 if (fOwner) { 4540 _CheckLockAndSwitchCurrent(); 4541 4542 child->_SetOwner(fOwner); 4543 child->_CreateSelf(); 4544 child->_Attach(); 4545 4546 if (lockedOwner) 4547 fOwner->Unlock(); 4548 } 4549 4550 InvalidateLayout(); 4551 4552 return true; 4553 } 4554 4555 4556 bool 4557 BView::RemoveChild(BView* child) 4558 { 4559 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name())); 4560 4561 if (!child) 4562 return false; 4563 4564 if (child->fParent != this) 4565 return false; 4566 4567 return child->RemoveSelf(); 4568 } 4569 4570 4571 int32 4572 BView::CountChildren() const 4573 { 4574 _CheckLock(); 4575 4576 uint32 count = 0; 4577 BView* child = fFirstChild; 4578 4579 while (child != NULL) { 4580 count++; 4581 child = child->fNextSibling; 4582 } 4583 4584 return count; 4585 } 4586 4587 4588 BView* 4589 BView::ChildAt(int32 index) const 4590 { 4591 _CheckLock(); 4592 4593 BView* child = fFirstChild; 4594 while (child != NULL && index-- > 0) { 4595 child = child->fNextSibling; 4596 } 4597 4598 return child; 4599 } 4600 4601 4602 BView* 4603 BView::NextSibling() const 4604 { 4605 return fNextSibling; 4606 } 4607 4608 4609 BView* 4610 BView::PreviousSibling() const 4611 { 4612 return fPreviousSibling; 4613 } 4614 4615 4616 bool 4617 BView::RemoveSelf() 4618 { 4619 _RemoveLayoutItemsFromLayout(false); 4620 4621 return _RemoveSelf(); 4622 } 4623 4624 4625 bool 4626 BView::_RemoveSelf() 4627 { 4628 STRACE(("BView(%s)::_RemoveSelf()\n", Name())); 4629 4630 // Remove this child from its parent 4631 4632 BWindow* owner = fOwner; 4633 _CheckLock(); 4634 4635 if (owner != NULL) { 4636 _UpdateStateForRemove(); 4637 _Detach(); 4638 } 4639 4640 BView* parent = fParent; 4641 if (!parent || !parent->_RemoveChildFromList(this)) 4642 return false; 4643 4644 if (owner != NULL && !fTopLevelView) { 4645 // the top level view is deleted by the app_server automatically 4646 owner->fLink->StartMessage(AS_VIEW_DELETE); 4647 owner->fLink->Attach<int32>(_get_object_token_(this)); 4648 } 4649 4650 parent->InvalidateLayout(); 4651 4652 STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name())); 4653 4654 return true; 4655 } 4656 4657 4658 void 4659 BView::_RemoveLayoutItemsFromLayout(bool deleteItems) 4660 { 4661 if (fParent == NULL || fParent->fLayoutData->fLayout == NULL) 4662 return; 4663 4664 int32 index = fLayoutData->fLayoutItems.CountItems(); 4665 while (index-- > 0) { 4666 BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(index); 4667 item->RemoveSelf(); 4668 // Removes item from fLayoutItems list 4669 if (deleteItems) 4670 delete item; 4671 } 4672 } 4673 4674 4675 BView* 4676 BView::Parent() const 4677 { 4678 if (fParent && fParent->fTopLevelView) 4679 return NULL; 4680 4681 return fParent; 4682 } 4683 4684 4685 BView* 4686 BView::FindView(const char* name) const 4687 { 4688 if (name == NULL) 4689 return NULL; 4690 4691 if (Name() != NULL && !strcmp(Name(), name)) 4692 return const_cast<BView*>(this); 4693 4694 BView* child = fFirstChild; 4695 while (child != NULL) { 4696 BView* view = child->FindView(name); 4697 if (view != NULL) 4698 return view; 4699 4700 child = child->fNextSibling; 4701 } 4702 4703 return NULL; 4704 } 4705 4706 4707 void 4708 BView::MoveBy(float deltaX, float deltaY) 4709 { 4710 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY)); 4711 } 4712 4713 4714 void 4715 BView::MoveTo(BPoint where) 4716 { 4717 MoveTo(where.x, where.y); 4718 } 4719 4720 4721 void 4722 BView::MoveTo(float x, float y) 4723 { 4724 if (x == fParentOffset.x && y == fParentOffset.y) 4725 return; 4726 4727 // BeBook says we should do this. And it makes sense. 4728 x = roundf(x); 4729 y = roundf(y); 4730 4731 if (fOwner) { 4732 _CheckLockAndSwitchCurrent(); 4733 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO); 4734 fOwner->fLink->Attach<float>(x); 4735 fOwner->fLink->Attach<float>(y); 4736 4737 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4738 4739 _FlushIfNotInTransaction(); 4740 } 4741 4742 _MoveTo((int32)x, (int32)y); 4743 } 4744 4745 4746 void 4747 BView::ResizeBy(float deltaWidth, float deltaHeight) 4748 { 4749 // BeBook says we should do this. And it makes sense. 4750 deltaWidth = roundf(deltaWidth); 4751 deltaHeight = roundf(deltaHeight); 4752 4753 if (deltaWidth == 0 && deltaHeight == 0) 4754 return; 4755 4756 if (fOwner) { 4757 _CheckLockAndSwitchCurrent(); 4758 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO); 4759 4760 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth); 4761 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight); 4762 4763 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4764 4765 _FlushIfNotInTransaction(); 4766 } 4767 4768 _ResizeBy((int32)deltaWidth, (int32)deltaHeight); 4769 } 4770 4771 4772 void 4773 BView::ResizeTo(float width, float height) 4774 { 4775 ResizeBy(width - fBounds.Width(), height - fBounds.Height()); 4776 } 4777 4778 4779 void 4780 BView::ResizeTo(BSize size) 4781 { 4782 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height()); 4783 } 4784 4785 4786 // #pragma mark - Inherited Methods (from BHandler) 4787 4788 4789 status_t 4790 BView::GetSupportedSuites(BMessage* data) 4791 { 4792 if (data == NULL) 4793 return B_BAD_VALUE; 4794 4795 status_t status = data->AddString("suites", "suite/vnd.Be-view"); 4796 BPropertyInfo propertyInfo(sViewPropInfo); 4797 if (status == B_OK) 4798 status = data->AddFlat("messages", &propertyInfo); 4799 if (status == B_OK) 4800 return BHandler::GetSupportedSuites(data); 4801 return status; 4802 } 4803 4804 4805 BHandler* 4806 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier, 4807 int32 what, const char* property) 4808 { 4809 if (message->what == B_WINDOW_MOVE_BY 4810 || message->what == B_WINDOW_MOVE_TO) { 4811 return this; 4812 } 4813 4814 BPropertyInfo propertyInfo(sViewPropInfo); 4815 status_t err = B_BAD_SCRIPT_SYNTAX; 4816 BMessage replyMsg(B_REPLY); 4817 4818 switch (propertyInfo.FindMatch(message, index, specifier, what, property)) { 4819 case 0: 4820 case 1: 4821 case 3: 4822 return this; 4823 4824 case 2: 4825 if (fShelf) { 4826 message->PopSpecifier(); 4827 return fShelf; 4828 } 4829 4830 err = B_NAME_NOT_FOUND; 4831 replyMsg.AddString("message", "This window doesn't have a shelf"); 4832 break; 4833 4834 case 4: 4835 { 4836 if (!fFirstChild) { 4837 err = B_NAME_NOT_FOUND; 4838 replyMsg.AddString("message", "This window doesn't have " 4839 "children."); 4840 break; 4841 } 4842 BView* child = NULL; 4843 switch (what) { 4844 case B_INDEX_SPECIFIER: 4845 { 4846 int32 index; 4847 err = specifier->FindInt32("index", &index); 4848 if (err == B_OK) 4849 child = ChildAt(index); 4850 break; 4851 } 4852 case B_REVERSE_INDEX_SPECIFIER: 4853 { 4854 int32 rindex; 4855 err = specifier->FindInt32("index", &rindex); 4856 if (err == B_OK) 4857 child = ChildAt(CountChildren() - rindex); 4858 break; 4859 } 4860 case B_NAME_SPECIFIER: 4861 { 4862 const char* name; 4863 err = specifier->FindString("name", &name); 4864 if (err == B_OK) 4865 child = FindView(name); 4866 break; 4867 } 4868 } 4869 4870 if (child != NULL) { 4871 message->PopSpecifier(); 4872 return child; 4873 } 4874 4875 if (err == B_OK) 4876 err = B_BAD_INDEX; 4877 4878 replyMsg.AddString("message", 4879 "Cannot find view at/with specified index/name."); 4880 break; 4881 } 4882 4883 default: 4884 return BHandler::ResolveSpecifier(message, index, specifier, what, 4885 property); 4886 } 4887 4888 if (err < B_OK) { 4889 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4890 4891 if (err == B_BAD_SCRIPT_SYNTAX) 4892 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4893 else 4894 replyMsg.AddString("message", strerror(err)); 4895 } 4896 4897 replyMsg.AddInt32("error", err); 4898 message->SendReply(&replyMsg); 4899 return NULL; 4900 } 4901 4902 4903 void 4904 BView::MessageReceived(BMessage* message) 4905 { 4906 if (!message->HasSpecifiers()) { 4907 switch (message->what) { 4908 case B_VIEW_RESIZED: 4909 FrameResized(message->GetInt32("width", 0), 4910 message->GetInt32("height", 0)); 4911 break; 4912 4913 case B_VIEW_MOVED: 4914 FrameMoved(fParentOffset); 4915 break; 4916 4917 case B_MOUSE_IDLE: 4918 { 4919 BPoint where; 4920 if (message->FindPoint("be:view_where", &where) != B_OK) 4921 break; 4922 4923 BToolTip* tip; 4924 if (GetToolTipAt(where, &tip)) 4925 ShowToolTip(tip); 4926 else 4927 BHandler::MessageReceived(message); 4928 break; 4929 } 4930 4931 case B_MOUSE_WHEEL_CHANGED: 4932 { 4933 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL); 4934 BScrollBar* vertical = ScrollBar(B_VERTICAL); 4935 if (horizontal == NULL && vertical == NULL) { 4936 // Pass the message to the next handler 4937 BHandler::MessageReceived(message); 4938 break; 4939 } 4940 4941 float deltaX = 0.0f; 4942 float deltaY = 0.0f; 4943 4944 if (horizontal != NULL) 4945 message->FindFloat("be:wheel_delta_x", &deltaX); 4946 4947 if (vertical != NULL) 4948 message->FindFloat("be:wheel_delta_y", &deltaY); 4949 4950 if (deltaX == 0.0f && deltaY == 0.0f) 4951 break; 4952 4953 if ((modifiers() & B_CONTROL_KEY) != 0) 4954 std::swap(horizontal, vertical); 4955 4956 if (horizontal != NULL && deltaX != 0.0f) 4957 ScrollWithMouseWheelDelta(horizontal, deltaX); 4958 4959 if (vertical != NULL && deltaY != 0.0f) 4960 ScrollWithMouseWheelDelta(vertical, deltaY); 4961 4962 break; 4963 } 4964 4965 // prevent message repeats 4966 case B_COLORS_UPDATED: 4967 case B_FONTS_UPDATED: 4968 break; 4969 4970 case B_SCREEN_CHANGED: 4971 { 4972 // propegate message to child views 4973 int32 childCount = CountChildren(); 4974 for (int32 i = 0; i < childCount; i++) { 4975 BView* view = ChildAt(i); 4976 if (view != NULL) 4977 view->MessageReceived(message); 4978 } 4979 break; 4980 } 4981 4982 default: 4983 BHandler::MessageReceived(message); 4984 break; 4985 } 4986 4987 return; 4988 } 4989 4990 // Scripting message 4991 4992 BMessage replyMsg(B_REPLY); 4993 status_t err = B_BAD_SCRIPT_SYNTAX; 4994 int32 index; 4995 BMessage specifier; 4996 int32 what; 4997 const char* property; 4998 4999 if (message->GetCurrentSpecifier(&index, &specifier, &what, &property) 5000 != B_OK) { 5001 return BHandler::MessageReceived(message); 5002 } 5003 5004 BPropertyInfo propertyInfo(sViewPropInfo); 5005 switch (propertyInfo.FindMatch(message, index, &specifier, what, 5006 property)) { 5007 case 0: 5008 if (message->what == B_GET_PROPERTY) { 5009 err = replyMsg.AddRect("result", Frame()); 5010 } else if (message->what == B_SET_PROPERTY) { 5011 BRect newFrame; 5012 err = message->FindRect("data", &newFrame); 5013 if (err == B_OK) { 5014 MoveTo(newFrame.LeftTop()); 5015 ResizeTo(newFrame.Width(), newFrame.Height()); 5016 } 5017 } 5018 break; 5019 case 1: 5020 if (message->what == B_GET_PROPERTY) { 5021 err = replyMsg.AddBool("result", IsHidden()); 5022 } else if (message->what == B_SET_PROPERTY) { 5023 bool newHiddenState; 5024 err = message->FindBool("data", &newHiddenState); 5025 if (err == B_OK) { 5026 if (newHiddenState == true) 5027 Hide(); 5028 else 5029 Show(); 5030 } 5031 } 5032 break; 5033 case 3: 5034 err = replyMsg.AddInt32("result", CountChildren()); 5035 break; 5036 default: 5037 return BHandler::MessageReceived(message); 5038 } 5039 5040 if (err != B_OK) { 5041 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 5042 5043 if (err == B_BAD_SCRIPT_SYNTAX) 5044 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 5045 else 5046 replyMsg.AddString("message", strerror(err)); 5047 5048 replyMsg.AddInt32("error", err); 5049 } 5050 5051 message->SendReply(&replyMsg); 5052 } 5053 5054 5055 status_t 5056 BView::Perform(perform_code code, void* _data) 5057 { 5058 switch (code) { 5059 case PERFORM_CODE_MIN_SIZE: 5060 ((perform_data_min_size*)_data)->return_value 5061 = BView::MinSize(); 5062 return B_OK; 5063 case PERFORM_CODE_MAX_SIZE: 5064 ((perform_data_max_size*)_data)->return_value 5065 = BView::MaxSize(); 5066 return B_OK; 5067 case PERFORM_CODE_PREFERRED_SIZE: 5068 ((perform_data_preferred_size*)_data)->return_value 5069 = BView::PreferredSize(); 5070 return B_OK; 5071 case PERFORM_CODE_LAYOUT_ALIGNMENT: 5072 ((perform_data_layout_alignment*)_data)->return_value 5073 = BView::LayoutAlignment(); 5074 return B_OK; 5075 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 5076 ((perform_data_has_height_for_width*)_data)->return_value 5077 = BView::HasHeightForWidth(); 5078 return B_OK; 5079 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 5080 { 5081 perform_data_get_height_for_width* data 5082 = (perform_data_get_height_for_width*)_data; 5083 BView::GetHeightForWidth(data->width, &data->min, &data->max, 5084 &data->preferred); 5085 return B_OK; 5086 } 5087 case PERFORM_CODE_SET_LAYOUT: 5088 { 5089 perform_data_set_layout* data = (perform_data_set_layout*)_data; 5090 BView::SetLayout(data->layout); 5091 return B_OK; 5092 } 5093 case PERFORM_CODE_LAYOUT_INVALIDATED: 5094 { 5095 perform_data_layout_invalidated* data 5096 = (perform_data_layout_invalidated*)_data; 5097 BView::LayoutInvalidated(data->descendants); 5098 return B_OK; 5099 } 5100 case PERFORM_CODE_DO_LAYOUT: 5101 { 5102 BView::DoLayout(); 5103 return B_OK; 5104 } 5105 case PERFORM_CODE_LAYOUT_CHANGED: 5106 { 5107 BView::LayoutChanged(); 5108 return B_OK; 5109 } 5110 case PERFORM_CODE_GET_TOOL_TIP_AT: 5111 { 5112 perform_data_get_tool_tip_at* data 5113 = (perform_data_get_tool_tip_at*)_data; 5114 data->return_value 5115 = BView::GetToolTipAt(data->point, data->tool_tip); 5116 return B_OK; 5117 } 5118 case PERFORM_CODE_ALL_UNARCHIVED: 5119 { 5120 perform_data_all_unarchived* data = 5121 (perform_data_all_unarchived*)_data; 5122 5123 data->return_value = BView::AllUnarchived(data->archive); 5124 return B_OK; 5125 } 5126 case PERFORM_CODE_ALL_ARCHIVED: 5127 { 5128 perform_data_all_archived* data = 5129 (perform_data_all_archived*)_data; 5130 5131 data->return_value = BView::AllArchived(data->archive); 5132 return B_OK; 5133 } 5134 } 5135 5136 return BHandler::Perform(code, _data); 5137 } 5138 5139 5140 // #pragma mark - Layout Functions 5141 5142 5143 BSize 5144 BView::MinSize() 5145 { 5146 // TODO: make sure this works correctly when some methods are overridden 5147 float width, height; 5148 GetPreferredSize(&width, &height); 5149 5150 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 5151 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 5152 : BSize(width, height))); 5153 } 5154 5155 5156 BSize 5157 BView::MaxSize() 5158 { 5159 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 5160 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 5161 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 5162 } 5163 5164 5165 BSize 5166 BView::PreferredSize() 5167 { 5168 // TODO: make sure this works correctly when some methods are overridden 5169 float width, height; 5170 GetPreferredSize(&width, &height); 5171 5172 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 5173 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 5174 : BSize(width, height))); 5175 } 5176 5177 5178 BAlignment 5179 BView::LayoutAlignment() 5180 { 5181 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 5182 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 5183 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 5184 } 5185 5186 5187 void 5188 BView::SetExplicitMinSize(BSize size) 5189 { 5190 fLayoutData->fMinSize = size; 5191 InvalidateLayout(); 5192 } 5193 5194 5195 void 5196 BView::SetExplicitMaxSize(BSize size) 5197 { 5198 fLayoutData->fMaxSize = size; 5199 InvalidateLayout(); 5200 } 5201 5202 5203 void 5204 BView::SetExplicitPreferredSize(BSize size) 5205 { 5206 fLayoutData->fPreferredSize = size; 5207 InvalidateLayout(); 5208 } 5209 5210 5211 void 5212 BView::SetExplicitSize(BSize size) 5213 { 5214 fLayoutData->fMinSize = size; 5215 fLayoutData->fMaxSize = size; 5216 fLayoutData->fPreferredSize = size; 5217 InvalidateLayout(); 5218 } 5219 5220 5221 void 5222 BView::SetExplicitAlignment(BAlignment alignment) 5223 { 5224 fLayoutData->fAlignment = alignment; 5225 InvalidateLayout(); 5226 } 5227 5228 5229 BSize 5230 BView::ExplicitMinSize() const 5231 { 5232 return fLayoutData->fMinSize; 5233 } 5234 5235 5236 BSize 5237 BView::ExplicitMaxSize() const 5238 { 5239 return fLayoutData->fMaxSize; 5240 } 5241 5242 5243 BSize 5244 BView::ExplicitPreferredSize() const 5245 { 5246 return fLayoutData->fPreferredSize; 5247 } 5248 5249 5250 BAlignment 5251 BView::ExplicitAlignment() const 5252 { 5253 return fLayoutData->fAlignment; 5254 } 5255 5256 5257 bool 5258 BView::HasHeightForWidth() 5259 { 5260 return (fLayoutData->fLayout 5261 ? fLayoutData->fLayout->HasHeightForWidth() : false); 5262 } 5263 5264 5265 void 5266 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 5267 { 5268 if (fLayoutData->fLayout) 5269 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 5270 } 5271 5272 5273 void 5274 BView::SetLayout(BLayout* layout) 5275 { 5276 if (layout == fLayoutData->fLayout) 5277 return; 5278 5279 if (layout && layout->Layout()) 5280 debugger("BView::SetLayout() failed, layout is already in use."); 5281 5282 fFlags |= B_SUPPORTS_LAYOUT; 5283 5284 // unset and delete the old layout 5285 if (fLayoutData->fLayout) { 5286 fLayoutData->fLayout->RemoveSelf(); 5287 fLayoutData->fLayout->SetOwner(NULL); 5288 delete fLayoutData->fLayout; 5289 } 5290 5291 fLayoutData->fLayout = layout; 5292 5293 if (fLayoutData->fLayout) { 5294 fLayoutData->fLayout->SetOwner(this); 5295 5296 // add all children 5297 int count = CountChildren(); 5298 for (int i = 0; i < count; i++) 5299 fLayoutData->fLayout->AddView(ChildAt(i)); 5300 } 5301 5302 InvalidateLayout(); 5303 } 5304 5305 5306 BLayout* 5307 BView::GetLayout() const 5308 { 5309 return fLayoutData->fLayout; 5310 } 5311 5312 5313 void 5314 BView::InvalidateLayout(bool descendants) 5315 { 5316 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n", 5317 // this, descendants, fLayoutData->fLayoutValid, 5318 // fLayoutData->fLayoutInProgress); 5319 5320 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress 5321 || fLayoutData->fLayoutInvalidationDisabled > 0) { 5322 return; 5323 } 5324 fLayoutData->fLayoutValid = false; 5325 fLayoutData->fMinMaxValid = false; 5326 LayoutInvalidated(descendants); 5327 5328 if (descendants) { 5329 for (BView* child = fFirstChild; 5330 child; child = child->fNextSibling) { 5331 child->InvalidateLayout(descendants); 5332 } 5333 } 5334 5335 if (fLayoutData->fLayout) 5336 fLayoutData->fLayout->InvalidateLayout(descendants); 5337 else 5338 _InvalidateParentLayout(); 5339 5340 if (fTopLevelView 5341 && fOwner != NULL) 5342 fOwner->PostMessage(B_LAYOUT_WINDOW); 5343 } 5344 5345 5346 void 5347 BView::EnableLayoutInvalidation() 5348 { 5349 if (fLayoutData->fLayoutInvalidationDisabled > 0) 5350 fLayoutData->fLayoutInvalidationDisabled--; 5351 } 5352 5353 5354 void 5355 BView::DisableLayoutInvalidation() 5356 { 5357 fLayoutData->fLayoutInvalidationDisabled++; 5358 } 5359 5360 5361 bool 5362 BView::IsLayoutInvalidationDisabled() 5363 { 5364 if (fLayoutData->fLayoutInvalidationDisabled > 0) 5365 return true; 5366 return false; 5367 } 5368 5369 5370 bool 5371 BView::IsLayoutValid() const 5372 { 5373 return fLayoutData->fLayoutValid; 5374 } 5375 5376 5377 void 5378 BView::ResetLayoutInvalidation() 5379 { 5380 fLayoutData->fMinMaxValid = true; 5381 } 5382 5383 5384 BLayoutContext* 5385 BView::LayoutContext() const 5386 { 5387 return fLayoutData->fLayoutContext; 5388 } 5389 5390 5391 void 5392 BView::Layout(bool force) 5393 { 5394 BLayoutContext context; 5395 _Layout(force, &context); 5396 } 5397 5398 5399 void 5400 BView::Relayout() 5401 { 5402 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 5403 fLayoutData->fNeedsRelayout = true; 5404 if (fLayoutData->fLayout) 5405 fLayoutData->fLayout->RequireLayout(); 5406 5407 // Layout() is recursive, that is if the parent view is currently laid 5408 // out, we don't call layout() on this view, but wait for the parent's 5409 // Layout() to do that for us. 5410 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 5411 Layout(false); 5412 } 5413 } 5414 5415 5416 void 5417 BView::LayoutInvalidated(bool descendants) 5418 { 5419 // hook method 5420 } 5421 5422 5423 void 5424 BView::DoLayout() 5425 { 5426 if (fLayoutData->fLayout) 5427 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext()); 5428 } 5429 5430 5431 void 5432 BView::SetToolTip(const char* text) 5433 { 5434 if (text == NULL || text[0] == '\0') { 5435 SetToolTip((BToolTip*)NULL); 5436 return; 5437 } 5438 5439 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip)) 5440 tip->SetText(text); 5441 else 5442 SetToolTip(new BTextToolTip(text)); 5443 } 5444 5445 5446 void 5447 BView::SetToolTip(BToolTip* tip) 5448 { 5449 if (fToolTip == tip) 5450 return; 5451 else if (tip == NULL) 5452 HideToolTip(); 5453 5454 if (fToolTip != NULL) 5455 fToolTip->ReleaseReference(); 5456 5457 fToolTip = tip; 5458 5459 if (fToolTip != NULL) 5460 fToolTip->AcquireReference(); 5461 } 5462 5463 5464 BToolTip* 5465 BView::ToolTip() const 5466 { 5467 return fToolTip; 5468 } 5469 5470 5471 void 5472 BView::ShowToolTip(BToolTip* tip) 5473 { 5474 if (tip == NULL) 5475 return; 5476 5477 BPoint where; 5478 GetMouse(&where, NULL, false); 5479 5480 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this); 5481 } 5482 5483 5484 void 5485 BView::HideToolTip() 5486 { 5487 BToolTipManager::Manager()->HideTip(); 5488 } 5489 5490 5491 bool 5492 BView::GetToolTipAt(BPoint point, BToolTip** _tip) 5493 { 5494 if (fToolTip != NULL) { 5495 *_tip = fToolTip; 5496 return true; 5497 } 5498 5499 *_tip = NULL; 5500 return false; 5501 } 5502 5503 5504 void 5505 BView::LayoutChanged() 5506 { 5507 // hook method 5508 } 5509 5510 5511 void 5512 BView::_Layout(bool force, BLayoutContext* context) 5513 { 5514 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 5515 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 5516 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, 5517 //fLayoutData->fLayoutInProgress); 5518 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 5519 fLayoutData->fLayoutValid = false; 5520 5521 if (fLayoutData->fLayoutInProgress) 5522 return; 5523 5524 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 5525 fLayoutData->fLayoutContext = context; 5526 5527 fLayoutData->fLayoutInProgress = true; 5528 DoLayout(); 5529 fLayoutData->fLayoutInProgress = false; 5530 5531 fLayoutData->fLayoutValid = true; 5532 fLayoutData->fMinMaxValid = true; 5533 fLayoutData->fNeedsRelayout = false; 5534 5535 // layout children 5536 for(BView* child = fFirstChild; child; child = child->fNextSibling) { 5537 if (!child->IsHidden(child)) 5538 child->_Layout(force, context); 5539 } 5540 5541 LayoutChanged(); 5542 5543 fLayoutData->fLayoutContext = oldContext; 5544 5545 // invalidate the drawn content, if requested 5546 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 5547 Invalidate(); 5548 } 5549 } 5550 5551 5552 void 5553 BView::_LayoutLeft(BLayout* deleted) 5554 { 5555 // If our layout is added to another layout (via BLayout::AddItem()) 5556 // then we share ownership of our layout. In the event that our layout gets 5557 // deleted by the layout it has been added to, this method is called so 5558 // that we don't double-delete our layout. 5559 if (fLayoutData->fLayout == deleted) 5560 fLayoutData->fLayout = NULL; 5561 InvalidateLayout(); 5562 } 5563 5564 5565 void 5566 BView::_InvalidateParentLayout() 5567 { 5568 if (!fParent) 5569 return; 5570 5571 BLayout* layout = fLayoutData->fLayout; 5572 BLayout* layoutParent = layout ? layout->Layout() : NULL; 5573 if (layoutParent) { 5574 layoutParent->InvalidateLayout(); 5575 } else if (fLayoutData->fLayoutItems.CountItems() > 0) { 5576 int32 count = fLayoutData->fLayoutItems.CountItems(); 5577 for (int32 i = 0; i < count; i++) { 5578 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout(); 5579 } 5580 } else { 5581 fParent->InvalidateLayout(); 5582 } 5583 } 5584 5585 5586 // #pragma mark - Private Functions 5587 5588 5589 void 5590 BView::_InitData(BRect frame, const char* name, uint32 resizingMode, 5591 uint32 flags) 5592 { 5593 // Info: The name of the view is set by BHandler constructor 5594 5595 STRACE(("BView::_InitData: enter\n")); 5596 5597 // initialize members 5598 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 5599 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name); 5600 5601 // There are applications that swap the resize mask and the flags in the 5602 // BView constructor. This does not cause problems under BeOS as it just 5603 // ors the two fields to one 32bit flag. 5604 // For now we do the same but print the above warning message. 5605 // TODO: this should be removed at some point and the original 5606 // version restored: 5607 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 5608 fFlags = resizingMode | flags; 5609 5610 // handle rounding 5611 frame.left = roundf(frame.left); 5612 frame.top = roundf(frame.top); 5613 frame.right = roundf(frame.right); 5614 frame.bottom = roundf(frame.bottom); 5615 5616 fParentOffset.Set(frame.left, frame.top); 5617 5618 fOwner = NULL; 5619 fParent = NULL; 5620 fNextSibling = NULL; 5621 fPreviousSibling = NULL; 5622 fFirstChild = NULL; 5623 5624 fShowLevel = 0; 5625 fTopLevelView = false; 5626 5627 fCurrentPicture = NULL; 5628 fCommArray = NULL; 5629 5630 fVerScroller = NULL; 5631 fHorScroller = NULL; 5632 5633 fIsPrinting = false; 5634 fAttached = false; 5635 5636 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 5637 // TODO: Maybe we could auto-delete those views on AddChild() instead? 5638 fState = new BPrivate::ViewState; 5639 5640 fBounds = frame.OffsetToCopy(B_ORIGIN); 5641 fShelf = NULL; 5642 5643 fEventMask = 0; 5644 fEventOptions = 0; 5645 fMouseEventOptions = 0; 5646 5647 fLayoutData = new LayoutData; 5648 5649 fToolTip = NULL; 5650 5651 if ((flags & B_SUPPORTS_LAYOUT) != 0) { 5652 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 5653 SetLowUIColor(ViewUIColor()); 5654 SetHighUIColor(B_PANEL_TEXT_COLOR); 5655 } 5656 } 5657 5658 5659 void 5660 BView::_RemoveCommArray() 5661 { 5662 if (fCommArray) { 5663 delete [] fCommArray->array; 5664 delete fCommArray; 5665 fCommArray = NULL; 5666 } 5667 } 5668 5669 5670 void 5671 BView::_SetOwner(BWindow* newOwner) 5672 { 5673 if (!newOwner) 5674 _RemoveCommArray(); 5675 5676 if (fOwner != newOwner && fOwner) { 5677 if (fOwner->fFocus == this) 5678 MakeFocus(false); 5679 5680 if (fOwner->fLastMouseMovedView == this) 5681 fOwner->fLastMouseMovedView = NULL; 5682 5683 fOwner->RemoveHandler(this); 5684 if (fShelf) 5685 fOwner->RemoveHandler(fShelf); 5686 } 5687 5688 if (newOwner && newOwner != fOwner) { 5689 newOwner->AddHandler(this); 5690 if (fShelf) 5691 newOwner->AddHandler(fShelf); 5692 5693 if (fTopLevelView) 5694 SetNextHandler(newOwner); 5695 else 5696 SetNextHandler(fParent); 5697 } 5698 5699 fOwner = newOwner; 5700 5701 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) 5702 child->_SetOwner(newOwner); 5703 } 5704 5705 5706 void 5707 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) 5708 { 5709 if (!_CheckOwnerLockAndSwitchCurrent()) 5710 return; 5711 5712 if (picture == NULL) { 5713 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 5714 fOwner->fLink->Attach<int32>(-1); 5715 5716 // NOTE: No need to sync here, since the -1 token cannot 5717 // become invalid on the server. 5718 } else { 5719 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 5720 fOwner->fLink->Attach<int32>(picture->Token()); 5721 fOwner->fLink->Attach<BPoint>(where); 5722 fOwner->fLink->Attach<bool>(invert); 5723 5724 // NOTE: "sync" defaults to true in public methods. If you know what 5725 // you are doing, i.e. if you know your BPicture stays valid, you 5726 // can avoid the performance impact of syncing. In a use-case where 5727 // the client creates BPictures on the stack, these BPictures may 5728 // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw() 5729 // goes out of scope, and the command is processed earlier in the 5730 // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the 5731 // ServerWindow thread, which will then have the result that no 5732 // ServerPicture is found of the token. 5733 if (sync) 5734 Sync(); 5735 } 5736 } 5737 5738 5739 void 5740 BView::_ClipToRect(BRect rect, bool inverse) 5741 { 5742 if (_CheckOwnerLockAndSwitchCurrent()) { 5743 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_RECT); 5744 fOwner->fLink->Attach<bool>(inverse); 5745 fOwner->fLink->Attach<BRect>(rect); 5746 _FlushIfNotInTransaction(); 5747 } 5748 } 5749 5750 5751 void 5752 BView::_ClipToShape(BShape* shape, bool inverse) 5753 { 5754 if (shape == NULL) 5755 return; 5756 5757 shape_data* sd = (shape_data*)shape->fPrivateData; 5758 if (sd->opCount == 0 || sd->ptCount == 0) 5759 return; 5760 5761 if (_CheckOwnerLockAndSwitchCurrent()) { 5762 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_SHAPE); 5763 fOwner->fLink->Attach<bool>(inverse); 5764 fOwner->fLink->Attach<int32>(sd->opCount); 5765 fOwner->fLink->Attach<int32>(sd->ptCount); 5766 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 5767 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 5768 _FlushIfNotInTransaction(); 5769 } 5770 } 5771 5772 5773 bool 5774 BView::_RemoveChildFromList(BView* child) 5775 { 5776 if (child->fParent != this) 5777 return false; 5778 5779 if (fFirstChild == child) { 5780 // it's the first view in the list 5781 fFirstChild = child->fNextSibling; 5782 } else { 5783 // there must be a previous sibling 5784 child->fPreviousSibling->fNextSibling = child->fNextSibling; 5785 } 5786 5787 if (child->fNextSibling) 5788 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 5789 5790 child->fParent = NULL; 5791 child->fNextSibling = NULL; 5792 child->fPreviousSibling = NULL; 5793 5794 return true; 5795 } 5796 5797 5798 bool 5799 BView::_AddChildToList(BView* child, BView* before) 5800 { 5801 if (!child) 5802 return false; 5803 if (child->fParent != NULL) { 5804 debugger("View already belongs to someone else"); 5805 return false; 5806 } 5807 if (before != NULL && before->fParent != this) { 5808 debugger("Invalid before view"); 5809 return false; 5810 } 5811 5812 if (before != NULL) { 5813 // add view before this one 5814 child->fNextSibling = before; 5815 child->fPreviousSibling = before->fPreviousSibling; 5816 if (child->fPreviousSibling != NULL) 5817 child->fPreviousSibling->fNextSibling = child; 5818 5819 before->fPreviousSibling = child; 5820 if (fFirstChild == before) 5821 fFirstChild = child; 5822 } else { 5823 // add view to the end of the list 5824 BView* last = fFirstChild; 5825 while (last != NULL && last->fNextSibling != NULL) { 5826 last = last->fNextSibling; 5827 } 5828 5829 if (last != NULL) { 5830 last->fNextSibling = child; 5831 child->fPreviousSibling = last; 5832 } else { 5833 fFirstChild = child; 5834 child->fPreviousSibling = NULL; 5835 } 5836 5837 child->fNextSibling = NULL; 5838 } 5839 5840 child->fParent = this; 5841 return true; 5842 } 5843 5844 5845 /*! \brief Creates the server counterpart of this view. 5846 This is only done for views that are part of the view hierarchy, ie. when 5847 they are attached to a window. 5848 RemoveSelf() deletes the server object again. 5849 */ 5850 bool 5851 BView::_CreateSelf() 5852 { 5853 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 5854 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 5855 // of the view and its parent are both send to the server. 5856 5857 if (fTopLevelView) 5858 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 5859 else 5860 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 5861 5862 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 5863 fOwner->fLink->AttachString(Name()); 5864 fOwner->fLink->Attach<BRect>(Frame()); 5865 fOwner->fLink->Attach<BPoint>(LeftTop()); 5866 fOwner->fLink->Attach<uint32>(ResizingMode()); 5867 fOwner->fLink->Attach<uint32>(fEventMask); 5868 fOwner->fLink->Attach<uint32>(fEventOptions); 5869 fOwner->fLink->Attach<uint32>(Flags()); 5870 fOwner->fLink->Attach<bool>(IsHidden(this)); 5871 fOwner->fLink->Attach<rgb_color>(fState->view_color); 5872 if (fTopLevelView) 5873 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 5874 else 5875 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 5876 fOwner->fLink->Flush(); 5877 5878 _CheckOwnerLockAndSwitchCurrent(); 5879 fState->UpdateServerState(*fOwner->fLink); 5880 5881 // we create all its children, too 5882 5883 for (BView* child = fFirstChild; child != NULL; 5884 child = child->fNextSibling) { 5885 child->_CreateSelf(); 5886 } 5887 5888 fOwner->fLink->Flush(); 5889 return true; 5890 } 5891 5892 5893 /*! Sets the new view position. 5894 It doesn't contact the server, though - the only case where this 5895 is called outside of MoveTo() is as reaction of moving a view 5896 in the server (a.k.a. B_WINDOW_RESIZED). 5897 It also calls the BView's FrameMoved() hook. 5898 */ 5899 void 5900 BView::_MoveTo(int32 x, int32 y) 5901 { 5902 fParentOffset.Set(x, y); 5903 5904 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 5905 BMessage moved(B_VIEW_MOVED); 5906 moved.AddInt64("when", system_time()); 5907 moved.AddPoint("where", BPoint(x, y)); 5908 5909 BMessenger target(this); 5910 target.SendMessage(&moved); 5911 } 5912 } 5913 5914 5915 /*! Computes the actual new frame size and recalculates the size of 5916 the children as well. 5917 It doesn't contact the server, though - the only case where this 5918 is called outside of ResizeBy() is as reaction of resizing a view 5919 in the server (a.k.a. B_WINDOW_RESIZED). 5920 It also calls the BView's FrameResized() hook. 5921 */ 5922 void 5923 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 5924 { 5925 fBounds.right += deltaWidth; 5926 fBounds.bottom += deltaHeight; 5927 5928 if (Window() == NULL) { 5929 // we're not supposed to exercise the resizing code in case 5930 // we haven't been attached to a window yet 5931 return; 5932 } 5933 5934 // layout the children 5935 if ((fFlags & B_SUPPORTS_LAYOUT) != 0) { 5936 Relayout(); 5937 } else { 5938 for (BView* child = fFirstChild; child; child = child->fNextSibling) 5939 child->_ParentResizedBy(deltaWidth, deltaHeight); 5940 } 5941 5942 if (fFlags & B_FRAME_EVENTS) { 5943 BMessage resized(B_VIEW_RESIZED); 5944 resized.AddInt64("when", system_time()); 5945 resized.AddInt32("width", fBounds.IntegerWidth()); 5946 resized.AddInt32("height", fBounds.IntegerHeight()); 5947 5948 BMessenger target(this); 5949 target.SendMessage(&resized); 5950 } 5951 } 5952 5953 5954 /*! Relayouts the view according to its resizing mode. */ 5955 void 5956 BView::_ParentResizedBy(int32 x, int32 y) 5957 { 5958 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5959 BRect newFrame = Frame(); 5960 5961 // follow with left side 5962 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5963 newFrame.left += x; 5964 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5965 newFrame.left += x / 2; 5966 5967 // follow with right side 5968 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5969 newFrame.right += x; 5970 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5971 newFrame.right += x / 2; 5972 5973 // follow with top side 5974 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5975 newFrame.top += y; 5976 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5977 newFrame.top += y / 2; 5978 5979 // follow with bottom side 5980 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5981 newFrame.bottom += y; 5982 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5983 newFrame.bottom += y / 2; 5984 5985 if (newFrame.LeftTop() != fParentOffset) { 5986 // move view 5987 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5988 } 5989 5990 if (newFrame != Frame()) { 5991 // resize view 5992 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5993 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5994 _ResizeBy(widthDiff, heightDiff); 5995 } 5996 } 5997 5998 5999 void 6000 BView::_Activate(bool active) 6001 { 6002 WindowActivated(active); 6003 6004 for (BView* child = fFirstChild; child != NULL; 6005 child = child->fNextSibling) { 6006 child->_Activate(active); 6007 } 6008 } 6009 6010 6011 void 6012 BView::_Attach() 6013 { 6014 if (fOwner != NULL) { 6015 // unmask state flags to force [re]syncing with the app_server 6016 fState->valid_flags &= ~(B_VIEW_WHICH_VIEW_COLOR_BIT 6017 | B_VIEW_WHICH_LOW_COLOR_BIT | B_VIEW_WHICH_HIGH_COLOR_BIT); 6018 6019 if (fState->which_view_color != B_NO_COLOR) 6020 SetViewUIColor(fState->which_view_color, 6021 fState->which_view_color_tint); 6022 6023 if (fState->which_high_color != B_NO_COLOR) 6024 SetHighUIColor(fState->which_high_color, 6025 fState->which_high_color_tint); 6026 6027 if (fState->which_low_color != B_NO_COLOR) 6028 SetLowUIColor(fState->which_low_color, 6029 fState->which_low_color_tint); 6030 } 6031 6032 AttachedToWindow(); 6033 6034 fAttached = true; 6035 6036 // after giving the view a chance to do this itself, 6037 // check for the B_PULSE_NEEDED flag and make sure the 6038 // window set's up the pulse messaging 6039 if (fOwner) { 6040 if (fFlags & B_PULSE_NEEDED) { 6041 _CheckLock(); 6042 if (fOwner->fPulseRunner == NULL) 6043 fOwner->SetPulseRate(fOwner->PulseRate()); 6044 } 6045 6046 if (!fOwner->IsHidden()) 6047 Invalidate(); 6048 } 6049 6050 for (BView* child = fFirstChild; child != NULL; 6051 child = child->fNextSibling) { 6052 // we need to check for fAttached as new views could have been 6053 // added in AttachedToWindow() - and those are already attached 6054 if (!child->fAttached) 6055 child->_Attach(); 6056 } 6057 6058 AllAttached(); 6059 } 6060 6061 6062 void 6063 BView::_ColorsUpdated(BMessage* message) 6064 { 6065 if (fTopLevelView 6066 && fLayoutData->fLayout != NULL 6067 && !fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)) { 6068 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 6069 SetHighUIColor(B_PANEL_TEXT_COLOR); 6070 } 6071 6072 rgb_color color; 6073 6074 const char* colorName = ui_color_name(fState->which_view_color); 6075 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) { 6076 fState->view_color = tint_color(color, fState->which_view_color_tint); 6077 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 6078 } 6079 6080 colorName = ui_color_name(fState->which_low_color); 6081 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) { 6082 fState->low_color = tint_color(color, fState->which_low_color_tint); 6083 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 6084 } 6085 6086 colorName = ui_color_name(fState->which_high_color); 6087 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) { 6088 fState->high_color = tint_color(color, fState->which_high_color_tint); 6089 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 6090 } 6091 6092 MessageReceived(message); 6093 6094 for (BView* child = fFirstChild; child != NULL; 6095 child = child->fNextSibling) 6096 child->_ColorsUpdated(message); 6097 6098 Invalidate(); 6099 } 6100 6101 6102 void 6103 BView::_Detach() 6104 { 6105 DetachedFromWindow(); 6106 fAttached = false; 6107 6108 for (BView* child = fFirstChild; child != NULL; 6109 child = child->fNextSibling) { 6110 child->_Detach(); 6111 } 6112 6113 AllDetached(); 6114 6115 if (fOwner) { 6116 _CheckLock(); 6117 6118 if (!fOwner->IsHidden()) 6119 Invalidate(); 6120 6121 // make sure our owner doesn't need us anymore 6122 6123 if (fOwner->CurrentFocus() == this) { 6124 MakeFocus(false); 6125 // MakeFocus() is virtual and might not be 6126 // passing through to the BView version, 6127 // but we need to make sure at this point 6128 // that we are not the focus view anymore. 6129 if (fOwner->CurrentFocus() == this) 6130 fOwner->_SetFocus(NULL, true); 6131 } 6132 6133 if (fOwner->fDefaultButton == this) 6134 fOwner->SetDefaultButton(NULL); 6135 6136 if (fOwner->fKeyMenuBar == this) 6137 fOwner->fKeyMenuBar = NULL; 6138 6139 if (fOwner->fLastMouseMovedView == this) 6140 fOwner->fLastMouseMovedView = NULL; 6141 6142 if (fOwner->fLastViewToken == _get_object_token_(this)) 6143 fOwner->fLastViewToken = B_NULL_TOKEN; 6144 6145 _SetOwner(NULL); 6146 } 6147 } 6148 6149 6150 void 6151 BView::_Draw(BRect updateRect) 6152 { 6153 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 6154 return; 6155 6156 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 6157 // -> View is simply not drawn at all 6158 6159 _SwitchServerCurrentView(); 6160 6161 ConvertFromScreen(&updateRect); 6162 6163 // TODO: make states robust (the hook implementation could 6164 // mess things up if it uses non-matching Push- and PopState(), 6165 // we would not be guaranteed to still have the same state on 6166 // the stack after having called Draw()) 6167 PushState(); 6168 Draw(updateRect); 6169 PopState(); 6170 Flush(); 6171 } 6172 6173 6174 void 6175 BView::_DrawAfterChildren(BRect updateRect) 6176 { 6177 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 6178 || !(Flags() & B_DRAW_ON_CHILDREN)) 6179 return; 6180 6181 _SwitchServerCurrentView(); 6182 6183 ConvertFromScreen(&updateRect); 6184 6185 // TODO: make states robust (see above) 6186 PushState(); 6187 DrawAfterChildren(updateRect); 6188 PopState(); 6189 Flush(); 6190 } 6191 6192 6193 void 6194 BView::_FontsUpdated(BMessage* message) 6195 { 6196 MessageReceived(message); 6197 6198 for (BView* child = fFirstChild; child != NULL; 6199 child = child->fNextSibling) { 6200 child->_FontsUpdated(message); 6201 } 6202 } 6203 6204 6205 void 6206 BView::_Pulse() 6207 { 6208 if ((Flags() & B_PULSE_NEEDED) != 0) 6209 Pulse(); 6210 6211 for (BView* child = fFirstChild; child != NULL; 6212 child = child->fNextSibling) { 6213 child->_Pulse(); 6214 } 6215 } 6216 6217 6218 void 6219 BView::_UpdateStateForRemove() 6220 { 6221 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 6222 if (!_CheckOwnerLockAndSwitchCurrent()) 6223 return; 6224 6225 fState->UpdateFrom(*fOwner->fLink); 6226 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 6227 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 6228 // 6229 // status_t code; 6230 // if (fOwner->fLink->FlushWithReply(code) == B_OK 6231 // && code == B_OK) { 6232 // fOwner->fLink->Read<BPoint>(&fParentOffset); 6233 // fOwner->fLink->Read<BRect>(&fBounds); 6234 // fState->valid_flags |= B_VIEW_FRAME_BIT; 6235 // } 6236 // } 6237 6238 // update children as well 6239 6240 for (BView* child = fFirstChild; child != NULL; 6241 child = child->fNextSibling) { 6242 if (child->fOwner) 6243 child->_UpdateStateForRemove(); 6244 } 6245 } 6246 6247 6248 inline void 6249 BView::_UpdatePattern(::pattern pattern) 6250 { 6251 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 6252 return; 6253 6254 if (fOwner) { 6255 _CheckLockAndSwitchCurrent(); 6256 6257 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 6258 fOwner->fLink->Attach< ::pattern>(pattern); 6259 6260 fState->valid_flags |= B_VIEW_PATTERN_BIT; 6261 } 6262 6263 fState->pattern = pattern; 6264 } 6265 6266 6267 void 6268 BView::_FlushIfNotInTransaction() 6269 { 6270 if (!fOwner->fInTransaction) { 6271 fOwner->Flush(); 6272 } 6273 } 6274 6275 6276 BShelf* 6277 BView::_Shelf() const 6278 { 6279 return fShelf; 6280 } 6281 6282 6283 void 6284 BView::_SetShelf(BShelf* shelf) 6285 { 6286 if (fShelf != NULL && fOwner != NULL) 6287 fOwner->RemoveHandler(fShelf); 6288 6289 fShelf = shelf; 6290 6291 if (fShelf != NULL && fOwner != NULL) 6292 fOwner->AddHandler(fShelf); 6293 } 6294 6295 6296 status_t 6297 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 6298 uint32 followFlags, uint32 options) 6299 { 6300 if (!_CheckOwnerLockAndSwitchCurrent()) 6301 return B_ERROR; 6302 6303 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 6304 6305 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 6306 fOwner->fLink->Attach<int32>(serverToken); 6307 fOwner->fLink->Attach<BRect>(srcRect); 6308 fOwner->fLink->Attach<BRect>(dstRect); 6309 fOwner->fLink->Attach<int32>(followFlags); 6310 fOwner->fLink->Attach<int32>(options); 6311 6312 status_t status = B_ERROR; 6313 fOwner->fLink->FlushWithReply(status); 6314 6315 return status; 6316 } 6317 6318 6319 bool 6320 BView::_CheckOwnerLockAndSwitchCurrent() const 6321 { 6322 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name())); 6323 6324 if (fOwner == NULL) { 6325 debugger("View method requires owner and doesn't have one."); 6326 return false; 6327 } 6328 6329 _CheckLockAndSwitchCurrent(); 6330 6331 return true; 6332 } 6333 6334 6335 bool 6336 BView::_CheckOwnerLock() const 6337 { 6338 if (fOwner) { 6339 fOwner->check_lock(); 6340 return true; 6341 } else { 6342 debugger("View method requires owner and doesn't have one."); 6343 return false; 6344 } 6345 } 6346 6347 6348 void 6349 BView::_CheckLockAndSwitchCurrent() const 6350 { 6351 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name())); 6352 6353 if (!fOwner) 6354 return; 6355 6356 fOwner->check_lock(); 6357 6358 _SwitchServerCurrentView(); 6359 } 6360 6361 6362 void 6363 BView::_CheckLock() const 6364 { 6365 if (fOwner) 6366 fOwner->check_lock(); 6367 } 6368 6369 6370 void 6371 BView::_SwitchServerCurrentView() const 6372 { 6373 int32 serverToken = _get_object_token_(this); 6374 6375 if (fOwner->fLastViewToken != serverToken) { 6376 STRACE(("contacting app_server... sending token: %" B_PRId32 "\n", 6377 serverToken)); 6378 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 6379 fOwner->fLink->Attach<int32>(serverToken); 6380 6381 fOwner->fLastViewToken = serverToken; 6382 } 6383 } 6384 6385 6386 status_t 6387 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta) 6388 { 6389 if (scrollBar == NULL || delta == 0.0f) 6390 return B_BAD_VALUE; 6391 6392 float smallStep; 6393 float largeStep; 6394 scrollBar->GetSteps(&smallStep, &largeStep); 6395 6396 // pressing the shift key scrolls faster (following the pseudo-standard set 6397 // by other desktop environments). 6398 if ((modifiers() & B_SHIFT_KEY) != 0) 6399 delta *= largeStep; 6400 else 6401 delta *= smallStep * 3; 6402 6403 scrollBar->SetValue(scrollBar->Value() + delta); 6404 6405 return B_OK; 6406 } 6407 6408 6409 #if __GNUC__ == 2 6410 6411 6412 extern "C" void 6413 _ReservedView1__5BView(BView* view, BRect rect) 6414 { 6415 view->BView::DrawAfterChildren(rect); 6416 } 6417 6418 6419 extern "C" void 6420 _ReservedView2__5BView(BView* view) 6421 { 6422 // MinSize() 6423 perform_data_min_size data; 6424 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 6425 } 6426 6427 6428 extern "C" void 6429 _ReservedView3__5BView(BView* view) 6430 { 6431 // MaxSize() 6432 perform_data_max_size data; 6433 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 6434 } 6435 6436 6437 extern "C" BSize 6438 _ReservedView4__5BView(BView* view) 6439 { 6440 // PreferredSize() 6441 perform_data_preferred_size data; 6442 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 6443 return data.return_value; 6444 } 6445 6446 6447 extern "C" BAlignment 6448 _ReservedView5__5BView(BView* view) 6449 { 6450 // LayoutAlignment() 6451 perform_data_layout_alignment data; 6452 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 6453 return data.return_value; 6454 } 6455 6456 6457 extern "C" bool 6458 _ReservedView6__5BView(BView* view) 6459 { 6460 // HasHeightForWidth() 6461 perform_data_has_height_for_width data; 6462 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 6463 return data.return_value; 6464 } 6465 6466 6467 extern "C" void 6468 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 6469 float* preferred) 6470 { 6471 // GetHeightForWidth() 6472 perform_data_get_height_for_width data; 6473 data.width = width; 6474 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 6475 if (min != NULL) 6476 *min = data.min; 6477 if (max != NULL) 6478 *max = data.max; 6479 if (preferred != NULL) 6480 *preferred = data.preferred; 6481 } 6482 6483 6484 extern "C" void 6485 _ReservedView8__5BView(BView* view, BLayout* layout) 6486 { 6487 // SetLayout() 6488 perform_data_set_layout data; 6489 data.layout = layout; 6490 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 6491 } 6492 6493 6494 extern "C" void 6495 _ReservedView9__5BView(BView* view, bool descendants) 6496 { 6497 // LayoutInvalidated() 6498 perform_data_layout_invalidated data; 6499 data.descendants = descendants; 6500 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 6501 } 6502 6503 6504 extern "C" void 6505 _ReservedView10__5BView(BView* view) 6506 { 6507 // DoLayout() 6508 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 6509 } 6510 6511 6512 #endif // __GNUC__ == 2 6513 6514 6515 extern "C" bool 6516 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)( 6517 BView* view, BPoint point, BToolTip** _toolTip) 6518 { 6519 // GetToolTipAt() 6520 perform_data_get_tool_tip_at data; 6521 data.point = point; 6522 data.tool_tip = _toolTip; 6523 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 6524 return data.return_value; 6525 } 6526 6527 6528 extern "C" void 6529 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)( 6530 BView* view) 6531 { 6532 // LayoutChanged(); 6533 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL); 6534 } 6535 6536 6537 void BView::_ReservedView13() {} 6538 void BView::_ReservedView14() {} 6539 void BView::_ReservedView15() {} 6540 void BView::_ReservedView16() {} 6541 6542 6543 BView::BView(const BView& other) 6544 : 6545 BHandler() 6546 { 6547 // this is private and not functional, but exported 6548 } 6549 6550 6551 BView& 6552 BView::operator=(const BView& other) 6553 { 6554 // this is private and not functional, but exported 6555 return *this; 6556 } 6557 6558 6559 void 6560 BView::_PrintToStream() 6561 { 6562 printf("BView::_PrintToStream()\n"); 6563 printf("\tName: %s\n" 6564 "\tParent: %s\n" 6565 "\tFirstChild: %s\n" 6566 "\tNextSibling: %s\n" 6567 "\tPrevSibling: %s\n" 6568 "\tOwner(Window): %s\n" 6569 "\tToken: %" B_PRId32 "\n" 6570 "\tFlags: %" B_PRId32 "\n" 6571 "\tView origin: (%f,%f)\n" 6572 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 6573 "\tShow level: %d\n" 6574 "\tTopView?: %s\n" 6575 "\tBPicture: %s\n" 6576 "\tVertical Scrollbar %s\n" 6577 "\tHorizontal Scrollbar %s\n" 6578 "\tIs Printing?: %s\n" 6579 "\tShelf?: %s\n" 6580 "\tEventMask: %" B_PRId32 "\n" 6581 "\tEventOptions: %" B_PRId32 "\n", 6582 Name(), 6583 fParent ? fParent->Name() : "NULL", 6584 fFirstChild ? fFirstChild->Name() : "NULL", 6585 fNextSibling ? fNextSibling->Name() : "NULL", 6586 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 6587 fOwner ? fOwner->Name() : "NULL", 6588 _get_object_token_(this), 6589 fFlags, 6590 fParentOffset.x, fParentOffset.y, 6591 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 6592 fShowLevel, 6593 fTopLevelView ? "YES" : "NO", 6594 fCurrentPicture? "YES" : "NULL", 6595 fVerScroller? "YES" : "NULL", 6596 fHorScroller? "YES" : "NULL", 6597 fIsPrinting? "YES" : "NO", 6598 fShelf? "YES" : "NO", 6599 fEventMask, 6600 fEventOptions); 6601 6602 printf("\tState status:\n" 6603 "\t\tLocalCoordianteSystem: (%f,%f)\n" 6604 "\t\tPenLocation: (%f,%f)\n" 6605 "\t\tPenSize: %f\n" 6606 "\t\tHighColor: [%d,%d,%d,%d]\n" 6607 "\t\tLowColor: [%d,%d,%d,%d]\n" 6608 "\t\tViewColor: [%d,%d,%d,%d]\n" 6609 "\t\tPattern: %" B_PRIx64 "\n" 6610 "\t\tDrawingMode: %d\n" 6611 "\t\tLineJoinMode: %d\n" 6612 "\t\tLineCapMode: %d\n" 6613 "\t\tMiterLimit: %f\n" 6614 "\t\tAlphaSource: %d\n" 6615 "\t\tAlphaFuntion: %d\n" 6616 "\t\tScale: %f\n" 6617 "\t\t(Print)FontAliasing: %s\n" 6618 "\t\tFont Info:\n", 6619 fState->origin.x, fState->origin.y, 6620 fState->pen_location.x, fState->pen_location.y, 6621 fState->pen_size, 6622 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 6623 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 6624 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 6625 *((uint64*)&(fState->pattern)), 6626 fState->drawing_mode, 6627 fState->line_join, 6628 fState->line_cap, 6629 fState->miter_limit, 6630 fState->alpha_source_mode, 6631 fState->alpha_function_mode, 6632 fState->scale, 6633 fState->font_aliasing? "YES" : "NO"); 6634 6635 fState->font.PrintToStream(); 6636 6637 // TODO: also print the line array. 6638 } 6639 6640 6641 void 6642 BView::_PrintTree() 6643 { 6644 int32 spaces = 2; 6645 BView* c = fFirstChild; //c = short for: current 6646 printf( "'%s'\n", Name() ); 6647 if (c != NULL) { 6648 while(true) { 6649 // action block 6650 { 6651 for (int i = 0; i < spaces; i++) 6652 printf(" "); 6653 6654 printf( "'%s'\n", c->Name() ); 6655 } 6656 6657 // go deep 6658 if (c->fFirstChild) { 6659 c = c->fFirstChild; 6660 spaces += 2; 6661 } else { 6662 // go right 6663 if (c->fNextSibling) { 6664 c = c->fNextSibling; 6665 } else { 6666 // go up 6667 while (!c->fParent->fNextSibling && c->fParent != this) { 6668 c = c->fParent; 6669 spaces -= 2; 6670 } 6671 6672 // that enough! We've reached this view. 6673 if (c->fParent == this) 6674 break; 6675 6676 c = c->fParent->fNextSibling; 6677 spaces -= 2; 6678 } 6679 } 6680 } 6681 } 6682 } 6683 6684 6685 // #pragma mark - 6686 6687 6688 BLayoutItem* 6689 BView::Private::LayoutItemAt(int32 index) 6690 { 6691 return fView->fLayoutData->fLayoutItems.ItemAt(index); 6692 } 6693 6694 6695 int32 6696 BView::Private::CountLayoutItems() 6697 { 6698 return fView->fLayoutData->fLayoutItems.CountItems(); 6699 } 6700 6701 6702 void 6703 BView::Private::RegisterLayoutItem(BLayoutItem* item) 6704 { 6705 fView->fLayoutData->fLayoutItems.AddItem(item); 6706 } 6707 6708 6709 void 6710 BView::Private::DeregisterLayoutItem(BLayoutItem* item) 6711 { 6712 fView->fLayoutData->fLayoutItems.RemoveItem(item); 6713 } 6714 6715 6716 bool 6717 BView::Private::MinMaxValid() 6718 { 6719 return fView->fLayoutData->fMinMaxValid; 6720 } 6721 6722 6723 bool 6724 BView::Private::WillLayout() 6725 { 6726 BView::LayoutData* data = fView->fLayoutData; 6727 if (data->fLayoutInProgress) 6728 return false; 6729 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid) 6730 return true; 6731 return false; 6732 } 6733