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