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