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 and add the status tray 164 fReplicantTray = new TReplicantTray(this, fVertical); 165 fDragRegion = new TDragRegion(this, fReplicantTray); 166 fDragRegion->AddChild(fReplicantTray); 167 if (fTrayLocation != 0) 168 AddChild(fDragRegion); 169 170 // create and add the application menubar 171 fExpandoMenuBar = new TExpandoMenuBar(this, fVertical); 172 fInlineScrollView = new TInlineScrollView(fExpandoMenuBar, 173 fVertical ? B_VERTICAL : B_HORIZONTAL); 174 AddChild(fInlineScrollView); 175 176 // If mini mode, hide the application menubar 177 if (state == kMiniState) 178 fInlineScrollView->Hide(); 179 } 180 181 182 TBarView::~TBarView() 183 { 184 delete fDragMessage; 185 delete fCachedTypesList; 186 delete fBarMenuBar; 187 } 188 189 190 void 191 TBarView::AttachedToWindow() 192 { 193 BView::AttachedToWindow(); 194 195 SetViewUIColor(B_MENU_BACKGROUND_COLOR); 196 SetFont(be_plain_font); 197 198 fMouseFilter = new BarViewMessageFilter(this); 199 Window()->AddCommonFilter(fMouseFilter); 200 201 fTrackingHookData.fTrackingHook = MenuTrackingHook; 202 fTrackingHookData.fTarget = BMessenger(this); 203 fTrackingHookData.fDragMessage = new BMessage(B_REFS_RECEIVED); 204 } 205 206 207 void 208 TBarView::DetachedFromWindow() 209 { 210 Window()->RemoveCommonFilter(fMouseFilter); 211 delete fMouseFilter; 212 fMouseFilter = NULL; 213 delete fTrackingHookData.fDragMessage; 214 fTrackingHookData.fDragMessage = NULL; 215 } 216 217 218 void 219 TBarView::Draw(BRect) 220 { 221 BRect bounds(Bounds()); 222 223 rgb_color hilite = tint_color(ViewColor(), B_DARKEN_1_TINT); 224 225 SetHighColor(hilite); 226 if (AcrossTop()) 227 StrokeLine(bounds.LeftBottom(), bounds.RightBottom()); 228 else if (AcrossBottom()) 229 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 230 231 if (fVertical && fState == kExpandoState) { 232 SetHighColor(hilite); 233 BRect frame(fExpandoMenuBar->Frame()); 234 StrokeLine(BPoint(frame.left, frame.top - 1), 235 BPoint(frame.right, frame.top -1)); 236 } 237 } 238 239 240 void 241 TBarView::MessageReceived(BMessage* message) 242 { 243 switch (message->what) { 244 case B_LOCALE_CHANGED: 245 case kShowHideTime: 246 case kShowSeconds: 247 case kShowDayOfWeek: 248 case kShowTimeZone: 249 case kGetClockSettings: 250 fReplicantTray->MessageReceived(message); 251 break; 252 253 case B_REFS_RECEIVED: 254 // received when an item is selected during DnD 255 // message is targeted here from Be menu 256 HandleDeskbarMenu(message); 257 break; 258 259 case B_ARCHIVED_OBJECT: 260 { 261 // this message has been retargeted to here 262 // instead of directly to the replicant tray 263 // so that I can follow the common pathway 264 // for adding icons to the tray 265 int32 id; 266 if (AddItem(message, B_DESKBAR_TRAY, &id) == B_OK) 267 Looper()->DetachCurrentMessage(); 268 break; 269 } 270 271 case kUpdateOrientation: 272 { 273 _ChangeState(message); 274 break; 275 } 276 277 default: 278 BView::MessageReceived(message); 279 } 280 } 281 282 283 void 284 TBarView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 285 { 286 if (fDragRegion->IsDragging()) { 287 fDragRegion->MouseMoved(where, transit, dragMessage); 288 return; 289 } 290 291 if (transit == B_ENTERED_VIEW && EventMask() == 0) 292 SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 293 294 desk_settings* settings = fBarApp->Settings(); 295 bool alwaysOnTop = settings->alwaysOnTop; 296 bool autoRaise = settings->autoRaise; 297 bool autoHide = settings->autoHide; 298 299 if (!autoRaise && !autoHide) { 300 if (transit == B_EXITED_VIEW || transit == B_OUTSIDE_VIEW) 301 SetEventMask(0); 302 return; 303 } 304 305 bool isTopMost = Window()->Feel() == B_FLOATING_ALL_WINDOW_FEEL; 306 307 // Auto-Raise 308 where = ConvertToScreen(where); 309 BRect screenFrame = (BScreen(Window())).Frame(); 310 if ((where.x == screenFrame.left || where.x == screenFrame.right 311 || where.y == screenFrame.top || where.y == screenFrame.bottom) 312 && Window()->Frame().Contains(where)) { 313 // cursor is on a screen edge within the window frame 314 315 if (!alwaysOnTop && autoRaise && !isTopMost) 316 RaiseDeskbar(true); 317 318 if (autoHide && IsHidden()) 319 HideDeskbar(false); 320 321 } else { 322 TBarWindow* window = (TBarWindow*)Window(); 323 if (window->IsShowingMenu()) 324 return; 325 326 // cursor is not on screen edge 327 BRect preventHideArea = Window()->Frame().InsetByCopy( 328 -kMaxPreventHidingDist, -kMaxPreventHidingDist); 329 330 if (preventHideArea.Contains(where)) 331 return; 332 333 // cursor to bar distance above threshold 334 if (!alwaysOnTop && autoRaise && isTopMost) { 335 RaiseDeskbar(false); 336 SetEventMask(0); 337 } 338 339 if (autoHide && !IsHidden()) 340 HideDeskbar(true); 341 } 342 } 343 344 345 void 346 TBarView::MouseDown(BPoint where) 347 { 348 where = ConvertToScreen(where); 349 350 if (Window()->Frame().Contains(where)) { 351 Window()->Activate(); 352 353 if ((modifiers() & (B_CONTROL_KEY | B_COMMAND_KEY | B_OPTION_KEY 354 | B_SHIFT_KEY)) == (B_CONTROL_KEY | B_COMMAND_KEY)) { 355 // The window key was pressed - enter dragging code 356 fDragRegion->MouseDown(fDragRegion->DragRegion().LeftTop()); 357 return; 358 } 359 } else { 360 // hide deskbar if required 361 desk_settings* settings = fBarApp->Settings(); 362 bool alwaysOnTop = settings->alwaysOnTop; 363 bool autoRaise = settings->autoRaise; 364 bool autoHide = settings->autoHide; 365 bool isTopMost = Window()->Feel() == B_FLOATING_ALL_WINDOW_FEEL; 366 367 if (!alwaysOnTop && autoRaise && isTopMost) 368 RaiseDeskbar(false); 369 370 if (autoHide && !IsHidden()) 371 HideDeskbar(true); 372 } 373 } 374 375 376 void 377 TBarView::PlaceDeskbarMenu() 378 { 379 float height; 380 height = fVertical ? kMenuBarHeight : fBarApp->IconSize() + 4; 381 382 BPoint loc(B_ORIGIN); 383 float width = gMinimumWindowWidth; 384 385 if (fState == kFullState) { 386 fBarMenuBar->RemoveTeamMenu(); 387 fBarMenuBar->RemoveSeperatorItem(); 388 loc = Bounds().LeftTop(); 389 } else if (fState == kExpandoState) { 390 fBarMenuBar->RemoveTeamMenu(); 391 if (fVertical) { 392 // shows apps below tray 393 fBarMenuBar->RemoveSeperatorItem(); 394 width += 1; 395 } else { 396 // shows apps to the right of bemenu 397 fBarMenuBar->AddSeparatorItem(); 398 width = floorf(width) / 2 + kSepItemWidth; 399 } 400 loc = Bounds().LeftTop(); 401 } else { 402 // mini mode, DeskbarMenu next to team menu 403 fBarMenuBar->RemoveSeperatorItem(); 404 fBarMenuBar->AddTeamMenu(); 405 } 406 407 fBarMenuBar->SmartResize(width, height); 408 fBarMenuBar->MoveTo(loc); 409 } 410 411 412 void 413 TBarView::PlaceTray(bool vertSwap, bool leftSwap) 414 { 415 BPoint statusLoc; 416 if (fState == kFullState) { 417 fDragRegion->ResizeTo(fBarMenuBar->Frame().Width(), kMenuBarHeight); 418 statusLoc.y = fBarMenuBar->Frame().bottom + 1; 419 statusLoc.x = 0; 420 fDragRegion->MoveTo(statusLoc); 421 422 if (!fReplicantTray->IsHidden()) 423 fReplicantTray->Hide(); 424 425 return; 426 } 427 428 if (fReplicantTray->IsHidden()) 429 fReplicantTray->Show(); 430 431 if (fTrayLocation != 0) { 432 fReplicantTray->SetMultiRow(fVertical); 433 fReplicantTray->RealignReplicants(); 434 fDragRegion->ResizeToPreferred(); 435 436 if (fVertical) { 437 statusLoc.y = fBarMenuBar->Frame().bottom + 1; 438 statusLoc.x = 0; 439 if (fLeft && fVertical) 440 fReplicantTray->MoveTo(5, 2); 441 else 442 fReplicantTray->MoveTo(2, 2); 443 } else { 444 BRect screenFrame = (BScreen(Window())).Frame(); 445 statusLoc.x = screenFrame.right - fDragRegion->Bounds().Width(); 446 statusLoc.y = -1; 447 } 448 449 fDragRegion->MoveTo(statusLoc); 450 } 451 } 452 453 454 void 455 TBarView::PlaceApplicationBar() 456 { 457 BRect screenFrame = (BScreen(Window())).Frame(); 458 if (fState == kMiniState) { 459 if (!fInlineScrollView->IsHidden()) 460 fInlineScrollView->Hide(); 461 SizeWindow(screenFrame); 462 PositionWindow(screenFrame); 463 Window()->UpdateIfNeeded(); 464 Invalidate(); 465 return; 466 } 467 468 if (fInlineScrollView->IsHidden()) 469 fInlineScrollView->Show(); 470 471 BRect expandoFrame(0, 0, 0, 0); 472 if (fVertical) { 473 // left or right 474 expandoFrame.top = fTrayLocation != 0 ? fDragRegion->Frame().bottom + 1 475 : fBarMenuBar->Frame().bottom + 1; 476 expandoFrame.left = fDragRegion->Frame().left; 477 expandoFrame.right = expandoFrame.left + gMinimumWindowWidth; 478 expandoFrame.bottom = fState == kFullState ? screenFrame.bottom 479 : expandoFrame.top + 1; 480 } else { 481 // top or bottom 482 expandoFrame.top = 0; 483 expandoFrame.bottom = fBarApp->IconSize() + 4; 484 485 if (fBarMenuBar != NULL) 486 expandoFrame.left = fBarMenuBar->Frame().Width() + 1; 487 488 if (fTrayLocation != 0 && fDragRegion != NULL) { 489 expandoFrame.right = screenFrame.Width() 490 - fDragRegion->Frame().Width() - 1; 491 } else 492 expandoFrame.right = screenFrame.Width(); 493 } 494 495 fInlineScrollView->DetachScrollers(); 496 fInlineScrollView->MoveTo(expandoFrame.LeftTop()); 497 fInlineScrollView->ResizeTo(expandoFrame.Width(), fVertical 498 ? screenFrame.bottom - expandoFrame.top 499 : expandoFrame.Height()); 500 fExpandoMenuBar->MoveTo(0, 0); 501 fExpandoMenuBar->ResizeTo(expandoFrame.Width(), expandoFrame.Height()); 502 503 if (!fVertical) { 504 // Set the max item width based on icon size 505 fExpandoMenuBar->SetMaxItemWidth(); 506 } 507 508 if (fState == kExpandoState) 509 fExpandoMenuBar->BuildItems(); 510 511 SizeWindow(screenFrame); 512 PositionWindow(screenFrame); 513 fExpandoMenuBar->DoLayout(); 514 // force menu to resize 515 CheckForScrolling(); 516 Window()->UpdateIfNeeded(); 517 Invalidate(); 518 } 519 520 521 void 522 TBarView::GetPreferredWindowSize(BRect screenFrame, float* width, float* height) 523 { 524 float windowHeight = 0; 525 float windowWidth = gMinimumWindowWidth; 526 bool setToHiddenSize = fBarApp->Settings()->autoHide && IsHidden() 527 && !fDragRegion->IsDragging(); 528 529 if (setToHiddenSize) { 530 windowHeight = kHiddenDimension; 531 532 if (fState == kExpandoState && !fVertical) { 533 // top or bottom, full 534 fExpandoMenuBar->CheckItemSizes(0); 535 windowWidth = screenFrame.Width(); 536 } else 537 windowWidth = kHiddenDimension; 538 } else { 539 if (fState == kFullState) { 540 windowHeight = screenFrame.bottom; 541 windowWidth = fBarMenuBar->Frame().Width(); 542 } else if (fState == kExpandoState) { 543 if (fVertical) { 544 // top left or right 545 if (fTrayLocation != 0) 546 windowHeight = fDragRegion->Frame().bottom + 1; 547 else 548 windowHeight = fBarMenuBar->Frame().bottom + 1; 549 550 windowHeight += fExpandoMenuBar->Bounds().Height(); 551 } else { 552 // top or bottom, full 553 fExpandoMenuBar->CheckItemSizes(0); 554 windowHeight = fBarApp->IconSize() + 4; 555 windowWidth = screenFrame.Width(); 556 } 557 } else { 558 // four corners 559 if (fTrayLocation != 0) 560 windowHeight = fDragRegion->Frame().bottom; 561 else 562 windowHeight = fBarMenuBar->Frame().bottom; 563 } 564 } 565 566 *width = windowWidth; 567 *height = windowHeight; 568 } 569 570 571 void 572 TBarView::SizeWindow(BRect screenFrame) 573 { 574 float windowWidth; 575 float windowHeight; 576 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight); 577 Window()->ResizeTo(windowWidth, windowHeight); 578 } 579 580 581 void 582 TBarView::PositionWindow(BRect screenFrame) 583 { 584 float windowWidth; 585 float windowHeight; 586 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight); 587 588 BPoint moveLoc(0, 0); 589 // right, expanded 590 if (!fLeft && fVertical) { 591 if (fState == kFullState) 592 moveLoc.x = screenFrame.right - fBarMenuBar->Frame().Width(); 593 else 594 moveLoc.x = screenFrame.right - windowWidth; 595 } 596 597 // bottom, full or corners 598 if (!fTop) 599 moveLoc.y = screenFrame.bottom - windowHeight; 600 601 Window()->MoveTo(moveLoc); 602 } 603 604 605 void 606 TBarView::CheckForScrolling() 607 { 608 if (fInlineScrollView != NULL && fExpandoMenuBar != NULL) { 609 if (fExpandoMenuBar->CheckForSizeOverrun()) 610 fInlineScrollView->AttachScrollers(); 611 else 612 fInlineScrollView->DetachScrollers(); 613 } 614 } 615 616 617 void 618 TBarView::SaveSettings() 619 { 620 desk_settings* settings = fBarApp->Settings(); 621 622 settings->vertical = fVertical; 623 settings->left = fLeft; 624 settings->top = fTop; 625 settings->state = fState; 626 settings->width = 0; 627 628 fReplicantTray->SaveTimeSettings(); 629 } 630 631 632 void 633 TBarView::UpdatePlacement() 634 { 635 ChangeState(fState, fVertical, fLeft, fTop); 636 } 637 638 639 void 640 TBarView::ChangeState(int32 state, bool vertical, bool left, bool top, 641 bool async) 642 { 643 BMessage message(kUpdateOrientation); 644 message.AddInt32("state", state); 645 message.AddBool("vertical", vertical); 646 message.AddBool("left", left); 647 message.AddBool("top", top); 648 649 if (async) 650 BMessenger(this).SendMessage(&message); 651 else 652 _ChangeState(&message); 653 } 654 655 656 void 657 TBarView::_ChangeState(BMessage* message) 658 { 659 int32 state = message->FindInt32("state"); 660 bool vertical = message->FindBool("vertical"); 661 bool left = message->FindBool("left"); 662 bool top = message->FindBool("top"); 663 664 bool vertSwap = (fVertical != vertical); 665 bool leftSwap = (fLeft != left); 666 bool stateChanged = (fState != state); 667 668 fState = state; 669 fVertical = vertical; 670 fLeft = left; 671 fTop = top; 672 673 if (stateChanged || vertSwap) { 674 be_app->PostMessage(kStateChanged); 675 // Send a message to the preferences window to let it know to 676 // enable or disable preference items. 677 678 if (vertSwap && fExpandoMenuBar != NULL) { 679 if (fVertical) { 680 fInlineScrollView->SetOrientation(B_VERTICAL); 681 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_COLUMN); 682 fExpandoMenuBar->StartMonitoringWindows(); 683 } else { 684 fInlineScrollView->SetOrientation(B_HORIZONTAL); 685 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_ROW); 686 fExpandoMenuBar->StopMonitoringWindows(); 687 } 688 } 689 } 690 691 PlaceDeskbarMenu(); 692 PlaceTray(vertSwap, leftSwap); 693 PlaceApplicationBar(); 694 } 695 696 697 void 698 TBarView::RaiseDeskbar(bool raise) 699 { 700 if (raise) 701 Window()->SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 702 else 703 Window()->SetFeel(B_NORMAL_WINDOW_FEEL); 704 } 705 706 707 void 708 TBarView::HideDeskbar(bool hide) 709 { 710 BRect screenFrame = (BScreen(Window())).Frame(); 711 712 if (hide) { 713 Hide(); 714 PositionWindow(screenFrame); 715 SizeWindow(screenFrame); 716 } else { 717 Show(); 718 SizeWindow(screenFrame); 719 PositionWindow(screenFrame); 720 } 721 } 722 723 724 // #pragma mark - Drag and Drop 725 726 727 void 728 TBarView::CacheDragData(const BMessage* incoming) 729 { 730 if (!incoming) 731 return; 732 733 if (Dragging() && SpringLoadedFolderCompareMessages(incoming, fDragMessage)) 734 return; 735 736 // disposes then fills cached drag message and 737 // mimetypes list 738 SpringLoadedFolderCacheDragData(incoming, &fDragMessage, &fCachedTypesList); 739 } 740 741 742 static void 743 init_tracking_hook(BMenuItem* item, 744 bool (*hookFunction)(BMenu*, void*), void* state) 745 { 746 if (!item) 747 return; 748 749 BMenu* windowMenu = item->Submenu(); 750 if (windowMenu) { 751 // have a menu, set the tracking hook 752 windowMenu->SetTrackingHook(hookFunction, state); 753 } 754 } 755 756 757 status_t 758 TBarView::DragStart() 759 { 760 if (!Dragging()) 761 return B_OK; 762 763 BPoint loc; 764 uint32 buttons; 765 GetMouse(&loc, &buttons); 766 767 if (fExpandoMenuBar != NULL && fExpandoMenuBar->Frame().Contains(loc)) { 768 ConvertToScreen(&loc); 769 BPoint expandoLocation = fExpandoMenuBar->ConvertFromScreen(loc); 770 TTeamMenuItem* item = fExpandoMenuBar->TeamItemAtPoint(expandoLocation); 771 772 if (fLastDragItem) 773 init_tracking_hook(fLastDragItem, NULL, NULL); 774 775 if (item != NULL) { 776 if (item == fLastDragItem) 777 return B_OK; 778 779 fLastDragItem = item; 780 } 781 } 782 783 return B_OK; 784 } 785 786 787 bool 788 TBarView::MenuTrackingHook(BMenu* menu, void* castToThis) 789 { 790 // return true if the menu should go away 791 TrackingHookData* data = static_cast<TrackingHookData*>(castToThis); 792 if (!data) 793 return false; 794 795 TBarView* barview = dynamic_cast<TBarView*>(data->fTarget.Target(NULL)); 796 if (!barview || !menu->LockLooper()) 797 return false; 798 799 uint32 buttons; 800 BPoint location; 801 menu->GetMouse(&location, &buttons); 802 803 bool endMenu = true; 804 BRect frame(menu->Bounds()); 805 frame.InsetBy(-kMenuTrackMargin, -kMenuTrackMargin); 806 807 if (frame.Contains(location)) { 808 // if current loc is still in the menu 809 // keep tracking 810 endMenu = false; 811 } else { 812 // see if the mouse is in the team/deskbar menu item 813 menu->ConvertToScreen(&location); 814 if (barview->LockLooper()) { 815 TExpandoMenuBar* expando = barview->ExpandoMenuBar(); 816 TDeskbarMenu* bemenu 817 = (dynamic_cast<TBarWindow*>(barview->Window()))->DeskbarMenu(); 818 819 if (bemenu && bemenu->LockLooper()) { 820 bemenu->ConvertFromScreen(&location); 821 if (bemenu->Frame().Contains(location)) 822 endMenu = false; 823 824 bemenu->UnlockLooper(); 825 } 826 827 if (endMenu && expando) { 828 expando->ConvertFromScreen(&location); 829 BMenuItem* item = expando->TeamItemAtPoint(location); 830 if (item) 831 endMenu = false; 832 } 833 barview->UnlockLooper(); 834 } 835 } 836 837 menu->UnlockLooper(); 838 return endMenu; 839 } 840 841 842 // used by WindowMenu and TeamMenu to 843 // set the tracking hook for dragging 844 TrackingHookData* 845 TBarView::GetTrackingHookData() 846 { 847 // all tracking hook data is 848 // preset in AttachedToWindow 849 // data should never change 850 return &fTrackingHookData; 851 } 852 853 854 void 855 TBarView::DragStop(bool full) 856 { 857 if (!Dragging()) 858 return; 859 860 if (fExpandoMenuBar != NULL) { 861 if (fLastDragItem != NULL) { 862 init_tracking_hook(fLastDragItem, NULL, NULL); 863 fLastDragItem = NULL; 864 } 865 } 866 867 if (full) { 868 delete fDragMessage; 869 fDragMessage = NULL; 870 871 delete fCachedTypesList; 872 fCachedTypesList = NULL; 873 } 874 } 875 876 877 bool 878 TBarView::AppCanHandleTypes(const char* signature) 879 { 880 // used for filtering apps/teams in the ExpandoMenuBar and TeamMenu 881 882 if (modifiers() & B_CONTROL_KEY) { 883 // control key forces acceptance, just like drag&drop on icons 884 return true; 885 } 886 887 if (!signature || strlen(signature) == 0 888 || !fCachedTypesList || fCachedTypesList->CountItems() == 0) 889 return false; 890 891 if (strcasecmp(signature, kTrackerSignature) == 0) { 892 // tracker should support all types 893 // and should pass them on to the appropriate application 894 return true; 895 } 896 897 entry_ref hintref; 898 BMimeType appmime(signature); 899 if (appmime.GetAppHint(&hintref) != B_OK) 900 return false; 901 902 // an app was found, now see if it supports any of 903 // the refs in the message 904 BFile file(&hintref, O_RDONLY); 905 BAppFileInfo fileinfo(&file); 906 907 // scan the cached mimetype list and see if this app 908 // supports anything in the list 909 // only one item needs to match in the list of refs 910 911 int32 count = fCachedTypesList->CountItems(); 912 for (int32 i = 0 ; i < count ; i++) { 913 if (fileinfo.IsSupportedType(fCachedTypesList->ItemAt(i)->String())) 914 return true; 915 } 916 917 return false; 918 } 919 920 921 void 922 TBarView::SetDragOverride(bool on) 923 { 924 fRefsRcvdOnly = on; 925 } 926 927 928 bool 929 TBarView::DragOverride() 930 { 931 return fRefsRcvdOnly; 932 } 933 934 935 status_t 936 TBarView::SendDragMessage(const char* signature, entry_ref* ref) 937 { 938 status_t err = B_ERROR; 939 if (fDragMessage != NULL) { 940 if (fRefsRcvdOnly) { 941 // current message sent to apps is only B_REFS_RECEIVED 942 fDragMessage->what = B_REFS_RECEIVED; 943 } 944 945 BRoster roster; 946 if (signature != NULL && *signature != '\0' 947 && roster.IsRunning(signature)) { 948 BMessenger messenger(signature); 949 // drag message is still owned by DB, copy is sent 950 // can toss it after send 951 err = messenger.SendMessage(fDragMessage); 952 } else if (ref != NULL) { 953 FSLaunchItem((const entry_ref*)ref, (const BMessage*)fDragMessage, 954 true, true); 955 } else if (signature != NULL && *signature != '\0') 956 roster.Launch(signature, fDragMessage); 957 } 958 959 return err; 960 } 961 962 963 bool 964 TBarView::InvokeItem(const char* signature) 965 { 966 // sent from TeamMenuItem 967 if (Dragging() && AppCanHandleTypes(signature)) { 968 SendDragMessage(signature); 969 // invoking okay to toss memory 970 DragStop(true); 971 return true; 972 } 973 974 return false; 975 } 976 977 978 void 979 TBarView::HandleDeskbarMenu(BMessage* messagewithdestination) 980 { 981 if (!Dragging()) 982 return; 983 984 // in mini-mode 985 if (fVertical && fState != kExpandoState) { 986 // if drop is in the team menu, bail 987 if (fBarMenuBar->CountItems() >= 2) { 988 uint32 buttons; 989 BPoint location; 990 GetMouse(&location, &buttons); 991 if (fBarMenuBar->ItemAt(1)->Frame().Contains(location)) 992 return; 993 } 994 } 995 996 if (messagewithdestination) { 997 entry_ref ref; 998 if (messagewithdestination->FindRef("refs", &ref) == B_OK) { 999 BEntry entry(&ref, true); 1000 if (entry.IsDirectory()) { 1001 // if the ref received (should only be 1) is a directory 1002 // then add the drag refs to the directory 1003 AddRefsToDeskbarMenu(DragMessage(), &ref); 1004 } else 1005 SendDragMessage(NULL, &ref); 1006 } 1007 } else { 1008 // adds drag refs to top level in deskbar menu 1009 AddRefsToDeskbarMenu(DragMessage(), NULL); 1010 } 1011 1012 // clean up drag message and types list 1013 DragStop(true); 1014 } 1015 1016 1017 // #pragma mark - Add-ons 1018 1019 1020 // shelf is ignored for now, 1021 // it exists in anticipation of having other 'shelves' for 1022 // storing items 1023 1024 status_t 1025 TBarView::ItemInfo(int32 id, const char** name, DeskbarShelf* shelf) 1026 { 1027 *shelf = B_DESKBAR_TRAY; 1028 return fReplicantTray->ItemInfo(id, name); 1029 } 1030 1031 1032 status_t 1033 TBarView::ItemInfo(const char* name, int32* id, DeskbarShelf* shelf) 1034 { 1035 *shelf = B_DESKBAR_TRAY; 1036 return fReplicantTray->ItemInfo(name, id); 1037 } 1038 1039 1040 bool 1041 TBarView::ItemExists(int32 id, DeskbarShelf) 1042 { 1043 return fReplicantTray->IconExists(id); 1044 } 1045 1046 1047 bool 1048 TBarView::ItemExists(const char* name, DeskbarShelf) 1049 { 1050 return fReplicantTray->IconExists(name); 1051 } 1052 1053 1054 int32 1055 TBarView::CountItems(DeskbarShelf) 1056 { 1057 return fReplicantTray->IconCount(); 1058 } 1059 1060 1061 status_t 1062 TBarView::AddItem(BMessage* item, DeskbarShelf, int32* id) 1063 { 1064 return fReplicantTray->AddIcon(item, id); 1065 } 1066 1067 1068 status_t 1069 TBarView::AddItem(BEntry* entry, DeskbarShelf, int32* id) 1070 { 1071 return fReplicantTray->LoadAddOn(entry, id); 1072 } 1073 1074 1075 void 1076 TBarView::RemoveItem(int32 id) 1077 { 1078 fReplicantTray->RemoveIcon(id); 1079 } 1080 1081 1082 void 1083 TBarView::RemoveItem(const char* name, DeskbarShelf) 1084 { 1085 fReplicantTray->RemoveIcon(name); 1086 } 1087 1088 1089 BRect 1090 TBarView::OffsetIconFrame(BRect rect) const 1091 { 1092 BRect frame(Frame()); 1093 1094 frame.left += fDragRegion->Frame().left + fReplicantTray->Frame().left 1095 + rect.left; 1096 frame.top += fDragRegion->Frame().top + fReplicantTray->Frame().top 1097 + rect.top; 1098 1099 frame.right = frame.left + rect.Width(); 1100 frame.bottom = frame.top + rect.Height(); 1101 1102 return frame; 1103 } 1104 1105 1106 BRect 1107 TBarView::IconFrame(int32 id) const 1108 { 1109 return OffsetIconFrame(fReplicantTray->IconFrame(id)); 1110 } 1111 1112 1113 BRect 1114 TBarView::IconFrame(const char* name) const 1115 { 1116 return OffsetIconFrame(fReplicantTray->IconFrame(name)); 1117 } 1118