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