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 trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 #include <Debug.h> 36 37 #include <string.h> 38 39 #include <Autolock.h> 40 #include <Bitmap.h> 41 #include <ControlLook.h> 42 #include <NodeInfo.h> 43 #include <Roster.h> 44 #include <Screen.h> 45 46 #include "icons.h" 47 #include "icons_logo.h" 48 #include "BarApp.h" 49 #include "BarMenuTitle.h" 50 #include "BarView.h" 51 #include "BeMenu.h" 52 #include "DeskBarUtils.h" 53 #include "ExpandoMenuBar.h" 54 #include "ResourceSet.h" 55 #include "ShowHideMenuItem.h" 56 #include "StatusView.h" 57 #include "TeamMenuItem.h" 58 #include "WindowMenu.h" 59 #include "WindowMenuItem.h" 60 61 const float kDefaultBeMenuWidth = 50.0f; 62 const float kSepItemWidth = 5.0f; 63 64 const uint32 M_MINIMIZE_TEAM = 'mntm'; 65 const uint32 M_BRING_TEAM_TO_FRONT = 'bftm'; 66 67 68 bool TExpandoMenuBar::sDoMonitor = false; 69 thread_id TExpandoMenuBar::sMonThread = B_ERROR; 70 BLocker TExpandoMenuBar::sMonLocker("expando monitor"); 71 72 73 TExpandoMenuBar::TExpandoMenuBar(TBarView *bar, BRect frame, const char *name, 74 bool vertical, bool drawLabel) 75 : BMenuBar(frame, name, B_FOLLOW_NONE, 76 vertical ? B_ITEMS_IN_COLUMN : B_ITEMS_IN_ROW, vertical), 77 fVertical(vertical), 78 fOverflow(false), 79 fDrawLabel(drawLabel), 80 fIsScrolling(false), 81 fShowTeamExpander(static_cast<TBarApp *>(be_app)->Settings()->superExpando), 82 fExpandNewTeams(static_cast<TBarApp *>(be_app)->Settings()->expandNewTeams), 83 fBeMenuWidth(kDefaultBeMenuWidth), 84 fBarView(bar), 85 fFirstApp(0), 86 fPreviousDragTargetItem(NULL) 87 { 88 #ifdef DOUBLECLICKBRINGSTOFRONT 89 fLastClickItem = -1; 90 fLastClickTime = 0; 91 #endif 92 93 SetItemMargins(0.0f, 0.0f, 0.0f, 0.0f); 94 SetFont(be_plain_font); 95 SetMaxContentWidth(sMinimumWindowWidth); 96 } 97 98 99 int 100 TExpandoMenuBar::CompareByName(const void *first, const void *second) 101 { 102 return strcasecmp((*(static_cast<BarTeamInfo * const*>(first)))->name, 103 (*(static_cast<BarTeamInfo * const*>(second)))->name); 104 } 105 106 107 void 108 TExpandoMenuBar::AttachedToWindow() 109 { 110 BMessenger self(this); 111 BList teamList; 112 TBarApp::Subscribe(self, &teamList); 113 float width = fVertical ? Frame().Width() : sMinimumWindowWidth; 114 float height = -1.0f; 115 116 // top or bottom mode, add be menu and sep for menubar tracking consistency 117 if (!fVertical) { 118 TBeMenu *beMenu = new TBeMenu(fBarView); 119 TBarWindow::SetBeMenu(beMenu); 120 const BBitmap* logoBitmap = AppResSet()->FindBitmap(B_MESSAGE_TYPE, 121 R_BeLogoIcon); 122 if (logoBitmap != NULL) 123 fBeMenuWidth = logoBitmap->Bounds().Width() + 16; 124 fBeMenuItem = new TBarMenuTitle(fBeMenuWidth, Frame().Height(), 125 logoBitmap, beMenu, true); 126 AddItem(fBeMenuItem); 127 128 fSeparatorItem = new TTeamMenuItem(kSepItemWidth, height, fVertical); 129 AddItem(fSeparatorItem); 130 fSeparatorItem->SetEnabled(false); 131 fFirstApp = 2; 132 } else { 133 fBeMenuItem = NULL; 134 fSeparatorItem = NULL; 135 } 136 137 desk_settings *settings = ((TBarApp *)be_app)->Settings(); 138 139 if (settings->sortRunningApps) 140 teamList.SortItems(CompareByName); 141 142 int32 count = teamList.CountItems(); 143 for (int32 i = 0; i < count; i++) { 144 BarTeamInfo *barInfo = (BarTeamInfo *)teamList.ItemAt(i); 145 if ((barInfo->flags & B_BACKGROUND_APP) == 0 146 && strcasecmp(barInfo->sig, kDeskbarSignature) != 0) { 147 if (settings->trackerAlwaysFirst 148 && !strcmp(barInfo->sig, kTrackerSignature)) { 149 AddItem(new TTeamMenuItem(barInfo->teams, barInfo->icon, 150 barInfo->name, barInfo->sig, width, height, 151 fDrawLabel, fVertical), fFirstApp); 152 } else { 153 AddItem(new TTeamMenuItem(barInfo->teams, barInfo->icon, 154 barInfo->name, barInfo->sig, width, height, 155 fDrawLabel, fVertical)); 156 } 157 158 barInfo->teams = NULL; 159 barInfo->icon = NULL; 160 barInfo->name = NULL; 161 barInfo->sig = NULL; 162 } 163 164 delete barInfo; 165 } 166 167 BMenuBar::AttachedToWindow(); 168 169 if (CountItems() == 0) { 170 // If we're empty, BMenuBar::AttachedToWindow() resizes us to some 171 // weird value - we just override it again 172 ResizeTo(width, 0); 173 } 174 175 if (fVertical) { 176 sDoMonitor = true; 177 sMonThread = spawn_thread(monitor_team_windows, 178 "Expando Window Watcher", B_LOW_PRIORITY, this); 179 resume_thread(sMonThread); 180 } 181 } 182 183 184 void 185 TExpandoMenuBar::DetachedFromWindow() 186 { 187 BMenuBar::DetachedFromWindow(); 188 189 if (sMonThread != B_ERROR) { 190 sDoMonitor = false; 191 192 status_t returnCode; 193 wait_for_thread(sMonThread, &returnCode); 194 195 sMonThread = B_ERROR; 196 } 197 198 BMessenger self(this); 199 BMessage message(msg_Unsubscribe); 200 message.AddMessenger("messenger", self); 201 be_app->PostMessage(&message); 202 203 RemoveItems(0, CountItems(), true); 204 } 205 206 207 void 208 TExpandoMenuBar::MessageReceived(BMessage *message) 209 { 210 int32 index; 211 TTeamMenuItem *item; 212 213 switch (message->what) { 214 case B_SOME_APP_LAUNCHED: { 215 BList *teams = NULL; 216 message->FindPointer("teams", (void **)&teams); 217 218 BBitmap *icon = NULL; 219 message->FindPointer("icon", (void **)&icon); 220 221 const char *signature; 222 if (message->FindString("sig", &signature) == B_OK 223 &&strcasecmp(signature, kDeskbarSignature) == 0) { 224 delete teams; 225 delete icon; 226 break; 227 } 228 229 uint32 flags; 230 if (message->FindInt32("flags", ((int32*) &flags)) == B_OK 231 && (flags & B_BACKGROUND_APP) != 0) { 232 delete teams; 233 delete icon; 234 break; 235 } 236 237 const char *name = NULL; 238 message->FindString("name", &name); 239 240 AddTeam(teams, icon, strdup(name), strdup(signature)); 241 break; 242 } 243 244 case msg_AddTeam: 245 AddTeam(message->FindInt32("team"), message->FindString("sig")); 246 break; 247 248 case msg_RemoveTeam: 249 { 250 team_id team = -1; 251 message->FindInt32("team", &team); 252 253 RemoveTeam(team, true); 254 break; 255 } 256 257 case B_SOME_APP_QUIT: 258 { 259 team_id team = -1; 260 message->FindInt32("team", &team); 261 262 RemoveTeam(team, false); 263 break; 264 } 265 266 case M_MINIMIZE_TEAM: 267 { 268 index = message->FindInt32("itemIndex"); 269 item = dynamic_cast<TTeamMenuItem *>(ItemAt(index)); 270 if (item == NULL) 271 break; 272 273 TShowHideMenuItem::TeamShowHideCommon(B_MINIMIZE_WINDOW, 274 item->Teams(), 275 item->Menu()->ConvertToScreen(item->Frame()), 276 true); 277 break; 278 } 279 280 case M_BRING_TEAM_TO_FRONT: 281 { 282 index = message->FindInt32("itemIndex"); 283 item = dynamic_cast<TTeamMenuItem *>(ItemAt(index)); 284 if (item == NULL) 285 break; 286 287 TShowHideMenuItem::TeamShowHideCommon(B_BRING_TO_FRONT, 288 item->Teams(), item->Menu()->ConvertToScreen(item->Frame()), 289 true); 290 break; 291 } 292 293 default: 294 BMenuBar::MessageReceived(message); 295 break; 296 } 297 } 298 299 300 void 301 TExpandoMenuBar::MouseDown(BPoint where) 302 { 303 BMessage *message = Window()->CurrentMessage(); 304 305 // check for three finger salute, a.k.a. Vulcan Death Grip 306 if (message != NULL) { 307 int32 modifiers = 0; 308 message->FindInt32("modifiers", &modifiers); 309 310 if ((modifiers & B_COMMAND_KEY) != 0 311 && (modifiers & B_OPTION_KEY) != 0 312 && (modifiers & B_SHIFT_KEY) != 0 313 && !fBarView->Dragging()) { 314 TTeamMenuItem *item = TeamItemAtPoint(where); 315 316 if (item != NULL) { 317 const BList *teams = item->Teams(); 318 int32 teamCount = teams->CountItems(); 319 320 team_id teamID; 321 for (int32 team = 0; team < teamCount; team++) { 322 teamID = (team_id)teams->ItemAt(team); 323 kill_team(teamID); 324 // remove the team immediately 325 // from display 326 RemoveTeam(teamID, false); 327 } 328 329 return; 330 } 331 } 332 } 333 334 // This feature is broken because the menu bar never receives 335 // the second click 336 #ifdef DOUBLECLICKBRINGSTOFRONT 337 // doubleclick on an item brings all to front 338 for (int32 i = fFirstApp; i < count; i++) { 339 TTeamMenuItem *item = (TTeamMenuItem *)ItemAt(i); 340 if (item->Frame().Contains(where)) { 341 bigtime_t clickSpeed = 0; 342 get_click_speed(&clickSpeed); 343 if (fLastClickItem == i 344 && clickSpeed > system_time() - fLastClickTime) { 345 // bring this team's window to the front 346 BMessage showMessage(M_BRING_TEAM_TO_FRONT); 347 showMessage.AddInt32("itemIndex", i); 348 Window()->PostMessage(&showMessage, this); 349 return; 350 } 351 352 fLastClickItem = i; 353 fLastClickTime = system_time(); 354 break; 355 } 356 } 357 #endif 358 359 // control click - show all/hide all shortcut 360 if (message != NULL) { 361 int32 modifiers = 0; 362 message->FindInt32("modifiers", &modifiers); 363 if ((modifiers & B_CONTROL_KEY) != 0 364 && ! fBarView->Dragging()) { 365 TTeamMenuItem *item = TeamItemAtPoint(where); 366 if (item != NULL) { 367 // show/hide item's teams 368 BMessage showMessage((modifiers & B_SHIFT_KEY) != 0 369 ? M_MINIMIZE_TEAM : M_BRING_TEAM_TO_FRONT); 370 showMessage.AddInt32("itemIndex", IndexOf(item)); 371 Window()->PostMessage(&showMessage, this); 372 return; 373 } 374 } 375 } 376 377 // Check the bounds of the expand Team icon 378 if (fShowTeamExpander && fVertical && !fBarView->Dragging()) { 379 TTeamMenuItem *item = TeamItemAtPoint(where); 380 if (item != NULL) { 381 BRect expanderRect = item->ExpanderBounds(); 382 if (expanderRect.Contains(where)) { 383 // Let the update thread wait... 384 BAutolock locker(sMonLocker); 385 386 // Toggle the item 387 item->ToggleExpandState(true); 388 item->Draw(); 389 390 // Absorb the message. 391 return; 392 } 393 } 394 } 395 396 BMenuBar::MouseDown(where); 397 } 398 399 400 void 401 TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage *message) 402 { 403 if (!message) { 404 // force a cleanup 405 _FinishedDrag(); 406 BMenuBar::MouseMoved(where, code, message); 407 return; 408 } 409 410 uint32 buttons; 411 if (!(Window()->CurrentMessage()) 412 || Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons) < B_OK) 413 buttons = 0; 414 415 if (buttons == 0) 416 return; 417 418 switch (code) { 419 case B_ENTERED_VIEW: 420 // fPreviousDragTargetItem should always be NULL here anyways. 421 if (fPreviousDragTargetItem) 422 _FinishedDrag(); 423 424 fBarView->CacheDragData(message); 425 fPreviousDragTargetItem = NULL; 426 break; 427 428 case B_OUTSIDE_VIEW: 429 // NOTE: Should not be here, but for the sake of defensive 430 // programming... 431 case B_EXITED_VIEW: 432 _FinishedDrag(); 433 break; 434 435 case B_INSIDE_VIEW: 436 if (fBarView->Dragging()) { 437 TTeamMenuItem* item = NULL; 438 for (int32 i = 0; i < CountItems(); i++) { 439 BMenuItem* _item = ItemAt(i); 440 if (_item->Frame().Contains(where)) { 441 item = dynamic_cast<TTeamMenuItem*>(_item); 442 break; 443 } 444 } 445 if (item == fPreviousDragTargetItem) 446 break; 447 if (fPreviousDragTargetItem != NULL) 448 fPreviousDragTargetItem->SetOverrideSelected(false); 449 if (item != NULL) 450 item->SetOverrideSelected(true); 451 fPreviousDragTargetItem = item; 452 } 453 break; 454 } 455 } 456 457 458 void 459 TExpandoMenuBar::MouseUp(BPoint where) 460 { 461 if (!fBarView->Dragging()) { 462 BMenuBar::MouseUp(where); 463 return; 464 } 465 466 _FinishedDrag(true); 467 } 468 469 470 bool 471 TExpandoMenuBar::InBeMenu(BPoint loc) const 472 { 473 if (!fVertical) { 474 if (fBeMenuItem && fBeMenuItem->Frame().Contains(loc)) 475 return true; 476 } else { 477 TBarWindow *window = dynamic_cast<TBarWindow*>(Window()); 478 if (window) { 479 if (TBeMenu *bemenu = window->BeMenu()) { 480 bool inBeMenu = false; 481 if (bemenu->LockLooper()) { 482 inBeMenu = bemenu->Frame().Contains(loc); 483 bemenu->UnlockLooper(); 484 } 485 return inBeMenu; 486 } 487 } 488 } 489 490 return false; 491 } 492 493 494 /** Returns the team menu item that belongs to the item under the 495 * specified \a point. 496 * If \a _item is given, it will return the exact menu item under 497 * that point (which might be a window item when the expander is on). 498 */ 499 500 TTeamMenuItem * 501 TExpandoMenuBar::TeamItemAtPoint(BPoint point, BMenuItem **_item) 502 { 503 TTeamMenuItem *lastApp = NULL; 504 int32 count = CountItems(); 505 506 for (int32 i = fFirstApp; i < count; i++) { 507 BMenuItem *item = ItemAt(i); 508 509 if (dynamic_cast<TTeamMenuItem *>(item) != NULL) 510 lastApp = (TTeamMenuItem *)item; 511 512 if (item && item->Frame().Contains(point)) { 513 if (_item != NULL) 514 *_item = item; 515 516 return lastApp; 517 } 518 } 519 520 // no item found 521 522 if (_item != NULL) 523 *_item = NULL; 524 525 return NULL; 526 } 527 528 529 void 530 TExpandoMenuBar::AddTeam(BList *team, BBitmap *icon, char *name, char *signature) 531 { 532 float itemWidth = fVertical ? fBarView->Bounds().Width() : sMinimumWindowWidth; 533 float itemHeight = -1.0f; 534 535 desk_settings *settings = ((TBarApp *)be_app)->Settings(); 536 TTeamMenuItem *item = new TTeamMenuItem(team, icon, name, signature, itemWidth, 537 itemHeight, fDrawLabel, fVertical); 538 539 if (settings->trackerAlwaysFirst && !strcmp(signature, kTrackerSignature)) { 540 AddItem(item, fFirstApp); 541 } else if (settings->sortRunningApps) { 542 TTeamMenuItem *teamItem = dynamic_cast<TTeamMenuItem *>(ItemAt(fFirstApp)); 543 int32 firstApp = fFirstApp; 544 545 // if Tracker should always be the first item, we need to skip it 546 // when sorting in the current item 547 if (settings->trackerAlwaysFirst && teamItem != NULL 548 && !strcmp(teamItem->Signature(), kTrackerSignature)) { 549 firstApp++; 550 } 551 552 int32 count = CountItems(), i; 553 for (i = firstApp; i < count; i++) { 554 teamItem = dynamic_cast<TTeamMenuItem *>(ItemAt(i)); 555 if (teamItem != NULL && strcasecmp(teamItem->Name(), name) > 0) { 556 AddItem(item, i); 557 break; 558 } 559 } 560 // was the item added to the list yet? 561 if (i == count) 562 AddItem(item); 563 } else 564 AddItem(item); 565 566 if (fVertical) { 567 if (item && fShowTeamExpander && fExpandNewTeams) 568 item->ToggleExpandState(false); 569 570 fBarView->SizeWindow(BScreen(Window()).Frame()); 571 } else 572 CheckItemSizes(1); 573 574 Window()->UpdateIfNeeded(); 575 } 576 577 578 void 579 TExpandoMenuBar::AddTeam(team_id team, const char *signature) 580 { 581 int32 count = CountItems(); 582 for (int32 i = fFirstApp; i < count; i++) { 583 // Only add to team menu items 584 if (TTeamMenuItem *item = dynamic_cast<TTeamMenuItem *>(ItemAt(i))) { 585 if (strcasecmp(item->Signature(), signature) == 0) { 586 if (!(item->Teams()->HasItem((void *)team))) 587 item->Teams()->AddItem((void *)team); 588 589 break; 590 } 591 } 592 } 593 } 594 595 596 void 597 TExpandoMenuBar::RemoveTeam(team_id team, bool partial) 598 { 599 int32 count = CountItems(); 600 for (int32 i = fFirstApp; i < count; i++) { 601 if (TTeamMenuItem *item = dynamic_cast<TTeamMenuItem *>(ItemAt(i))) { 602 if (item->Teams()->HasItem((void *)team)) { 603 item->Teams()->RemoveItem(team); 604 605 if (partial) 606 return; 607 608 #ifdef DOUBLECLICKBRINGSTOFRONT 609 if (fLastClickItem == i) 610 fLastClickItem = -1; 611 #endif 612 613 RemoveItem(i); 614 615 if (fVertical) { 616 // instead of resizing the window here and there in the code 617 // the resize method will be centered in one place 618 // thus, the same behavior (good or bad) will be used whereever 619 // window sizing is done 620 fBarView->SizeWindow(BScreen(Window()).Frame()); 621 } else 622 CheckItemSizes(-1); 623 624 Window()->UpdateIfNeeded(); 625 626 delete item; 627 return; 628 } 629 } 630 } 631 } 632 633 634 void 635 TExpandoMenuBar::CheckItemSizes(int32 delta) 636 { 637 float width = Frame().Width(); 638 int32 count = CountItems(); 639 bool reset = false; 640 float newWidth = 0; 641 float fullWidth = (sMinimumWindowWidth * count); 642 643 if (!fBarView->Vertical()) { 644 // in this case there are 2 extra items: 645 // The Be Menu 646 // The little separator item 647 fullWidth = fullWidth - (sMinimumWindowWidth * 2) + (fBeMenuWidth + kSepItemWidth); 648 width -= (fBeMenuWidth + kSepItemWidth); 649 count -= 2; 650 } 651 652 if (delta >= 0 && fullWidth > width) { 653 fOverflow = true; 654 reset = true; 655 newWidth = floorf(width/count); 656 } else if (delta < 0 && fOverflow) { 657 reset = true; 658 if (fullWidth > width) 659 newWidth = floorf(width/count); 660 else 661 newWidth = sMinimumWindowWidth; 662 } 663 if (newWidth > sMinimumWindowWidth) 664 newWidth = sMinimumWindowWidth; 665 666 if (reset) { 667 SetMaxContentWidth(newWidth); 668 if (newWidth == sMinimumWindowWidth) 669 fOverflow = false; 670 InvalidateLayout(); 671 672 for (int32 index = fFirstApp; ; index++) { 673 TTeamMenuItem *item = (TTeamMenuItem *)ItemAt(index); 674 if (!item) 675 break; 676 item->SetOverrideWidth(newWidth); 677 } 678 679 Invalidate(); 680 Window()->UpdateIfNeeded(); 681 } 682 } 683 684 685 menu_layout 686 TExpandoMenuBar::MenuLayout() const 687 { 688 return Layout(); 689 } 690 691 692 void 693 TExpandoMenuBar::Draw(BRect update) 694 { 695 BMenu::Draw(update); 696 } 697 698 699 void 700 TExpandoMenuBar::DrawBackground(BRect) 701 { 702 if (fVertical) 703 return; 704 705 BRect bounds(Bounds()); 706 rgb_color menuColor = ViewColor(); 707 rgb_color hilite = tint_color(menuColor, B_DARKEN_1_TINT); 708 rgb_color dark = tint_color(menuColor, B_DARKEN_2_TINT); 709 rgb_color vlight = tint_color(menuColor, B_LIGHTEN_2_TINT); 710 711 int32 last = CountItems() - 1; 712 if (last >= 0) 713 bounds.left = ItemAt(last)->Frame().right + 1; 714 else 715 bounds.left = 0; 716 717 if (be_control_look != NULL) { 718 SetHighColor(tint_color(menuColor, 1.22)); 719 StrokeLine(bounds.LeftTop(), bounds.LeftBottom()); 720 bounds.left++; 721 uint32 borders = BControlLook::B_TOP_BORDER 722 | BControlLook::B_BOTTOM_BORDER | BControlLook::B_RIGHT_BORDER; 723 724 be_control_look->DrawButtonBackground(this, bounds, bounds, menuColor, 725 0, borders); 726 } else { 727 SetHighColor(vlight); 728 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 729 StrokeLine(BPoint(bounds.left, bounds.top + 1), bounds.LeftBottom()); 730 SetHighColor(hilite); 731 StrokeLine(BPoint(bounds.left + 1, bounds.bottom), bounds.RightBottom()); 732 } 733 } 734 735 736 /** Something to help determine if we are showing too many apps 737 * need to add in scrolling functionality. 738 */ 739 740 void 741 TExpandoMenuBar::CheckForSizeOverrun() 742 { 743 BRect screenFrame = (BScreen(Window())).Frame(); 744 if (fVertical) 745 fIsScrolling = Window()->Frame().bottom > screenFrame.bottom; 746 else 747 fIsScrolling = false; 748 } 749 750 751 void 752 TExpandoMenuBar::SizeWindow() 753 { 754 if (fVertical) 755 fBarView->SizeWindow(BScreen(Window()).Frame()); 756 else 757 CheckItemSizes(1); 758 } 759 760 761 int32 762 TExpandoMenuBar::monitor_team_windows(void *arg) 763 { 764 TExpandoMenuBar *teamMenu = (TExpandoMenuBar *)arg; 765 766 while (teamMenu->sDoMonitor) { 767 sMonLocker.Lock(); 768 769 if (teamMenu->Window()->LockWithTimeout(50000) == B_OK) { 770 int32 totalItems = teamMenu->CountItems(); 771 772 // Set all WindowMenuItems to require an update. 773 TWindowMenuItem *item = NULL; 774 for (int32 i = 0; i < totalItems; i++) { 775 if (!teamMenu->SubmenuAt(i)){ 776 item = static_cast<TWindowMenuItem *>(teamMenu->ItemAt(i)); 777 item->SetRequireUpdate(); 778 } 779 } 780 781 // Perform SetTo() on all the items that still exist as well as add new items. 782 bool itemModified = false, resize = false; 783 TTeamMenuItem *teamItem = NULL; 784 785 for (int32 i = 0; i < totalItems; i++) { 786 if (teamMenu->SubmenuAt(i) == NULL) 787 continue; 788 789 teamItem = static_cast<TTeamMenuItem *>(teamMenu->ItemAt(i)); 790 if (teamItem->IsExpanded()) { 791 int32 teamCount = teamItem->Teams()->CountItems(); 792 for (int32 j = 0; j < teamCount; j++) { 793 // The following code is almost a copy/paste from 794 // WindowMenu.cpp 795 team_id theTeam = (team_id)teamItem->Teams()->ItemAt(j); 796 int32 count = 0; 797 int32 *tokens = get_token_list(theTeam, &count); 798 799 for (int32 k = 0; k < count; k++) { 800 client_window_info *wInfo 801 = get_window_info(tokens[k]); 802 if (wInfo == NULL) 803 continue; 804 805 if (TWindowMenu::WindowShouldBeListed(wInfo->feel) 806 && (wInfo->show_hide_level <= 0 807 || wInfo->is_mini)) { 808 // Check if we have a matching window item... 809 item = teamItem->ExpandedWindowItem( 810 wInfo->server_token); 811 if (item) { 812 item->SetTo(wInfo->name, 813 wInfo->server_token, wInfo->is_mini, 814 ((1 << current_workspace()) & wInfo->workspaces) != 0); 815 816 if (strcmp(wInfo->name, item->Label()) != 0) 817 item->SetLabel(wInfo->name); 818 819 if (item->ChangedState()) 820 itemModified = true; 821 } else if (teamItem->IsExpanded()) { 822 // Add the item 823 item = new TWindowMenuItem(wInfo->name, 824 wInfo->server_token, wInfo->is_mini, 825 ((1 << current_workspace()) & wInfo->workspaces) != 0, 826 false); 827 item->ExpandedItem(true); 828 teamMenu->AddItem(item, i + 1); 829 resize = true; 830 } 831 } 832 free(wInfo); 833 } 834 free(tokens); 835 } 836 } 837 } 838 839 // Remove any remaining items which require an update. 840 for (int32 i = 0; i < totalItems; i++) { 841 if (!teamMenu->SubmenuAt(i)){ 842 item = static_cast<TWindowMenuItem *>(teamMenu->ItemAt(i)); 843 if (item && item->RequiresUpdate()) { 844 item = static_cast<TWindowMenuItem *>(teamMenu->RemoveItem(i)); 845 delete item; 846 totalItems--; 847 848 resize = true; 849 } 850 } 851 } 852 853 // If any of the WindowMenuItems changed state, we need to force a repaint. 854 if (itemModified || resize) { 855 teamMenu->Invalidate(); 856 if (resize) 857 teamMenu->SizeWindow(); 858 } 859 860 teamMenu->Window()->Unlock(); 861 } 862 863 sMonLocker.Unlock(); 864 865 // sleep for a bit... 866 snooze(150000); 867 } 868 return B_OK; 869 } 870 871 872 void 873 TExpandoMenuBar::_FinishedDrag(bool invoke) 874 { 875 if (fPreviousDragTargetItem != NULL) { 876 if (invoke) 877 fPreviousDragTargetItem->Invoke(); 878 fPreviousDragTargetItem->SetOverrideSelected(false); 879 fPreviousDragTargetItem = NULL; 880 } 881 if (!invoke && fBarView->Dragging()) 882 fBarView->DragStop(true); 883 } 884 885