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