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