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 if (fState == kMiniState) 469 width = gMinimumWindowWidth; 470 else 471 width = fBarApp->Settings()->width; 472 473 height = fTabHeight; 474 } else { 475 width = gMinimumWindowWidth / 2 + kIconPadding; 476 height = std::max(TeamMenuItemHeight(), 477 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter); 478 } 479 menuFrame.bottom = menuFrame.top + height; 480 481 if (fBarMenuBar == NULL) { 482 // create the Be menu 483 fBarMenuBar = new TBarMenuBar(menuFrame, "BarMenuBar", this); 484 AddChild(fBarMenuBar); 485 } else 486 fBarMenuBar->SmartResize(-1, -1); 487 488 if (fVertical) { 489 switch (fState) { 490 case kFullState: 491 case kExpandoState: 492 default: 493 // shows apps below tray 494 fBarMenuBar->RemoveTeamMenu(); 495 fBarMenuBar->RemoveSeperatorItem(); 496 break; 497 498 case kMiniState: 499 // leaf menu next to team menu 500 fBarMenuBar->RemoveSeperatorItem(); 501 fBarMenuBar->AddTeamMenu(); 502 break; 503 } 504 } else { 505 // shows apps to the right of the leaf menu 506 fBarMenuBar->RemoveTeamMenu(); 507 fBarMenuBar->AddSeparatorItem(); 508 } 509 510 fBarMenuBar->SmartResize(width, height); 511 fBarMenuBar->MoveTo(B_ORIGIN); 512 } 513 514 515 void 516 TBarView::PlaceTray(bool vertSwap, bool leftSwap) 517 { 518 BPoint statusLoc; 519 if (fTrayLocation == 0) { 520 // no replicant tray mode, not used 521 if (!fReplicantTray->IsHidden()) 522 fReplicantTray->Hide(); 523 return; 524 } else if (fReplicantTray->IsHidden()) 525 fReplicantTray->Show(); 526 527 fReplicantTray->RealignReplicants(); 528 fDragRegion->ResizeToPreferred(); 529 // also resizes replicant tray 530 531 if (fVertical) { 532 if (fState == kExpandoState || fState == kFullState) { 533 // move replicant tray down by 2px 534 if (fLeft) { 535 // move replicant tray past dragger and shrink by same amount 536 fReplicantTray->MoveTo(kDragWidth + 1, 2); 537 fReplicantTray->ResizeBy(-(kDragWidth + 1), -2); 538 } else { 539 fReplicantTray->MoveTo(0, 2); 540 fReplicantTray->ResizeBy(0, -2); 541 } 542 543 statusLoc.x = 0; 544 statusLoc.y = fBarMenuBar->Frame().bottom + 1; 545 } else if (fState == kMiniState) { 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 } 554 } else { 555 // horizontal 556 557 // move tray right and down to not cover border, resize by same 558 fReplicantTray->MoveTo(2, 0); 559 fReplicantTray->ResizeBy(-2, 0); 560 BRect screenFrame = (BScreen(Window())).Frame(); 561 statusLoc.x = screenFrame.right - fDragRegion->Bounds().Width(); 562 statusLoc.y = 0; 563 } 564 565 fDragRegion->MoveTo(statusLoc); 566 567 // make room for top and bottom border 568 fResizeControl->ResizeTo(kDragWidth, fDragRegion->Bounds().Height() - 2); 569 570 // resize control is only used in vertical expando and full state 571 if (fVertical && fState != kMiniState) { 572 // move resize control into place based on width setting 573 fResizeControl->MoveTo( 574 fLeft ? fBarApp->Settings()->width - kDragWidth : 0, 1); 575 if (fResizeControl->IsHidden()) 576 fResizeControl->Show(); 577 } else { 578 // hide resize control 579 if (!fResizeControl->IsHidden()) 580 fResizeControl->Hide(); 581 } 582 583 fDragRegion->Invalidate(); 584 } 585 586 587 void 588 TBarView::PlaceApplicationBar() 589 { 590 BRect screenFrame = (BScreen(Window())).Frame(); 591 if (fVertical && fState == kMiniState) { 592 if (!fInlineScrollView->IsHidden()) 593 fInlineScrollView->Hide(); 594 595 SizeWindow(screenFrame); 596 PositionWindow(screenFrame); 597 Window()->UpdateIfNeeded(); 598 // move the menu bar into place after the window has been resized 599 // based on replicant tray 600 fBarMenuBar->MoveTo(fLeft ? 0 : fDragRegion->Bounds().right + 1, 0); 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 // horizontal top or bottom 657 windowHeight = std::max(TeamMenuItemHeight(), 658 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter); 659 windowWidth = screenFrame.Width(); 660 } else { 661 // vertical 662 switch (fState) { 663 case kFullState: 664 case kExpandoState: 665 default: 666 // top left or right 667 if (fTrayLocation != 0) 668 windowHeight = fDragRegion->Frame().bottom + 1; 669 else 670 windowHeight = fBarMenuBar->Frame().bottom + 1; 671 672 // use Height() here not bottom because view can be scrolled 673 if (fExpandoMenuBar != NULL) 674 windowHeight += fExpandoMenuBar->Bounds().Height(); 675 676 // full state has minimum screen window height 677 if (fState == kFullState) 678 windowHeight = std::max(screenFrame.bottom, windowHeight); 679 680 windowWidth = fBarApp->Settings()->width; 681 break; 682 683 case kMiniState: 684 // four corners 685 windowHeight = fBarMenuBar->Frame().bottom; 686 windowWidth = fDragRegion->Frame().Width() 687 + fBarMenuBar->Frame().Width() + 1; 688 break; 689 } 690 } 691 692 *width = windowWidth; 693 *height = windowHeight; 694 } 695 696 697 void 698 TBarView::SizeWindow(BRect screenFrame) 699 { 700 float windowWidth; 701 float windowHeight; 702 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight); 703 Window()->ResizeTo(windowWidth, windowHeight); 704 ResizeTo(windowWidth, windowHeight); 705 } 706 707 708 void 709 TBarView::PositionWindow(BRect screenFrame) 710 { 711 float windowWidth; 712 float windowHeight; 713 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight); 714 715 BPoint moveLoc(0, 0); 716 // right, expanded, mini, or full 717 if (!fLeft && fVertical) 718 moveLoc.x = screenFrame.right - windowWidth; 719 720 // bottom, full 721 if (!fTop) 722 moveLoc.y = screenFrame.bottom - windowHeight; 723 724 Window()->MoveTo(moveLoc); 725 } 726 727 728 void 729 TBarView::CheckForScrolling() 730 { 731 if (fInlineScrollView == NULL && fExpandoMenuBar == NULL) 732 return; 733 734 if (fExpandoMenuBar->CheckForSizeOverrun()) 735 fInlineScrollView->AttachScrollers(); 736 else 737 fInlineScrollView->DetachScrollers(); 738 } 739 740 741 void 742 TBarView::SaveSettings() 743 { 744 desk_settings* settings = fBarApp->Settings(); 745 746 settings->vertical = fVertical; 747 settings->left = fLeft; 748 settings->top = fTop; 749 settings->state = fState; 750 751 fReplicantTray->SaveTimeSettings(); 752 } 753 754 755 void 756 TBarView::UpdatePlacement() 757 { 758 ChangeState(fState, fVertical, fLeft, fTop); 759 } 760 761 762 void 763 TBarView::ChangeState(int32 state, bool vertical, bool left, bool top, 764 bool async) 765 { 766 BMessage message(kUpdateOrientation); 767 message.AddInt32("state", state); 768 message.AddBool("vertical", vertical); 769 message.AddBool("left", left); 770 message.AddBool("top", top); 771 772 if (async) 773 BMessenger(this).SendMessage(&message); 774 else 775 _ChangeState(&message); 776 } 777 778 779 void 780 TBarView::_ChangeState(BMessage* message) 781 { 782 int32 state = message->FindInt32("state"); 783 bool vertical = message->FindBool("vertical"); 784 bool left = message->FindBool("left"); 785 bool top = message->FindBool("top"); 786 787 bool vertSwap = (fVertical != vertical); 788 bool leftSwap = (fLeft != left); 789 bool stateChanged = (fState != state); 790 791 fState = state; 792 fVertical = vertical; 793 fLeft = left; 794 fTop = top; 795 796 if (stateChanged || vertSwap) { 797 be_app->PostMessage(kStateChanged); 798 // Send a message to the preferences window to let it know to 799 // enable or disable preference items. 800 801 TBarWindow* barWindow = dynamic_cast<TBarWindow*>(Window()); 802 if (barWindow != NULL) 803 barWindow->SetSizeLimits(); 804 805 if (vertSwap && fExpandoMenuBar != NULL) { 806 if (fVertical) { 807 fInlineScrollView->SetOrientation(B_VERTICAL); 808 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_COLUMN); 809 fExpandoMenuBar->StartMonitoringWindows(); 810 } else { 811 fInlineScrollView->SetOrientation(B_HORIZONTAL); 812 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_ROW); 813 fExpandoMenuBar->StopMonitoringWindows(); 814 } 815 } 816 } 817 818 PlaceDeskbarMenu(); 819 PlaceTray(vertSwap, leftSwap); 820 PlaceApplicationBar(); 821 } 822 823 824 void 825 TBarView::RaiseDeskbar(bool raise) 826 { 827 fIsRaised = raise; 828 829 // raise or lower Deskbar without changing the active window 830 if (raise) { 831 Window()->SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 832 Window()->SetFeel(B_NORMAL_WINDOW_FEEL); 833 } else 834 Window()->SendBehind(Window()); 835 } 836 837 838 void 839 TBarView::HideDeskbar(bool hide) 840 { 841 BRect screenFrame = (BScreen(Window())).Frame(); 842 843 if (hide) { 844 Hide(); 845 if (fBarWindow != NULL) 846 fBarWindow->SetSizeLimits(); 847 848 PositionWindow(screenFrame); 849 SizeWindow(screenFrame); 850 } else { 851 Show(); 852 if (fBarWindow != NULL) 853 fBarWindow->SetSizeLimits(); 854 855 SizeWindow(screenFrame); 856 PositionWindow(screenFrame); 857 } 858 } 859 860 861 // #pragma mark - Drag and Drop 862 863 864 void 865 TBarView::CacheDragData(const BMessage* incoming) 866 { 867 if (!incoming) 868 return; 869 870 if (Dragging() && SpringLoadedFolderCompareMessages(incoming, fDragMessage)) 871 return; 872 873 // disposes then fills cached drag message and 874 // mimetypes list 875 SpringLoadedFolderCacheDragData(incoming, &fDragMessage, &fCachedTypesList); 876 } 877 878 879 static void 880 init_tracking_hook(BMenuItem* item, 881 bool (*hookFunction)(BMenu*, void*), void* state) 882 { 883 if (!item) 884 return; 885 886 BMenu* windowMenu = item->Submenu(); 887 if (windowMenu) { 888 // have a menu, set the tracking hook 889 windowMenu->SetTrackingHook(hookFunction, state); 890 } 891 } 892 893 894 status_t 895 TBarView::DragStart() 896 { 897 if (!Dragging()) 898 return B_OK; 899 900 BPoint loc; 901 uint32 buttons; 902 GetMouse(&loc, &buttons); 903 904 if (fExpandoMenuBar != NULL && fExpandoMenuBar->Frame().Contains(loc)) { 905 ConvertToScreen(&loc); 906 BPoint expandoLocation = fExpandoMenuBar->ConvertFromScreen(loc); 907 TTeamMenuItem* item = fExpandoMenuBar->TeamItemAtPoint(expandoLocation); 908 909 if (fLastDragItem) 910 init_tracking_hook(fLastDragItem, NULL, NULL); 911 912 if (item != NULL) { 913 if (item == fLastDragItem) 914 return B_OK; 915 916 fLastDragItem = item; 917 } 918 } 919 920 return B_OK; 921 } 922 923 924 bool 925 TBarView::MenuTrackingHook(BMenu* menu, void* castToThis) 926 { 927 // return true if the menu should go away 928 TrackingHookData* data = static_cast<TrackingHookData*>(castToThis); 929 if (!data) 930 return false; 931 932 TBarView* barView = dynamic_cast<TBarView*>(data->fTarget.Target(NULL)); 933 if (!barView || !menu->LockLooper()) 934 return false; 935 936 uint32 buttons; 937 BPoint location; 938 menu->GetMouse(&location, &buttons); 939 940 bool endMenu = true; 941 BRect frame(menu->Bounds()); 942 frame.InsetBy(-kMenuTrackMargin, -kMenuTrackMargin); 943 944 if (frame.Contains(location)) { 945 // if current loc is still in the menu 946 // keep tracking 947 endMenu = false; 948 } else { 949 // see if the mouse is in the team/deskbar menu item 950 menu->ConvertToScreen(&location); 951 if (barView->LockLooper()) { 952 TExpandoMenuBar* expandoMenuBar = barView->ExpandoMenuBar(); 953 TBarWindow* barWindow 954 = dynamic_cast<TBarWindow*>(barView->Window()); 955 TDeskbarMenu* deskbarMenu = barWindow->DeskbarMenu(); 956 957 if (deskbarMenu && deskbarMenu->LockLooper()) { 958 deskbarMenu->ConvertFromScreen(&location); 959 if (deskbarMenu->Frame().Contains(location)) 960 endMenu = false; 961 962 deskbarMenu->UnlockLooper(); 963 } 964 965 if (endMenu && expandoMenuBar) { 966 expandoMenuBar->ConvertFromScreen(&location); 967 BMenuItem* item = expandoMenuBar->TeamItemAtPoint(location); 968 if (item) 969 endMenu = false; 970 } 971 barView->UnlockLooper(); 972 } 973 } 974 975 menu->UnlockLooper(); 976 977 return endMenu; 978 } 979 980 981 // used by WindowMenu and TeamMenu to 982 // set the tracking hook for dragging 983 TrackingHookData* 984 TBarView::GetTrackingHookData() 985 { 986 // all tracking hook data is 987 // preset in AttachedToWindow 988 // data should never change 989 return &fTrackingHookData; 990 } 991 992 993 void 994 TBarView::DragStop(bool full) 995 { 996 if (!Dragging()) 997 return; 998 999 if (fExpandoMenuBar != NULL) { 1000 if (fLastDragItem != NULL) { 1001 init_tracking_hook(fLastDragItem, NULL, NULL); 1002 fLastDragItem = NULL; 1003 } 1004 } 1005 1006 if (full) { 1007 delete fDragMessage; 1008 fDragMessage = NULL; 1009 1010 delete fCachedTypesList; 1011 fCachedTypesList = NULL; 1012 } 1013 } 1014 1015 1016 bool 1017 TBarView::AppCanHandleTypes(const char* signature) 1018 { 1019 // used for filtering apps/teams in the ExpandoMenuBar and TeamMenu 1020 1021 if (modifiers() & B_CONTROL_KEY) { 1022 // control key forces acceptance, just like drag&drop on icons 1023 return true; 1024 } 1025 1026 if (!signature || strlen(signature) == 0 1027 || !fCachedTypesList || fCachedTypesList->CountItems() == 0) 1028 return false; 1029 1030 if (strcasecmp(signature, kTrackerSignature) == 0) { 1031 // tracker should support all types 1032 // and should pass them on to the appropriate application 1033 return true; 1034 } 1035 1036 entry_ref hintref; 1037 BMimeType appmime(signature); 1038 if (appmime.GetAppHint(&hintref) != B_OK) 1039 return false; 1040 1041 // an app was found, now see if it supports any of 1042 // the refs in the message 1043 BFile file(&hintref, O_RDONLY); 1044 BAppFileInfo fileinfo(&file); 1045 1046 // scan the cached mimetype list and see if this app 1047 // supports anything in the list 1048 // only one item needs to match in the list of refs 1049 1050 int32 count = fCachedTypesList->CountItems(); 1051 for (int32 i = 0 ; i < count ; i++) { 1052 if (fileinfo.IsSupportedType(fCachedTypesList->ItemAt(i)->String())) 1053 return true; 1054 } 1055 1056 return false; 1057 } 1058 1059 1060 void 1061 TBarView::SetDragOverride(bool on) 1062 { 1063 fRefsRcvdOnly = on; 1064 } 1065 1066 1067 bool 1068 TBarView::DragOverride() 1069 { 1070 return fRefsRcvdOnly; 1071 } 1072 1073 1074 status_t 1075 TBarView::SendDragMessage(const char* signature, entry_ref* ref) 1076 { 1077 status_t err = B_ERROR; 1078 if (fDragMessage != NULL) { 1079 if (fRefsRcvdOnly) { 1080 // current message sent to apps is only B_REFS_RECEIVED 1081 fDragMessage->what = B_REFS_RECEIVED; 1082 } 1083 1084 BRoster roster; 1085 if (signature != NULL && *signature != '\0' 1086 && roster.IsRunning(signature)) { 1087 BMessenger messenger(signature); 1088 // drag message is still owned by DB, copy is sent 1089 // can toss it after send 1090 err = messenger.SendMessage(fDragMessage); 1091 } else if (ref != NULL) { 1092 FSLaunchItem((const entry_ref*)ref, (const BMessage*)fDragMessage, 1093 true, true); 1094 } else if (signature != NULL && *signature != '\0') 1095 roster.Launch(signature, fDragMessage); 1096 } 1097 1098 return err; 1099 } 1100 1101 1102 bool 1103 TBarView::InvokeItem(const char* signature) 1104 { 1105 // sent from TeamMenuItem 1106 if (Dragging() && AppCanHandleTypes(signature)) { 1107 SendDragMessage(signature); 1108 // invoking okay to toss memory 1109 DragStop(true); 1110 return true; 1111 } 1112 1113 return false; 1114 } 1115 1116 1117 void 1118 TBarView::HandleDeskbarMenu(BMessage* messagewithdestination) 1119 { 1120 if (!Dragging()) 1121 return; 1122 1123 // in mini-mode 1124 if (fVertical && fState != kExpandoState) { 1125 // if drop is in the team menu, bail 1126 if (fBarMenuBar->CountItems() >= 2) { 1127 uint32 buttons; 1128 BPoint location; 1129 GetMouse(&location, &buttons); 1130 if (fBarMenuBar->ItemAt(1)->Frame().Contains(location)) 1131 return; 1132 } 1133 } 1134 1135 if (messagewithdestination) { 1136 entry_ref ref; 1137 if (messagewithdestination->FindRef("refs", &ref) == B_OK) { 1138 BEntry entry(&ref, true); 1139 if (entry.IsDirectory()) { 1140 // if the ref received (should only be 1) is a directory 1141 // then add the drag refs to the directory 1142 AddRefsToDeskbarMenu(DragMessage(), &ref); 1143 } else 1144 SendDragMessage(NULL, &ref); 1145 } 1146 } else { 1147 // adds drag refs to top level in deskbar menu 1148 AddRefsToDeskbarMenu(DragMessage(), NULL); 1149 } 1150 1151 // clean up drag message and types list 1152 DragStop(true); 1153 } 1154 1155 1156 // #pragma mark - Add-ons 1157 1158 1159 // shelf is ignored for now, 1160 // it exists in anticipation of having other 'shelves' for 1161 // storing items 1162 1163 status_t 1164 TBarView::ItemInfo(int32 id, const char** name, DeskbarShelf* shelf) 1165 { 1166 *shelf = B_DESKBAR_TRAY; 1167 return fReplicantTray->ItemInfo(id, name); 1168 } 1169 1170 1171 status_t 1172 TBarView::ItemInfo(const char* name, int32* id, DeskbarShelf* shelf) 1173 { 1174 *shelf = B_DESKBAR_TRAY; 1175 return fReplicantTray->ItemInfo(name, id); 1176 } 1177 1178 1179 bool 1180 TBarView::ItemExists(int32 id, DeskbarShelf) 1181 { 1182 return fReplicantTray->IconExists(id); 1183 } 1184 1185 1186 bool 1187 TBarView::ItemExists(const char* name, DeskbarShelf) 1188 { 1189 return fReplicantTray->IconExists(name); 1190 } 1191 1192 1193 int32 1194 TBarView::CountItems(DeskbarShelf) 1195 { 1196 return fReplicantTray->ReplicantCount(); 1197 } 1198 1199 1200 BSize 1201 TBarView::MaxItemSize(DeskbarShelf shelf) 1202 { 1203 return BSize(fReplicantTray->MaxReplicantWidth(), 1204 fReplicantTray->MaxReplicantHeight()); 1205 } 1206 1207 1208 status_t 1209 TBarView::AddItem(BMessage* item, DeskbarShelf, int32* id) 1210 { 1211 return fReplicantTray->AddIcon(item, id); 1212 } 1213 1214 1215 status_t 1216 TBarView::AddItem(BEntry* entry, DeskbarShelf, int32* id) 1217 { 1218 return fReplicantTray->LoadAddOn(entry, id); 1219 } 1220 1221 1222 void 1223 TBarView::RemoveItem(int32 id) 1224 { 1225 fReplicantTray->RemoveIcon(id); 1226 } 1227 1228 1229 void 1230 TBarView::RemoveItem(const char* name, DeskbarShelf) 1231 { 1232 fReplicantTray->RemoveIcon(name); 1233 } 1234 1235 1236 BRect 1237 TBarView::OffsetIconFrame(BRect rect) const 1238 { 1239 BRect frame(Frame()); 1240 1241 frame.left += fDragRegion->Frame().left + fReplicantTray->Frame().left 1242 + rect.left; 1243 frame.top += fDragRegion->Frame().top + fReplicantTray->Frame().top 1244 + rect.top; 1245 1246 frame.right = frame.left + rect.Width(); 1247 frame.bottom = frame.top + rect.Height(); 1248 1249 return frame; 1250 } 1251 1252 1253 BRect 1254 TBarView::IconFrame(int32 id) const 1255 { 1256 return OffsetIconFrame(fReplicantTray->IconFrame(id)); 1257 } 1258 1259 1260 BRect 1261 TBarView::IconFrame(const char* name) const 1262 { 1263 return OffsetIconFrame(fReplicantTray->IconFrame(name)); 1264 } 1265 1266 1267 float 1268 TBarView::TeamMenuItemHeight() const 1269 { 1270 const int32 iconSize = fBarApp->IconSize(); 1271 float iconSizePadded = kVPad + iconSize + kVPad; 1272 1273 font_height fontHeight; 1274 if (fExpandoMenuBar != NULL) 1275 fExpandoMenuBar->GetFontHeight(&fontHeight); 1276 else 1277 GetFontHeight(&fontHeight); 1278 1279 float labelHeight = fontHeight.ascent + fontHeight.descent; 1280 labelHeight = labelHeight < kMinTeamItemHeight ? kMinTeamItemHeight 1281 : ceilf(labelHeight * 1.1f); 1282 1283 bool hideLabels = static_cast<TBarApp*>(be_app)->Settings()->hideLabels; 1284 if (hideLabels && iconSize > B_MINI_ICON) { 1285 // height is determined based solely on icon size 1286 return iconSizePadded; 1287 } else if (!fVertical || (fVertical && iconSize <= B_LARGE_ICON)) { 1288 // horizontal or vertical with label on same row as icon: 1289 // height based on icon size or font size, whichever is bigger 1290 return std::max(iconSizePadded, labelHeight); 1291 } else if (fVertical && iconSize > B_LARGE_ICON) { 1292 // vertical with label below icon: height based on icon and label 1293 return ceilf(iconSizePadded + labelHeight); 1294 } else { 1295 // height is determined based solely on label height 1296 return labelHeight; 1297 } 1298 } 1299