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