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