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