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