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