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