Open Tracker License
Terms and Conditions
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice applies to all licensees
and shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Be Incorporated shall not be
used in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from Be Incorporated.
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
trademarks of Be Incorporated in the United States and other countries. Other
brand product names are registered trademarks or trademarks of their respective
holders.
All rights reserved.
*/
#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;
}
specified \a point.
If \a _item is given, it will return the exact menu item under
that point (which might be a window item when the expander is on).
*/
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());
}
and need to add or remove in scroll arrows.
*/
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);
}