#include "ExpandoMenuBar.h"
#include <strings.h>
#include <map>
#include <Autolock.h>
#include <Bitmap.h>
#include <Collator.h>
#include <ControlLook.h>
#include <Debug.h>
#include <MenuPrivate.h>
#include <MessengerPrivate.h>
#include <NodeInfo.h>
#include <Roster.h>
#include <Screen.h>
#include <Thread.h>
#include <Window.h>
#include "icons.h"
#include "BarApp.h"
#include "BarMenuBar.h"
#include "BarView.h"
#include "BarWindow.h"
#include "DeskbarMenu.h"
#include "DeskbarUtils.h"
#include "InlineScrollView.h"
#include "ResourceSet.h"
#include "ShowHideMenuItem.h"
#include "StatusView.h"
#include "TeamMenu.h"
#include "TeamMenuItem.h"
#include "WindowMenu.h"
#include "WindowMenuItem.h"
bool TExpandoMenuBar::sDoMonitor = false;
thread_id TExpandoMenuBar::sMonThread = B_ERROR;
BLocker TExpandoMenuBar::sMonLocker("expando monitor");
typedef std::map<BString, TTeamMenuItem*> TeamMenuItemMap;
TExpandoMenuBar::TExpandoMenuBar(menu_layout layout, TBarView* barView)
:
BMenuBar(BRect(0, 0, 0, 0), "ExpandoMenuBar", B_FOLLOW_NONE, layout),
fBarView(barView),
fOverflow(false),
fUnderflow(false),
fFirstBuild(true),
fPreviousDragTargetItem(NULL),
fLastMousedOverItem(NULL),
fLastClickedItem(NULL),
fLastClickTime(0)
{
SetItemMargins(0.0f, 0.0f, 0.0f, 0.0f);
SetFont(be_plain_font);
}
void
TExpandoMenuBar::AllAttached()
{
BMenuBar::AllAttached();
SizeWindow(0);
}
void
TExpandoMenuBar::AttachedToWindow()
{
BMenuBar::AttachedToWindow();
fTeamList.MakeEmpty();
if (Vertical())
StartMonitoringWindows();
}
void
TExpandoMenuBar::DetachedFromWindow()
{
BMenuBar::DetachedFromWindow();
StopMonitoringWindows();
BMessenger self(this);
BMessage message(kUnsubscribe);
message.AddMessenger("messenger", self);
be_app->PostMessage(&message);
RemoveItems(0, CountItems(), true);
}
void
TExpandoMenuBar::MessageReceived(BMessage* message)
{
int32 index;
TTeamMenuItem* item;
switch (message->what) {
case B_SOME_APP_LAUNCHED:
{
BList* teams = NULL;
message->FindPointer("teams", (void**)&teams);
BBitmap* icon = NULL;
message->FindPointer("icon", (void**)&icon);
const char* signature = NULL;
message->FindString("sig", &signature);
uint32 flags = 0;
message->FindInt32("flags", ((int32*) &flags));
const char* name = NULL;
message->FindString("name", &name);
AddTeam(teams, icon, strdup(name), strdup(signature));
break;
}
case B_MOUSE_WHEEL_CHANGED:
{
float deltaY = 0;
message->FindFloat("be:wheel_delta_y", &deltaY);
if (deltaY == 0)
return;
TInlineScrollView* scrollView
= dynamic_cast<TInlineScrollView*>(Parent());
if (scrollView == NULL || !scrollView->HasScrollers())
return;
float largeStep;
float smallStep;
scrollView->GetSteps(&smallStep, &largeStep);
if (modifiers() & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY))
deltaY *= largeStep;
else
deltaY *= smallStep;
scrollView->ScrollBy(deltaY);
break;
}
case kAddTeam:
AddTeam(message->FindInt32("team"), message->FindString("sig"));
break;
case kRemoveTeam:
{
team_id team = -1;
message->FindInt32("team", &team);
RemoveTeam(team, true);
break;
}
case B_SOME_APP_QUIT:
{
team_id team = -1;
message->FindInt32("team", &team);
RemoveTeam(team, false);
break;
}
case kMinimizeTeam:
{
index = message->FindInt32("itemIndex");
item = dynamic_cast<TTeamMenuItem*>(ItemAt(index));
if (item == NULL)
break;
TShowHideMenuItem::TeamShowHideCommon(B_MINIMIZE_WINDOW,
item->Teams(), item->Menu()->ConvertToScreen(item->Frame()),
true);
break;
}
case kBringTeamToFront:
{
index = message->FindInt32("itemIndex");
item = dynamic_cast<TTeamMenuItem*>(ItemAt(index));
if (item == NULL)
break;
TShowHideMenuItem::TeamShowHideCommon(B_BRING_TO_FRONT,
item->Teams(), item->Menu()->ConvertToScreen(item->Frame()),
true);
break;
}
default:
BMenuBar::MessageReceived(message);
break;
}
}
void
TExpandoMenuBar::MouseDown(BPoint where)
{
if (fBarView == NULL || fBarView->Dragging())
return BMenuBar::MouseDown(where);
BMessage* message = Window()->CurrentMessage();
BMenuItem* item = ItemAtPoint(where);
fLastClickedItem = item;
if (message == NULL || item == NULL)
return BMenuBar::MouseDown(where);
int32 modifiers = 0;
int32 buttons = 0;
message->FindInt32("modifiers", &modifiers);
message->FindInt32("buttons", &buttons);
if ((modifiers & B_SHIFT_KEY) != 0
&& (buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
TWindowMenuItem* wItem = dynamic_cast<TWindowMenuItem*>(item);
if (wItem != NULL) {
BMessenger messenger;
client_window_info* info = get_window_info(wItem->ID());
if (info != NULL) {
BMessenger::Private(messenger).SetTo(info->team,
info->client_port, info->client_token);
messenger.SendMessage(B_QUIT_REQUESTED);
free(info);
return;
}
}
}
TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(item);
if (teamItem == NULL)
return BMenuBar::MouseDown(where);
if (teamItem->HandleMouseDown(where))
return;
if (Vertical() && static_cast<TBarApp*>(be_app)->Settings()->superExpando
&& teamItem->ExpanderBounds().Contains(where)) {
teamItem->SetArrowDirection(BControlLook::B_RIGHT_DOWN_ARROW);
SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
Invalidate(teamItem->ExpanderBounds());
return;
}
int32 clicks;
bigtime_t clickSpeed = 0;
get_click_speed(&clickSpeed);
bigtime_t delta = system_time() - fLastClickTime;
if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1
&& item == fLastClickedItem && delta <= clickSpeed) {
be_roster->ActivateApp((addr_t)teamItem->Teams()->ItemAt(0));
return;
}
fLastClickTime = system_time();
BMenuBar::MouseDown(where);
}
void
TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message)
{
int32 buttons;
BMessage* currentMessage = Window()->CurrentMessage();
if (currentMessage == NULL
|| currentMessage->FindInt32("buttons", &buttons) != B_OK) {
buttons = 0;
}
if (message == NULL) {
_FinishedDrag();
if (Vertical() && buttons != 0
&& static_cast<TBarApp*>(be_app)->Settings()->superExpando) {
TTeamMenuItem* lastItem
= dynamic_cast<TTeamMenuItem*>(fLastClickedItem);
if (lastItem != NULL) {
if (lastItem->ExpanderBounds().Contains(where))
lastItem->SetArrowDirection(
BControlLook::B_RIGHT_DOWN_ARROW);
else {
lastItem->SetArrowDirection(lastItem->IsExpanded()
? BControlLook::B_DOWN_ARROW
: BControlLook::B_RIGHT_ARROW);
}
Invalidate(lastItem->ExpanderBounds());
}
}
if (code == B_INSIDE_VIEW) {
TTruncatableMenuItem* item;
TTeamMenuItem* teamItem = TeamItemAtPoint(where, (BMenuItem**)&item);
if (item == NULL) {
fLastMousedOverItem = NULL;
SetToolTip((const char*)NULL);
} else if (item != fLastMousedOverItem) {
if ((static_cast<TBarApp*>(be_app)->Settings()->hideLabels
&& teamItem != NULL)
|| strcasecmp(item->TruncatedLabel(), item->Label()) > 0) {
SetToolTip(item->Label());
} else
SetToolTip((const char*)NULL);
fLastMousedOverItem = item;
}
}
BMenuBar::MouseMoved(where, code, message);
return;
}
if (buttons == 0)
return;
switch (code) {
case B_ENTERED_VIEW:
if (fPreviousDragTargetItem != NULL)
_FinishedDrag();
fBarView->CacheDragData(message);
fPreviousDragTargetItem = NULL;
break;
case B_OUTSIDE_VIEW:
case B_EXITED_VIEW:
_FinishedDrag();
break;
case B_INSIDE_VIEW:
if (fBarView != NULL && fBarView->Dragging()) {
TTeamMenuItem* item = NULL;
int32 itemCount = CountItems();
for (int32 i = 0; i < itemCount; i++) {
BMenuItem* _item = ItemAt(i);
if (_item->Frame().Contains(where)) {
item = dynamic_cast<TTeamMenuItem*>(_item);
break;
}
}
if (item == fPreviousDragTargetItem)
break;
if (fPreviousDragTargetItem != NULL)
fPreviousDragTargetItem->SetOverrideSelected(false);
if (item != NULL)
item->SetOverrideSelected(true);
fPreviousDragTargetItem = item;
}
break;
}
}
void
TExpandoMenuBar::MouseUp(BPoint where)
{
if (fBarView != NULL && fBarView->Dragging()) {
_FinishedDrag(true);
return;
}
if (fLastClickedItem == NULL)
return BMenuBar::MouseUp(where);
TTeamMenuItem* lastItem = dynamic_cast<TTeamMenuItem*>(fLastClickedItem);
fLastClickedItem = NULL;
if (Vertical() && static_cast<TBarApp*>(be_app)->Settings()->superExpando
&& lastItem != NULL && lastItem->ExpanderBounds().Contains(where)) {
lastItem->ToggleExpandState(true);
lastItem->SetArrowDirection(lastItem->IsExpanded()
? BControlLook::B_DOWN_ARROW
: BControlLook::B_RIGHT_ARROW);
Invalidate(lastItem->ExpanderBounds());
}
BMenuBar::MouseUp(where);
}
void
TExpandoMenuBar::BuildItems()
{
BMessenger self(this);
TBarApp::Subscribe(self, &fTeamList);
desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings();
float itemWidth = -1.0f;
if (Vertical() && (fBarView->ExpandoState() || fBarView->FullState())) {
itemWidth = settings->width;
}
SetMaxContentWidth(itemWidth);
TeamMenuItemMap items;
int32 itemCount = CountItems();
BList itemList(itemCount);
for (int32 i = 0; i < itemCount; i++) {
BMenuItem* menuItem = RemoveItem((int32)0);
itemList.AddItem(menuItem);
TTeamMenuItem* item = dynamic_cast<TTeamMenuItem*>(menuItem);
if (item != NULL)
items[BString(item->Signature()).ToLower()] = item;
}
if (settings->sortRunningApps)
fTeamList.SortItems(TTeamMenu::CompareByName);
int32 teamCount = fTeamList.CountItems();
for (int32 i = 0; i < teamCount; i++) {
BarTeamInfo* barInfo = (BarTeamInfo*)fTeamList.ItemAt(i);
TeamMenuItemMap::const_iterator iter
= items.find(BString(barInfo->sig).ToLower());
if (iter == items.end()) {
TTeamMenuItem* item = new TTeamMenuItem(barInfo->teams,
barInfo->icon, barInfo->name, barInfo->sig, itemWidth);
if (settings->trackerAlwaysFirst
&& strcasecmp(barInfo->sig, kTrackerSignature) == 0) {
AddItem(item, 0);
} else
AddItem(item);
if (fFirstBuild && Vertical() && settings->expandNewTeams)
item->ToggleExpandState(true);
} else {
TTeamMenuItem* item = iter->second;
item->SetIcon(barInfo->icon);
item->SetOverrideWidth(itemWidth);
if (settings->trackerAlwaysFirst
&& strcasecmp(barInfo->sig, kTrackerSignature) == 0) {
AddItem(item, 0);
} else
AddItem(item);
int32 index = itemList.IndexOf(item);
TWindowMenuItem* windowItem;
TWindowMenu* submenu = dynamic_cast<TWindowMenu*>(item->Submenu());
bool hasWindowItems = false;
while ((windowItem = dynamic_cast<TWindowMenuItem*>(
(BMenuItem*)(itemList.ItemAt(++index)))) != NULL) {
if (Vertical())
AddItem(windowItem);
else {
delete windowItem;
hasWindowItems = submenu != NULL;
}
}
if (Vertical() && !settings->superExpando && item->IsExpanded())
item->ToggleExpandState(false);
if (hasWindowItems) {
submenu->SetExpanded(false, 0);
submenu->AttachedToWindow();
}
}
}
if (CountItems() == 0) {
ResizeTo(gMinimumWindowWidth, 0);
} else {
fFirstBuild = false;
}
}
bool
TExpandoMenuBar::InDeskbarMenu(BPoint loc) const
{
TBarWindow* window = dynamic_cast<TBarWindow*>(Window());
if (window != NULL) {
if (TDeskbarMenu* bemenu = window->DeskbarMenu()) {
bool inDeskbarMenu = false;
if (bemenu->LockLooper()) {
inDeskbarMenu = bemenu->Frame().Contains(loc);
bemenu->UnlockLooper();
}
return inDeskbarMenu;
}
}
return false;
}
BMenuItem*
TExpandoMenuBar::ItemAtPoint(BPoint point)
{
int32 itemCount = CountItems();
for (int32 index = 0; index < itemCount; index++) {
BMenuItem* item = ItemAt(index);
if (item != NULL && item->Frame().Contains(point))
return item;
}
return NULL;
}
TTeamMenuItem*
TExpandoMenuBar::TeamItemAtPoint(BPoint point, BMenuItem** _item)
{
TTeamMenuItem* lastApp = NULL;
int32 itemCount = CountItems();
for (int32 index = 0; index < itemCount; index++) {
BMenuItem* item = ItemAt(index);
if (item != NULL && item->Frame().Contains(point)) {
if (dynamic_cast<TTeamMenuItem*>(item) != NULL)
lastApp = (TTeamMenuItem*)item;
if (_item != NULL)
*_item = item;
return lastApp;
}
}
if (_item != NULL)
*_item = NULL;
return NULL;
}
void
TExpandoMenuBar::AddTeam(BList* team, BBitmap* icon, char* name,
char* signature)
{
TTeamMenuItem* item = new TTeamMenuItem(team, icon, name, signature);
desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings();
if (settings != NULL && settings->trackerAlwaysFirst
&& strcasecmp(signature, kTrackerSignature) == 0) {
AddItem(item, 0);
} else if (settings->sortRunningApps) {
TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(ItemAt(0));
int32 firstApp = 0;
if (settings->trackerAlwaysFirst && teamItem != NULL
&& strcasecmp(teamItem->Signature(), kTrackerSignature) == 0) {
firstApp++;
}
BCollator collator;
BLocale::Default()->GetCollator(&collator);
int32 i = firstApp;
int32 itemCount = CountItems();
while (i < itemCount) {
teamItem = dynamic_cast<TTeamMenuItem*>(ItemAt(i));
if (teamItem != NULL && collator.Compare(teamItem->Label(), name)
> 0) {
AddItem(item, i);
break;
}
i++;
}
if (i == itemCount)
AddItem(item);
} else
AddItem(item);
if (Vertical() && settings != NULL && settings->superExpando
&& settings->expandNewTeams) {
item->ToggleExpandState(false);
}
SizeWindow(1);
Window()->UpdateIfNeeded();
}
void
TExpandoMenuBar::AddTeam(team_id team, const char* signature)
{
int32 itemCount = CountItems();
for (int32 i = 0; i < itemCount; i++) {
TTeamMenuItem* item = dynamic_cast<TTeamMenuItem*>(ItemAt(i));
if (item != NULL && strcasecmp(item->Signature(), signature) == 0
&& !(item->Teams()->HasItem((void*)(addr_t)team))) {
item->Teams()->AddItem((void*)(addr_t)team);
break;
}
}
}
void
TExpandoMenuBar::RemoveTeam(team_id team, bool partial)
{
TWindowMenuItem* windowItem = NULL;
for (int32 i = CountItems() - 1; i >= 0; i--) {
TTeamMenuItem* item = dynamic_cast<TTeamMenuItem*>(ItemAt(i));
if (item != NULL && item->Teams()->HasItem((void*)(addr_t)team)) {
item->Teams()->RemoveItem(team);
if (partial)
return;
BAutolock locker(sMonLocker);
RemoveItem(i);
if (item == fPreviousDragTargetItem)
fPreviousDragTargetItem = NULL;
if (item == fLastMousedOverItem)
fLastMousedOverItem = NULL;
if (item == fLastClickedItem)
fLastClickedItem = NULL;
delete item;
while ((windowItem = dynamic_cast<TWindowMenuItem*>(
ItemAt(i))) != NULL) {
RemoveItem(i);
if (windowItem == fLastMousedOverItem)
fLastMousedOverItem = NULL;
if (windowItem == fLastClickedItem)
fLastClickedItem = NULL;
delete windowItem;
}
SizeWindow(-1);
Window()->UpdateIfNeeded();
return;
}
}
}
void
TExpandoMenuBar::CheckItemSizes(int32 delta, bool reset)
{
if (fBarView == NULL || Vertical())
return;
int32 itemCount = CountItems();
if (itemCount < 2)
return;
float minItemWidth = MinHorizontalItemWidth();
float maxItemWidth = MaxHorizontalItemWidth();
float maxMenuWidth = maxItemWidth * itemCount;
float maxWidth = MaxHorizontalWidth();
bool tooWide = maxMenuWidth > maxWidth;
float newItemWidth = maxItemWidth;
if (delta < 0 && fOverflow) {
if (tooWide)
newItemWidth = floorf(maxWidth / itemCount);
else
newItemWidth = maxItemWidth;
} else if (tooWide) {
fOverflow = true;
newItemWidth = std::min(floorf(maxWidth / itemCount), maxItemWidth);
}
fUnderflow = delta < 0 && newItemWidth < maxItemWidth;
if (fOverflow || fUnderflow || fFirstBuild || reset) {
if (newItemWidth > maxItemWidth)
newItemWidth = maxItemWidth;
else if (newItemWidth < minItemWidth)
newItemWidth = minItemWidth;
SetMaxContentWidth(newItemWidth);
if (newItemWidth == maxItemWidth)
fOverflow = false;
for (int32 index = 0; ; index++) {
TTeamMenuItem* item = (TTeamMenuItem*)ItemAt(index);
if (item == NULL)
break;
item->SetOverrideWidth(newItemWidth);
}
InvalidateLayout();
ResizeTo(newItemWidth * itemCount, Frame().Height());
}
}
float
TExpandoMenuBar::MinHorizontalItemWidth()
{
const int32 iconSize = static_cast<TBarApp*>(be_app)->TeamIconSize();
const float iconPadding = be_control_look->ComposeSpacing(kIconPadding);
float iconOnlyWidth = iconSize + iconPadding;
const int32 min = be_control_look->ComposeIconSize(kMinimumIconSize)
.IntegerWidth() + 1;
return static_cast<TBarApp*>(be_app)->Settings()->hideLabels
? iconOnlyWidth
: (iconSize - min) + gMinimumWindowWidth
+ (be_plain_font->Size() - 12) * 4;
}
float
TExpandoMenuBar::MaxHorizontalItemWidth()
{
const int32 iconSize = static_cast<TBarApp*>(be_app)->TeamIconSize();
const float iconPadding = be_control_look->ComposeSpacing(kIconPadding);
float iconOnlyWidth = iconSize + iconPadding;
if (static_cast<TBarApp*>(be_app)->Settings()->hideLabels)
return iconOnlyWidth + iconPadding;
return floorf(MinHorizontalItemWidth() * 1.25);
}
menu_layout
TExpandoMenuBar::MenuLayout() const
{
return Layout();
}
void
TExpandoMenuBar::SetMenuLayout(menu_layout layout)
{
BPrivate::MenuPrivate(this).SetLayout(layout);
InvalidateLayout();
}
void
TExpandoMenuBar::Draw(BRect updateRect)
{
BMenu::Draw(updateRect);
}
void
TExpandoMenuBar::DrawBackground(BRect updateRect)
{
if (Vertical())
return;
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), 1.22));
StrokeLine(Bounds().RightTop(), Bounds().RightBottom());
}
bool
TExpandoMenuBar::CheckForSizeOverrun()
{
if (Vertical())
return CheckForSizeOverrunVertical();
else
return CheckForSizeOverrunHorizontal();
}
bool
TExpandoMenuBar::CheckForSizeOverrunVertical()
{
if (Window() == NULL || !Vertical())
return false;
return Window()->Frame().bottom > (BScreen(Window())).Frame().bottom;
}
bool
TExpandoMenuBar::CheckForSizeOverrunHorizontal()
{
if (fBarView == NULL || Vertical())
return false;
int32 itemCount = CountItems();
if (itemCount < 2)
return false;
float minMenuWidth = MinHorizontalItemWidth() * itemCount;
float maxWidth = MaxHorizontalWidth();
return minMenuWidth > maxWidth;
}
float
TExpandoMenuBar::MaxHorizontalWidth()
{
return (BScreen(Window())).Frame().Width()
- fBarView->DragRegion()->Frame().Width() - 1
- fBarView->BarMenuBar()->Frame().Width();
}
void
TExpandoMenuBar::SizeWindow(int32 delta)
{
if (fBarView == NULL || Window() == NULL)
return;
BRect screenFrame = (BScreen(Window())).Frame();
fBarView->SizeWindow(screenFrame);
fBarView->PositionWindow(screenFrame);
if (!Vertical())
CheckItemSizes(delta);
fBarView->CheckForScrolling();
Window()->UpdateIfNeeded();
Invalidate();
}
void
TExpandoMenuBar::StartMonitoringWindows()
{
if (sMonThread != B_ERROR)
return;
sDoMonitor = true;
sMonThread = spawn_thread(monitor_team_windows,
"Expando Window Watcher", B_LOW_PRIORITY, this);
resume_thread(sMonThread);
}
void
TExpandoMenuBar::StopMonitoringWindows()
{
if (sMonThread == B_ERROR)
return;
sDoMonitor = false;
status_t returnCode;
wait_for_thread(sMonThread, &returnCode);
sMonThread = B_ERROR;
}
int32
TExpandoMenuBar::monitor_team_windows(void* arg)
{
TExpandoMenuBar* teamMenu = (TExpandoMenuBar*)arg;
while (teamMenu->sDoMonitor) {
sMonLocker.Lock();
if (teamMenu->Window()->LockWithTimeout(50000) == B_OK) {
int32 totalItems = teamMenu->CountItems();
TWindowMenuItem* item = NULL;
for (int32 i = 0; i < totalItems; i++) {
if (!teamMenu->SubmenuAt(i)) {
item = static_cast<TWindowMenuItem*>(teamMenu->ItemAt(i));
item->SetRequireUpdate(true);
}
}
bool itemModified = false;
bool resize = false;
TTeamMenuItem* teamItem = NULL;
for (int32 i = 0; i < totalItems; i++) {
if (teamMenu->SubmenuAt(i) == NULL)
continue;
teamItem = static_cast<TTeamMenuItem*>(teamMenu->ItemAt(i));
if (teamItem->IsExpanded()) {
int32 teamCount = teamItem->Teams()->CountItems();
for (int32 j = 0; j < teamCount; j++) {
team_id theTeam = (addr_t)teamItem->Teams()->ItemAt(j);
int32 count = 0;
int32* tokens = get_token_list(theTeam, &count);
for (int32 k = 0; k < count; k++) {
client_window_info* wInfo
= get_window_info(tokens[k]);
if (wInfo == NULL)
continue;
BString windowName(wInfo->name);
BString teamPrefix(teamItem->Label());
teamPrefix.Append(": ");
BString teamSuffix(" - ");
teamSuffix.Append(teamItem->Label());
if (windowName.StartsWith(teamPrefix))
windowName.RemoveFirst(teamPrefix);
if (windowName.EndsWith(teamSuffix))
windowName.RemoveLast(teamSuffix);
if (TWindowMenu::WindowShouldBeListed(wInfo)) {
item = teamItem->ExpandedWindowItem(
wInfo->server_token);
if (item != NULL) {
item->SetTo(windowName,
wInfo->server_token, wInfo->is_mini,
((1 << current_workspace())
& wInfo->workspaces) != 0);
if (strcasecmp(item->Label(), windowName)
> 0) {
item->SetLabel(windowName);
}
if (item->Modified())
itemModified = true;
} else if (teamItem->IsExpanded()) {
item = new TWindowMenuItem(windowName,
wInfo->server_token, wInfo->is_mini,
((1 << current_workspace())
& wInfo->workspaces) != 0, false);
item->SetExpanded(true);
teamMenu->AddItem(item,
TWindowMenuItem::InsertIndexFor(
teamMenu, i + 1, item));
resize = true;
}
}
free(wInfo);
}
free(tokens);
}
}
}
for (int32 i = 0; i < totalItems; i++) {
if (!teamMenu->SubmenuAt(i)) {
item = static_cast<TWindowMenuItem*>(teamMenu->ItemAt(i));
if (item && item->RequiresUpdate()) {
item = static_cast<TWindowMenuItem*>
(teamMenu->RemoveItem(i));
delete item;
totalItems--;
resize = true;
}
}
}
if (itemModified || resize) {
teamMenu->Invalidate();
if (resize)
teamMenu->SizeWindow(1);
}
teamMenu->Window()->Unlock();
}
sMonLocker.Unlock();
snooze(150000);
}
return B_OK;
}
void
TExpandoMenuBar::_FinishedDrag(bool invoke)
{
if (fPreviousDragTargetItem != NULL) {
if (invoke)
fPreviousDragTargetItem->Invoke();
fPreviousDragTargetItem->SetOverrideSelected(false);
fPreviousDragTargetItem = NULL;
}
if (!invoke && fBarView != NULL && fBarView->Dragging())
fBarView->DragStop(true);
}