1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered 30 trademarks of Be Incorporated in the United States and other countries. Other 31 brand product names are registered trademarks or trademarks of their respective 32 holders. 33 All rights reserved. 34 */ 35 36 37 #include "BarView.h" 38 39 #include <AppFileInfo.h> 40 #include <Bitmap.h> 41 #include <Debug.h> 42 #include <Directory.h> 43 #include <LocaleRoster.h> 44 #include <NodeInfo.h> 45 #include <Roster.h> 46 #include <Screen.h> 47 #include <String.h> 48 49 #include "icons.h" 50 #include "BarApp.h" 51 #include "BarMenuBar.h" 52 #include "BarWindow.h" 53 #include "DeskbarMenu.h" 54 #include "DeskbarUtils.h" 55 #include "ExpandoMenuBar.h" 56 #include "FSUtils.h" 57 #include "InlineScrollView.h" 58 #include "ResourceSet.h" 59 #include "StatusView.h" 60 #include "TeamMenuItem.h" 61 62 63 const int32 kDefaultRecentDocCount = 10; 64 const int32 kDefaultRecentAppCount = 10; 65 66 const int32 kMenuTrackMargin = 20; 67 const float kMinTeamItemHeight = 20.0f; 68 const float kVPad = 2.0f; 69 const float kIconPadding = 8.0f; 70 const float kScrollerDimension = 12.0f; 71 72 const uint32 kUpdateOrientation = 'UpOr'; 73 74 75 class BarViewMessageFilter : public BMessageFilter 76 { 77 public: 78 BarViewMessageFilter(TBarView* barView); 79 virtual ~BarViewMessageFilter(); 80 81 virtual filter_result Filter(BMessage* message, BHandler** target); 82 83 private: 84 TBarView* fBarView; 85 }; 86 87 88 BarViewMessageFilter::BarViewMessageFilter(TBarView* barView) 89 : 90 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 91 fBarView(barView) 92 { 93 } 94 95 96 BarViewMessageFilter::~BarViewMessageFilter() 97 { 98 } 99 100 101 filter_result 102 BarViewMessageFilter::Filter(BMessage* message, BHandler** target) 103 { 104 if (message->what == B_MOUSE_DOWN || message->what == B_MOUSE_MOVED) { 105 BPoint where = message->FindPoint("be:view_where"); 106 uint32 transit = message->FindInt32("be:transit"); 107 BMessage* dragMessage = NULL; 108 if (message->HasMessage("be:drag_message")) { 109 dragMessage = new BMessage(); 110 message->FindMessage("be:drag_message", dragMessage); 111 } 112 113 switch (message->what) { 114 case B_MOUSE_DOWN: 115 fBarView->MouseDown(where); 116 break; 117 118 case B_MOUSE_MOVED: 119 fBarView->MouseMoved(where, transit, dragMessage); 120 break; 121 } 122 123 delete dragMessage; 124 } 125 126 return B_DISPATCH_MESSAGE; 127 } 128 129 130 // #pragma mark - TBarView 131 132 133 TBarView::TBarView(BRect frame, bool vertical, bool left, bool top, 134 int32 state, float) 135 : 136 BView(frame, "BarView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), 137 fBarApp(static_cast<TBarApp*>(be_app)), 138 fBarWindow(NULL), 139 fInlineScrollView(NULL), 140 fBarMenuBar(NULL), 141 fExpandoMenuBar(NULL), 142 fTrayLocation(1), 143 fIsRaised(false), 144 fMouseDownOutside(false), 145 fVertical(vertical), 146 fTop(top), 147 fLeft(left), 148 fState(state), 149 fRefsRcvdOnly(true), 150 fDragMessage(NULL), 151 fCachedTypesList(NULL), 152 fMaxRecentDocs(kDefaultRecentDocCount), 153 fMaxRecentApps(kDefaultRecentAppCount), 154 fLastDragItem(NULL), 155 fMouseFilter(NULL), 156 fTabHeight(kMenuBarHeight) 157 { 158 // get window tab height 159 BWindow* tmpWindow = new(std::nothrow) BWindow(BRect(), NULL, 160 B_TITLED_WINDOW, 0); 161 if (tmpWindow != NULL) { 162 BMessage settings; 163 if (tmpWindow->GetDecoratorSettings(&settings) == B_OK) { 164 BRect tabRect; 165 if (settings.FindRect("tab frame", &tabRect) == B_OK) 166 fTabHeight = tabRect.Height(); 167 } 168 delete tmpWindow; 169 } 170 171 // determine the initial Be menu size 172 // (will be updated later) 173 BRect menuFrame(frame); 174 if (fVertical) 175 menuFrame.bottom = menuFrame.top + fTabHeight - 1; 176 else 177 menuFrame.bottom = menuFrame.top + TeamMenuItemHeight(); 178 179 // create and add the Be menu 180 fBarMenuBar = new TBarMenuBar(menuFrame, "BarMenuBar", this); 181 AddChild(fBarMenuBar); 182 183 // create the status tray 184 fReplicantTray = new TReplicantTray(this); 185 186 // create the resize control 187 fResizeControl = new TResizeControl(this); 188 189 // create the drag region and add the resize control 190 // and replicant tray to it 191 fDragRegion = new TDragRegion(this, fReplicantTray); 192 fDragRegion->AddChild(fResizeControl); 193 fDragRegion->AddChild(fReplicantTray); 194 195 // Add the drag region 196 if (fTrayLocation != 0) 197 AddChild(fDragRegion); 198 199 // create and add the expando menu bar 200 fExpandoMenuBar = new TExpandoMenuBar( 201 fVertical ? B_ITEMS_IN_COLUMN : B_ITEMS_IN_ROW, this); 202 fInlineScrollView = new TInlineScrollView(fExpandoMenuBar, 203 fVertical ? B_VERTICAL : B_HORIZONTAL); 204 AddChild(fInlineScrollView); 205 206 // hide the expando menu bar in mini-mode 207 if (state == kMiniState) 208 fInlineScrollView->Hide(); 209 210 // if auto-hide is on and we're not already hidden, hide ourself 211 if (fBarApp->Settings()->autoHide && !IsHidden()) 212 Hide(); 213 } 214 215 216 TBarView::~TBarView() 217 { 218 delete fDragMessage; 219 delete fCachedTypesList; 220 delete fBarMenuBar; 221 } 222 223 224 void 225 TBarView::AttachedToWindow() 226 { 227 BView::AttachedToWindow(); 228 229 fBarWindow = dynamic_cast<TBarWindow*>(Window()); 230 231 SetViewUIColor(B_MENU_BACKGROUND_COLOR); 232 SetFont(be_plain_font); 233 234 fMouseFilter = new BarViewMessageFilter(this); 235 Window()->AddCommonFilter(fMouseFilter); 236 237 fTrackingHookData.fTrackingHook = MenuTrackingHook; 238 fTrackingHookData.fTarget = BMessenger(this); 239 fTrackingHookData.fDragMessage = new BMessage(B_REFS_RECEIVED); 240 241 if (!fVertical) 242 UpdatePlacement(); // update MenuBarHeight 243 } 244 245 246 void 247 TBarView::DetachedFromWindow() 248 { 249 Window()->RemoveCommonFilter(fMouseFilter); 250 delete fMouseFilter; 251 fMouseFilter = NULL; 252 delete fTrackingHookData.fDragMessage; 253 fTrackingHookData.fDragMessage = NULL; 254 } 255 256 257 void 258 TBarView::Draw(BRect) 259 { 260 BRect bounds(Bounds()); 261 262 rgb_color hilite = tint_color(ViewColor(), B_DARKEN_1_TINT); 263 264 SetHighColor(hilite); 265 if (AcrossTop()) 266 StrokeLine(bounds.LeftBottom(), bounds.RightBottom()); 267 else if (AcrossBottom()) 268 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 269 270 if (fVertical && fState == kExpandoState) { 271 SetHighColor(hilite); 272 BRect frame(fExpandoMenuBar->Frame()); 273 StrokeLine(BPoint(frame.left, frame.top - 1), 274 BPoint(frame.right, frame.top -1)); 275 } 276 } 277 278 279 void 280 TBarView::MessageReceived(BMessage* message) 281 { 282 switch (message->what) { 283 case B_LOCALE_CHANGED: 284 case kRealignReplicants: 285 case kShowHideTime: 286 case kShowSeconds: 287 case kShowDayOfWeek: 288 case kShowTimeZone: 289 case kGetClockSettings: 290 fReplicantTray->MessageReceived(message); 291 break; 292 293 case B_REFS_RECEIVED: 294 // received when an item is selected during DnD 295 // message is targeted here from Be menu 296 HandleDeskbarMenu(message); 297 break; 298 299 case B_ARCHIVED_OBJECT: 300 { 301 // this message has been retargeted to here 302 // instead of directly to the replicant tray 303 // so that I can follow the common pathway 304 // for adding icons to the tray 305 int32 id; 306 if (AddItem(message, B_DESKBAR_TRAY, &id) == B_OK) 307 Looper()->DetachCurrentMessage(); 308 break; 309 } 310 311 case kUpdateOrientation: 312 { 313 _ChangeState(message); 314 break; 315 } 316 317 default: 318 BView::MessageReceived(message); 319 } 320 } 321 322 323 void 324 TBarView::MouseDown(BPoint where) 325 { 326 // exit if menu or calendar is showing 327 if (fBarWindow == NULL || fBarWindow->IsShowingMenu() 328 || fReplicantTray->fTime->IsShowingCalendar()) { 329 return BView::MouseDown(where); 330 } 331 332 // where is relative to status tray while mouse is over it so pull 333 // the screen point out of the message instead 334 BMessage* currentMessage = Window()->CurrentMessage(); 335 if (currentMessage == NULL) 336 return BView::MouseDown(where); 337 338 desk_settings* settings = fBarApp->Settings(); 339 bool alwaysOnTop = settings->alwaysOnTop; 340 bool autoRaise = settings->autoRaise; 341 bool autoHide = settings->autoHide; 342 343 BPoint whereScreen = currentMessage->GetPoint("screen_where", 344 ConvertToScreen(where)); 345 fMouseDownOutside = !Window()->Frame().Contains(whereScreen); 346 347 if (fMouseDownOutside) { 348 // lower Deskbar 349 if (!alwaysOnTop && autoRaise && fIsRaised) 350 RaiseDeskbar(false); 351 352 // hide Deskbar 353 if (autoHide && !IsHidden()) 354 HideDeskbar(true); 355 } else { 356 // Activate Deskbar on click only if not in auto-raise mode and not 357 // in always-on-top mode. In auto-raise mode click activates through 358 // foreground windows, which we don't want. We don't ever want to 359 // activate Deskbar in always-on-top mode because Deskbar is 360 // already on top and we don't want to change the active window. 361 if (!autoRaise && !alwaysOnTop) 362 Window()->Activate(true); 363 364 if ((modifiers() & (B_CONTROL_KEY | B_COMMAND_KEY | B_OPTION_KEY 365 | B_SHIFT_KEY)) == (B_CONTROL_KEY | B_COMMAND_KEY)) { 366 // The window key was pressed - enter dragging code 367 fDragRegion->MouseDown(fDragRegion->DragRegion().LeftTop()); 368 return BView::MouseDown(where); 369 } 370 } 371 372 BView::MouseDown(where); 373 } 374 375 376 void 377 TBarView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 378 { 379 if (fDragRegion->IsDragging()) 380 return fDragRegion->MouseMoved(where, transit, dragMessage); 381 else if (fResizeControl->IsResizing()) 382 return BView::MouseMoved(where, transit, dragMessage); 383 384 desk_settings* settings = fBarApp->Settings(); 385 bool alwaysOnTop = settings->alwaysOnTop; 386 bool autoRaise = settings->autoRaise; 387 bool autoHide = settings->autoHide; 388 389 // exit if both auto-raise and auto-hide are off 390 if (!autoRaise && !autoHide) { 391 // turn off mouse tracking 392 SetEventMask(0); 393 394 return BView::MouseMoved(where, transit, dragMessage); 395 } else if (EventMask() != B_POINTER_EVENTS) { 396 // track mouse outside view 397 SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 398 } 399 400 // exit if menu or calendar is showing 401 if (fBarWindow == NULL || fBarWindow->IsShowingMenu() 402 || fReplicantTray->fTime->IsShowingCalendar()) { 403 return BView::MouseMoved(where, transit, dragMessage); 404 } 405 406 // where is relative to status tray while mouse is over it so pull 407 // the screen point out of the message instead 408 BMessage* currentMessage = Window()->CurrentMessage(); 409 if (currentMessage == NULL) 410 return BView::MouseMoved(where, transit, dragMessage); 411 412 BPoint whereScreen = currentMessage->GetPoint("screen_where", 413 ConvertToScreen(where)); 414 BRect screenFrame = (BScreen(Window())).Frame(); 415 bool onScreenEdge = whereScreen.x == screenFrame.left 416 || whereScreen.x == screenFrame.right 417 || whereScreen.y == screenFrame.top 418 || whereScreen.y == screenFrame.bottom; 419 420 // Auto-Raise and Auto-Hide 421 if (!Window()->Frame().Contains(whereScreen)) { 422 // lower Deskbar 423 if (!alwaysOnTop && autoRaise && fIsRaised && !fMouseDownOutside) 424 RaiseDeskbar(false); 425 426 // check if cursor to bar distance is below threshold 427 BRect preventHideArea = Window()->Frame().InsetByCopy( 428 -kMaxPreventHidingDist, -kMaxPreventHidingDist); 429 if (!preventHideArea.Contains(whereScreen) 430 && autoHide && !IsHidden()) { 431 // hide Deskbar 432 HideDeskbar(true); 433 } 434 } else if (onScreenEdge) { 435 // cursor is on a screen edge within the window frame 436 437 // raise Deskbar 438 if (!alwaysOnTop && autoRaise && !fIsRaised && !fMouseDownOutside) 439 RaiseDeskbar(true); 440 441 // show Deskbar 442 if (autoHide && IsHidden()) 443 HideDeskbar(false); 444 } 445 446 BView::MouseMoved(where, transit, dragMessage); 447 } 448 449 450 void 451 TBarView::MouseUp(BPoint where) 452 { 453 fMouseDownOutside = false; 454 455 BView::MouseUp(where); 456 } 457 458 459 void 460 TBarView::PlaceDeskbarMenu() 461 { 462 float width = 0; 463 float height = 0; 464 465 // Calculate the size of the deskbar menu 466 BRect menuFrame(Bounds()); 467 if (fVertical) { 468 width = static_cast<TBarApp*>(be_app)->Settings()->width; 469 height = fTabHeight; 470 } else { 471 // horizontal 472 if (fState == kMiniState) { 473 width = gMinimumWindowWidth; 474 height = std::max(fTabHeight, 475 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter); 476 } else { 477 width = gMinimumWindowWidth / 2 + kIconPadding; 478 height = std::max(TeamMenuItemHeight(), 479 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter); 480 } 481 } 482 menuFrame.bottom = menuFrame.top + height; 483 484 if (fBarMenuBar == NULL) { 485 // create the Be menu 486 fBarMenuBar = new TBarMenuBar(menuFrame, "BarMenuBar", this); 487 AddChild(fBarMenuBar); 488 } else 489 fBarMenuBar->SmartResize(-1, -1); 490 491 if (fState == kMiniState) { 492 // vertical or horizontal mini 493 fBarMenuBar->RemoveSeperatorItem(); 494 fBarMenuBar->AddTeamMenu(); 495 } else if (fVertical) { 496 fBarMenuBar->RemoveSeperatorItem(); 497 fBarMenuBar->RemoveTeamMenu(); 498 } else { 499 fBarMenuBar->RemoveTeamMenu(); 500 fBarMenuBar->AddSeparatorItem(); 501 } 502 503 fBarMenuBar->SmartResize(width, height); 504 fBarMenuBar->MoveTo(B_ORIGIN); 505 } 506 507 508 void 509 TBarView::PlaceTray(bool vertSwap, bool leftSwap) 510 { 511 BPoint statusLoc; 512 if (fTrayLocation == 0) { 513 // no replicant tray mode, not used 514 if (!fReplicantTray->IsHidden()) 515 fReplicantTray->Hide(); 516 return; 517 } else if (fReplicantTray->IsHidden()) 518 fReplicantTray->Show(); 519 520 fReplicantTray->RealignReplicants(); 521 fDragRegion->ResizeToPreferred(); 522 // also resizes replicant tray 523 524 if (fVertical) { 525 if (fResizeControl->IsHidden()) 526 fResizeControl->Show(); 527 528 if (fLeft) { 529 // move replicant tray past dragger width on left 530 // also down 1px so it won't cover the border 531 fReplicantTray->MoveTo(kDragWidth + kGutter, kGutter); 532 533 // shrink width by same amount 534 fReplicantTray->ResizeBy(-(kDragWidth + kGutter), 0); 535 } else { 536 // move replicant tray down 1px so it won't cover the border 537 fReplicantTray->MoveTo(0, kGutter); 538 } 539 540 statusLoc.x = 0; 541 statusLoc.y = fBarMenuBar->Frame().bottom + 1; 542 } else { 543 // horizontal 544 if (fState == kMiniState) { 545 // horizontal mini 546 statusLoc.x = fLeft ? fBarMenuBar->Frame().right + 1 : 0; 547 statusLoc.y = 0; 548 549 // move past dragger and top border 550 // and make room for the top and bottom borders 551 fReplicantTray->MoveTo(fLeft ? kDragWidth : 0, kGutter); 552 fReplicantTray->ResizeBy(0, -4); 553 } else { 554 // move tray right and down to not cover border, resize by same 555 fReplicantTray->MoveTo(2, 0); 556 fReplicantTray->ResizeBy(-2, 0); 557 BRect screenFrame = (BScreen(Window())).Frame(); 558 statusLoc.x = screenFrame.right - fDragRegion->Bounds().Width(); 559 statusLoc.y = 0; 560 } 561 } 562 563 fDragRegion->MoveTo(statusLoc); 564 565 // make room for top and bottom border 566 fResizeControl->ResizeTo(kDragWidth, fDragRegion->Bounds().Height() - 2); 567 568 if (fVertical) { 569 // move resize control into place based on width setting 570 fResizeControl->MoveTo( 571 fLeft ? fBarApp->Settings()->width - kDragWidth : 0, 1); 572 if (fResizeControl->IsHidden()) 573 fResizeControl->Show(); 574 } else { 575 // hide resize control 576 if (!fResizeControl->IsHidden()) 577 fResizeControl->Hide(); 578 } 579 580 fDragRegion->Invalidate(); 581 } 582 583 584 void 585 TBarView::PlaceApplicationBar() 586 { 587 BRect screenFrame = (BScreen(Window())).Frame(); 588 if (fState == kMiniState) { 589 if (!fInlineScrollView->IsHidden()) 590 fInlineScrollView->Hide(); 591 592 SizeWindow(screenFrame); 593 PositionWindow(screenFrame); 594 Window()->UpdateIfNeeded(); 595 if (!fVertical) { 596 // move the menu bar into place after the window has been resized 597 // based on replicant tray 598 fBarMenuBar->MoveTo(fLeft ? 0 : fDragRegion->Bounds().right + 1, 599 0); 600 } 601 Invalidate(); 602 return; 603 } 604 605 if (fInlineScrollView->IsHidden()) 606 fInlineScrollView->Show(); 607 608 BRect expandoFrame(0, 0, 0, 0); 609 if (fVertical) { 610 // left or right 611 expandoFrame.left = fDragRegion->Frame().left; 612 expandoFrame.top = fTrayLocation != 0 ? fDragRegion->Frame().bottom + 1 613 : fBarMenuBar->Frame().bottom + 1; 614 expandoFrame.right = fBarApp->Settings()->width; 615 expandoFrame.bottom = fState == kFullState ? screenFrame.bottom 616 : Frame().bottom; 617 } else { 618 // top or bottom 619 expandoFrame.top = 0; 620 expandoFrame.bottom = TeamMenuItemHeight(); 621 expandoFrame.left = gMinimumWindowWidth / 2 + kIconPadding; 622 expandoFrame.right = screenFrame.Width(); 623 if (fTrayLocation != 0 && fDragRegion != NULL) 624 expandoFrame.right -= fDragRegion->Frame().Width() + 1; 625 } 626 627 fInlineScrollView->DetachScrollers(); 628 fInlineScrollView->MoveTo(expandoFrame.LeftTop()); 629 fInlineScrollView->ResizeTo(expandoFrame.Width(), fVertical 630 ? screenFrame.bottom - expandoFrame.top : expandoFrame.bottom); 631 fExpandoMenuBar->ResizeTo(expandoFrame.Width(), expandoFrame.Height()); 632 fExpandoMenuBar->MoveTo(0, 0); 633 fExpandoMenuBar->BuildItems(); 634 fExpandoMenuBar->SizeWindow(0); 635 } 636 637 638 void 639 TBarView::GetPreferredWindowSize(BRect screenFrame, float* width, 640 float* height) 641 { 642 float windowHeight = 0; 643 float windowWidth = 0; 644 bool setToHiddenSize = fBarApp->Settings()->autoHide && IsHidden() 645 && !fDragRegion->IsDragging(); 646 647 if (setToHiddenSize) { 648 windowHeight = kHiddenDimension; 649 650 if (fState == kExpandoState && !fVertical) { 651 // top or bottom, full 652 windowWidth = screenFrame.Width(); 653 } else 654 windowWidth = kHiddenDimension; 655 } else if (fVertical) { 656 if (fState == kFullState) { 657 // full state has minimum screen window height 658 windowHeight = std::max(screenFrame.bottom, windowHeight); 659 } else { 660 // mini or expando 661 if (fTrayLocation != 0) 662 windowHeight = fDragRegion->Frame().bottom; 663 else 664 windowHeight = fBarMenuBar->Frame().bottom; 665 666 if (fState == kExpandoState && fExpandoMenuBar != NULL) { 667 // top left or right 668 windowHeight += fExpandoMenuBar->Bounds().Height(); 669 // use Height() here, not bottom so view can be scrolled 670 } 671 } 672 673 windowWidth = fBarApp->Settings()->width; 674 } else { 675 // horizontal 676 if (fState == kMiniState) { 677 // four corners horizontal 678 windowHeight = fBarMenuBar->Frame().Height(); 679 windowWidth = fDragRegion->Frame().Width() 680 + fBarMenuBar->Frame().Width() + 1; 681 } else { 682 // horizontal top or bottom 683 windowHeight = std::max(TeamMenuItemHeight(), 684 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter); 685 windowWidth = screenFrame.Width(); 686 } 687 } 688 689 *width = windowWidth; 690 *height = windowHeight; 691 } 692 693 694 void 695 TBarView::SizeWindow(BRect screenFrame) 696 { 697 float windowWidth; 698 float windowHeight; 699 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight); 700 Window()->ResizeTo(windowWidth, windowHeight); 701 ResizeTo(windowWidth, windowHeight); 702 } 703 704 705 void 706 TBarView::PositionWindow(BRect screenFrame) 707 { 708 float windowWidth; 709 float windowHeight; 710 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight); 711 712 BPoint moveLoc(0, 0); 713 // right, expanded, mini, or full 714 if (!fLeft && (fVertical || fState == kMiniState)) 715 moveLoc.x = screenFrame.right - windowWidth; 716 717 // bottom, full 718 if (!fTop) 719 moveLoc.y = screenFrame.bottom - windowHeight; 720 721 Window()->MoveTo(moveLoc); 722 } 723 724 725 void 726 TBarView::CheckForScrolling() 727 { 728 if (fInlineScrollView == NULL && fExpandoMenuBar == NULL) 729 return; 730 731 if (fExpandoMenuBar->CheckForSizeOverrun()) 732 fInlineScrollView->AttachScrollers(); 733 else 734 fInlineScrollView->DetachScrollers(); 735 } 736 737 738 void 739 TBarView::SaveSettings() 740 { 741 desk_settings* settings = fBarApp->Settings(); 742 743 settings->vertical = fVertical; 744 settings->left = fLeft; 745 settings->top = fTop; 746 settings->state = fState; 747 748 fReplicantTray->SaveTimeSettings(); 749 } 750 751 752 void 753 TBarView::UpdatePlacement() 754 { 755 ChangeState(fState, fVertical, fLeft, fTop); 756 } 757 758 759 void 760 TBarView::ChangeState(int32 state, bool vertical, bool left, bool top, 761 bool async) 762 { 763 BMessage message(kUpdateOrientation); 764 message.AddInt32("state", state); 765 message.AddBool("vertical", vertical); 766 message.AddBool("left", left); 767 message.AddBool("top", top); 768 769 if (async) 770 BMessenger(this).SendMessage(&message); 771 else 772 _ChangeState(&message); 773 } 774 775 776 void 777 TBarView::_ChangeState(BMessage* message) 778 { 779 int32 state = message->FindInt32("state"); 780 bool vertical = message->FindBool("vertical"); 781 bool left = message->FindBool("left"); 782 bool top = message->FindBool("top"); 783 784 bool vertSwap = (fVertical != vertical); 785 bool leftSwap = (fLeft != left); 786 bool stateChanged = (fState != state); 787 788 fState = state; 789 fVertical = vertical; 790 fLeft = left; 791 fTop = top; 792 793 if (stateChanged || vertSwap) { 794 be_app->PostMessage(kStateChanged); 795 // Send a message to the preferences window to let it know to 796 // enable or disable preference items. 797 798 TBarWindow* barWindow = dynamic_cast<TBarWindow*>(Window()); 799 if (barWindow != NULL) 800 barWindow->SetSizeLimits(); 801 802 if (vertSwap && fExpandoMenuBar != NULL) { 803 if (fVertical) { 804 fInlineScrollView->SetOrientation(B_VERTICAL); 805 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_COLUMN); 806 fExpandoMenuBar->StartMonitoringWindows(); 807 } else { 808 fInlineScrollView->SetOrientation(B_HORIZONTAL); 809 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_ROW); 810 fExpandoMenuBar->StopMonitoringWindows(); 811 } 812 } 813 } 814 815 PlaceDeskbarMenu(); 816 PlaceTray(vertSwap, leftSwap); 817 PlaceApplicationBar(); 818 } 819 820 821 void 822 TBarView::RaiseDeskbar(bool raise) 823 { 824 fIsRaised = raise; 825 826 // raise or lower Deskbar without changing the active window 827 if (raise) { 828 Window()->SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 829 Window()->SetFeel(B_NORMAL_WINDOW_FEEL); 830 } else 831 Window()->SendBehind(Window()); 832 } 833 834 835 void 836 TBarView::HideDeskbar(bool hide) 837 { 838 BRect screenFrame = (BScreen(Window())).Frame(); 839 840 if (hide) { 841 Hide(); 842 if (fBarWindow != NULL) 843 fBarWindow->SetSizeLimits(); 844 845 PositionWindow(screenFrame); 846 SizeWindow(screenFrame); 847 } else { 848 Show(); 849 if (fBarWindow != NULL) 850 fBarWindow->SetSizeLimits(); 851 852 SizeWindow(screenFrame); 853 PositionWindow(screenFrame); 854 } 855 } 856 857 858 // #pragma mark - Drag and Drop 859 860 861 void 862 TBarView::CacheDragData(const BMessage* incoming) 863 { 864 if (!incoming) 865 return; 866 867 if (Dragging() && SpringLoadedFolderCompareMessages(incoming, fDragMessage)) 868 return; 869 870 // disposes then fills cached drag message and 871 // mimetypes list 872 SpringLoadedFolderCacheDragData(incoming, &fDragMessage, &fCachedTypesList); 873 } 874 875 876 static void 877 init_tracking_hook(BMenuItem* item, 878 bool (*hookFunction)(BMenu*, void*), void* state) 879 { 880 if (!item) 881 return; 882 883 BMenu* windowMenu = item->Submenu(); 884 if (windowMenu) { 885 // have a menu, set the tracking hook 886 windowMenu->SetTrackingHook(hookFunction, state); 887 } 888 } 889 890 891 status_t 892 TBarView::DragStart() 893 { 894 if (!Dragging()) 895 return B_OK; 896 897 BPoint loc; 898 uint32 buttons; 899 GetMouse(&loc, &buttons); 900 901 if (fExpandoMenuBar != NULL && fExpandoMenuBar->Frame().Contains(loc)) { 902 ConvertToScreen(&loc); 903 BPoint expandoLocation = fExpandoMenuBar->ConvertFromScreen(loc); 904 TTeamMenuItem* item = fExpandoMenuBar->TeamItemAtPoint(expandoLocation); 905 906 if (fLastDragItem) 907 init_tracking_hook(fLastDragItem, NULL, NULL); 908 909 if (item != NULL) { 910 if (item == fLastDragItem) 911 return B_OK; 912 913 fLastDragItem = item; 914 } 915 } 916 917 return B_OK; 918 } 919 920 921 bool 922 TBarView::MenuTrackingHook(BMenu* menu, void* castToThis) 923 { 924 // return true if the menu should go away 925 TrackingHookData* data = static_cast<TrackingHookData*>(castToThis); 926 if (!data) 927 return false; 928 929 TBarView* barView = dynamic_cast<TBarView*>(data->fTarget.Target(NULL)); 930 if (!barView || !menu->LockLooper()) 931 return false; 932 933 uint32 buttons; 934 BPoint location; 935 menu->GetMouse(&location, &buttons); 936 937 bool endMenu = true; 938 BRect frame(menu->Bounds()); 939 frame.InsetBy(-kMenuTrackMargin, -kMenuTrackMargin); 940 941 if (frame.Contains(location)) { 942 // if current loc is still in the menu 943 // keep tracking 944 endMenu = false; 945 } else { 946 // see if the mouse is in the team/deskbar menu item 947 menu->ConvertToScreen(&location); 948 if (barView->LockLooper()) { 949 TExpandoMenuBar* expandoMenuBar = barView->ExpandoMenuBar(); 950 TBarWindow* barWindow 951 = dynamic_cast<TBarWindow*>(barView->Window()); 952 TDeskbarMenu* deskbarMenu = barWindow->DeskbarMenu(); 953 954 if (deskbarMenu && deskbarMenu->LockLooper()) { 955 deskbarMenu->ConvertFromScreen(&location); 956 if (deskbarMenu->Frame().Contains(location)) 957 endMenu = false; 958 959 deskbarMenu->UnlockLooper(); 960 } 961 962 if (endMenu && expandoMenuBar) { 963 expandoMenuBar->ConvertFromScreen(&location); 964 BMenuItem* item = expandoMenuBar->TeamItemAtPoint(location); 965 if (item) 966 endMenu = false; 967 } 968 barView->UnlockLooper(); 969 } 970 } 971 972 menu->UnlockLooper(); 973 974 return endMenu; 975 } 976 977 978 // used by WindowMenu and TeamMenu to 979 // set the tracking hook for dragging 980 TrackingHookData* 981 TBarView::GetTrackingHookData() 982 { 983 // all tracking hook data is 984 // preset in AttachedToWindow 985 // data should never change 986 return &fTrackingHookData; 987 } 988 989 990 void 991 TBarView::DragStop(bool full) 992 { 993 if (!Dragging()) 994 return; 995 996 if (fExpandoMenuBar != NULL) { 997 if (fLastDragItem != NULL) { 998 init_tracking_hook(fLastDragItem, NULL, NULL); 999 fLastDragItem = NULL; 1000 } 1001 } 1002 1003 if (full) { 1004 delete fDragMessage; 1005 fDragMessage = NULL; 1006 1007 delete fCachedTypesList; 1008 fCachedTypesList = NULL; 1009 } 1010 } 1011 1012 1013 bool 1014 TBarView::AppCanHandleTypes(const char* signature) 1015 { 1016 // used for filtering apps/teams in the ExpandoMenuBar and TeamMenu 1017 1018 if (modifiers() & B_CONTROL_KEY) { 1019 // control key forces acceptance, just like drag&drop on icons 1020 return true; 1021 } 1022 1023 if (!signature || strlen(signature) == 0 1024 || !fCachedTypesList || fCachedTypesList->CountItems() == 0) 1025 return false; 1026 1027 if (strcasecmp(signature, kTrackerSignature) == 0) { 1028 // tracker should support all types 1029 // and should pass them on to the appropriate application 1030 return true; 1031 } 1032 1033 entry_ref hintref; 1034 BMimeType appmime(signature); 1035 if (appmime.GetAppHint(&hintref) != B_OK) 1036 return false; 1037 1038 // an app was found, now see if it supports any of 1039 // the refs in the message 1040 BFile file(&hintref, O_RDONLY); 1041 BAppFileInfo fileinfo(&file); 1042 1043 // scan the cached mimetype list and see if this app 1044 // supports anything in the list 1045 // only one item needs to match in the list of refs 1046 1047 int32 count = fCachedTypesList->CountItems(); 1048 for (int32 i = 0 ; i < count ; i++) { 1049 if (fileinfo.IsSupportedType(fCachedTypesList->ItemAt(i)->String())) 1050 return true; 1051 } 1052 1053 return false; 1054 } 1055 1056 1057 void 1058 TBarView::SetDragOverride(bool on) 1059 { 1060 fRefsRcvdOnly = on; 1061 } 1062 1063 1064 bool 1065 TBarView::DragOverride() 1066 { 1067 return fRefsRcvdOnly; 1068 } 1069 1070 1071 status_t 1072 TBarView::SendDragMessage(const char* signature, entry_ref* ref) 1073 { 1074 status_t err = B_ERROR; 1075 if (fDragMessage != NULL) { 1076 if (fRefsRcvdOnly) { 1077 // current message sent to apps is only B_REFS_RECEIVED 1078 fDragMessage->what = B_REFS_RECEIVED; 1079 } 1080 1081 BRoster roster; 1082 if (signature != NULL && *signature != '\0' 1083 && roster.IsRunning(signature)) { 1084 BMessenger messenger(signature); 1085 // drag message is still owned by DB, copy is sent 1086 // can toss it after send 1087 err = messenger.SendMessage(fDragMessage); 1088 } else if (ref != NULL) { 1089 FSLaunchItem((const entry_ref*)ref, (const BMessage*)fDragMessage, 1090 true, true); 1091 } else if (signature != NULL && *signature != '\0') 1092 roster.Launch(signature, fDragMessage); 1093 } 1094 1095 return err; 1096 } 1097 1098 1099 bool 1100 TBarView::InvokeItem(const char* signature) 1101 { 1102 // sent from TeamMenuItem 1103 if (Dragging() && AppCanHandleTypes(signature)) { 1104 SendDragMessage(signature); 1105 // invoking okay to toss memory 1106 DragStop(true); 1107 return true; 1108 } 1109 1110 return false; 1111 } 1112 1113 1114 void 1115 TBarView::HandleDeskbarMenu(BMessage* messagewithdestination) 1116 { 1117 if (!Dragging()) 1118 return; 1119 1120 // in mini-mode 1121 if (fVertical && fState != kExpandoState) { 1122 // if drop is in the team menu, bail 1123 if (fBarMenuBar->CountItems() >= 2) { 1124 uint32 buttons; 1125 BPoint location; 1126 GetMouse(&location, &buttons); 1127 if (fBarMenuBar->ItemAt(1)->Frame().Contains(location)) 1128 return; 1129 } 1130 } 1131 1132 if (messagewithdestination) { 1133 entry_ref ref; 1134 if (messagewithdestination->FindRef("refs", &ref) == B_OK) { 1135 BEntry entry(&ref, true); 1136 if (entry.IsDirectory()) { 1137 // if the ref received (should only be 1) is a directory 1138 // then add the drag refs to the directory 1139 AddRefsToDeskbarMenu(DragMessage(), &ref); 1140 } else 1141 SendDragMessage(NULL, &ref); 1142 } 1143 } else { 1144 // adds drag refs to top level in deskbar menu 1145 AddRefsToDeskbarMenu(DragMessage(), NULL); 1146 } 1147 1148 // clean up drag message and types list 1149 DragStop(true); 1150 } 1151 1152 1153 // #pragma mark - Add-ons 1154 1155 1156 // shelf is ignored for now, 1157 // it exists in anticipation of having other 'shelves' for 1158 // storing items 1159 1160 status_t 1161 TBarView::ItemInfo(int32 id, const char** name, DeskbarShelf* shelf) 1162 { 1163 *shelf = B_DESKBAR_TRAY; 1164 return fReplicantTray->ItemInfo(id, name); 1165 } 1166 1167 1168 status_t 1169 TBarView::ItemInfo(const char* name, int32* id, DeskbarShelf* shelf) 1170 { 1171 *shelf = B_DESKBAR_TRAY; 1172 return fReplicantTray->ItemInfo(name, id); 1173 } 1174 1175 1176 bool 1177 TBarView::ItemExists(int32 id, DeskbarShelf) 1178 { 1179 return fReplicantTray->IconExists(id); 1180 } 1181 1182 1183 bool 1184 TBarView::ItemExists(const char* name, DeskbarShelf) 1185 { 1186 return fReplicantTray->IconExists(name); 1187 } 1188 1189 1190 int32 1191 TBarView::CountItems(DeskbarShelf) 1192 { 1193 return fReplicantTray->ReplicantCount(); 1194 } 1195 1196 1197 BSize 1198 TBarView::MaxItemSize(DeskbarShelf shelf) 1199 { 1200 return BSize(fReplicantTray->MaxReplicantWidth(), 1201 fReplicantTray->MaxReplicantHeight()); 1202 } 1203 1204 1205 status_t 1206 TBarView::AddItem(BMessage* item, DeskbarShelf, int32* id) 1207 { 1208 return fReplicantTray->AddIcon(item, id); 1209 } 1210 1211 1212 status_t 1213 TBarView::AddItem(BEntry* entry, DeskbarShelf, int32* id) 1214 { 1215 return fReplicantTray->LoadAddOn(entry, id); 1216 } 1217 1218 1219 void 1220 TBarView::RemoveItem(int32 id) 1221 { 1222 fReplicantTray->RemoveIcon(id); 1223 } 1224 1225 1226 void 1227 TBarView::RemoveItem(const char* name, DeskbarShelf) 1228 { 1229 fReplicantTray->RemoveIcon(name); 1230 } 1231 1232 1233 BRect 1234 TBarView::OffsetIconFrame(BRect rect) const 1235 { 1236 BRect frame(Frame()); 1237 1238 frame.left += fDragRegion->Frame().left + fReplicantTray->Frame().left 1239 + rect.left; 1240 frame.top += fDragRegion->Frame().top + fReplicantTray->Frame().top 1241 + rect.top; 1242 1243 frame.right = frame.left + rect.Width(); 1244 frame.bottom = frame.top + rect.Height(); 1245 1246 return frame; 1247 } 1248 1249 1250 BRect 1251 TBarView::IconFrame(int32 id) const 1252 { 1253 return OffsetIconFrame(fReplicantTray->IconFrame(id)); 1254 } 1255 1256 1257 BRect 1258 TBarView::IconFrame(const char* name) const 1259 { 1260 return OffsetIconFrame(fReplicantTray->IconFrame(name)); 1261 } 1262 1263 1264 float 1265 TBarView::TeamMenuItemHeight() const 1266 { 1267 const int32 iconSize = fBarApp->IconSize(); 1268 float iconSizePadded = kVPad + iconSize + kVPad; 1269 1270 font_height fontHeight; 1271 if (fExpandoMenuBar != NULL) 1272 fExpandoMenuBar->GetFontHeight(&fontHeight); 1273 else 1274 GetFontHeight(&fontHeight); 1275 1276 float labelHeight = fontHeight.ascent + fontHeight.descent; 1277 labelHeight = labelHeight < kMinTeamItemHeight ? kMinTeamItemHeight 1278 : ceilf(labelHeight * 1.1f); 1279 1280 bool hideLabels = static_cast<TBarApp*>(be_app)->Settings()->hideLabels; 1281 if (hideLabels && iconSize > B_MINI_ICON) { 1282 // height is determined based solely on icon size 1283 return iconSizePadded; 1284 } else if (!fVertical || (fVertical && iconSize <= B_LARGE_ICON)) { 1285 // horizontal or vertical with label on same row as icon: 1286 // height based on icon size or font size, whichever is bigger 1287 return std::max(iconSizePadded, labelHeight); 1288 } else if (fVertical && iconSize > B_LARGE_ICON) { 1289 // vertical with label below icon: height based on icon and label 1290 return ceilf(iconSizePadded + labelHeight); 1291 } else { 1292 // height is determined based solely on label height 1293 return labelHeight; 1294 } 1295 } 1296