void TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message) { if (!message) { // force a cleanup _FinishedDrag(); BMenuBar::MouseMoved(where, code, message); return; } uint32 buttons; if (!(Window()->CurrentMessage()) || Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons) < B_OK) buttons = 0; if (buttons == 0) return; switch (code) { case B_ENTERED_VIEW: // fPreviousDragTargetItem should always be NULL here anyways. if (fPreviousDragTargetItem) _FinishedDrag(); fBarView->CacheDragData(message); fPreviousDragTargetItem = NULL; break; case B_OUTSIDE_VIEW: // NOTE: Should not be here, but for the sake of defensive // programming... case B_EXITED_VIEW: _FinishedDrag(); break; case B_INSIDE_VIEW: if (fBarView->Dragging()) { TTeamMenuItem* item = NULL; for (int32 i = 0; i < CountItems(); 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::AddTeam(team_id team, const char* signature) { int32 itemCount = CountItems(); for (int32 i = 0; i < itemCount; i++) { // Only add to team menu items 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::CheckItemSizes(int32 delta) { float width = Frame().Width(); int32 count = CountItems(); bool reset = false; float newWidth = 0; float fullWidth = (sMinimumWindowWidth * count); if (!fBarView->Vertical()) { // in this case there are 2 extra items: // - The Be Menu // - The little separator item fullWidth = fullWidth - (sMinimumWindowWidth * 2) + (fBeMenuWidth + kSepItemWidth); width -= (fBeMenuWidth + kSepItemWidth); count -= 2; } if (delta >= 0 && fullWidth > width) { fOverflow = true; reset = true; newWidth = floorf(width / count); } else if (delta < 0 && fOverflow) { reset = true; if (fullWidth > width) newWidth = floorf(width / count); else newWidth = sMinimumWindowWidth; } if (newWidth > sMinimumWindowWidth) newWidth = sMinimumWindowWidth; if (reset) { SetMaxContentWidth(newWidth); if (newWidth == sMinimumWindowWidth) fOverflow = false; InvalidateLayout(); for (int32 index = fFirstApp; ; index++) { TTeamMenuItem* item = (TTeamMenuItem*)ItemAt(index); if (!item) break; item->SetOverrideWidth(newWidth); } Invalidate(); Window()->UpdateIfNeeded(); } }
void TExpandoMenuBar::AddTeam(BList* team, BBitmap* icon, char* name, char* signature) { float itemWidth = fVertical ? fBarView->Bounds().Width() : sMinimumWindowWidth; float itemHeight = -1.0f; desk_settings* settings = ((TBarApp*)be_app)->Settings(); TTeamMenuItem* item = new TTeamMenuItem(team, icon, name, signature, itemWidth, itemHeight, fDrawLabel, fVertical); if (settings->trackerAlwaysFirst && !strcmp(signature, kTrackerSignature)) { AddItem(item, fFirstApp); } else if (settings->sortRunningApps) { TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(ItemAt(fFirstApp)); int32 firstApp = fFirstApp; // if Tracker should always be the first item, we need to skip it // when sorting in the current item if (settings->trackerAlwaysFirst && teamItem != NULL && !strcmp(teamItem->Signature(), kTrackerSignature)) { firstApp++; } int32 count = CountItems(), i; for (i = firstApp; i < count; i++) { teamItem = dynamic_cast<TTeamMenuItem*>(ItemAt(i)); if (teamItem != NULL && strcasecmp(teamItem->Name(), name) > 0) { AddItem(item, i); break; } } // was the item added to the list yet? if (i == count) AddItem(item); } else AddItem(item); if (fVertical) { if (item && fShowTeamExpander && fExpandNewTeams) item->ToggleExpandState(false); fBarView->SizeWindow(BScreen(Window()).Frame()); } else CheckItemSizes(1); Window()->UpdateIfNeeded(); }
void TBarView::SaveExpandedItems() { if (fExpando == NULL || fExpando->CountItems() <= 0) return; // Get a list of the signatures of expanded apps. Can't use // team_id because there can be more than one team per application for (int32 i = 0; i < fExpando->CountItems(); i++) { TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(fExpando->ItemAt(i)); if (teamItem != NULL && teamItem->IsExpanded()) AddExpandedItem(teamItem->Signature()); } }
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); // make the update thread wait 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) { // Also remove window items (if there are any) RemoveItem(i); if (windowItem == fLastMousedOverItem) fLastMousedOverItem = NULL; if (windowItem == fLastClickedItem) fLastClickedItem = NULL; delete windowItem; } SizeWindow(-1); Window()->UpdateIfNeeded(); return; } } }
void TBarView::ExpandItems() { if (fExpandoMenuBar == NULL || !fVertical || fState != kExpandoState || !fBarApp->Settings()->superExpando || fExpandedItems.CountItems() <= 0) { return; } // Start at the 'bottom' of the list working up. // Prevents being thrown off by expanding items. for (int32 i = fExpandoMenuBar->CountItems() - 1; i >= 0; i--) { TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(fExpandoMenuBar->ItemAt(i)); if (teamItem != NULL) { // Start at the 'bottom' of the fExpandedItems list working up // matching the order of the fExpandoMenuBar list in the outer loop. for (int32 j = fExpandedItems.CountItems() - 1; j >= 0; j--) { BString* itemSig = static_cast<BString*>(fExpandedItems.ItemAt(j)); if (itemSig->Compare(teamItem->Signature()) == 0) { // Found it, expand the item and delete signature from // the list so that we don't consider it for later items. teamItem->ToggleExpandState(false); fExpandedItems.RemoveItem(j); delete itemSig; break; } } } } // Clean up the expanded items list RemoveExpandedItems(); }
void TExpandoMenuBar::_DoneTracking(BPoint point) { TTeamMenuItem* lastItem = dynamic_cast<TTeamMenuItem*>(fLastClickedItem); if (lastItem == NULL) return; if (!lastItem->ExpanderBounds().Contains(point)) return; lastItem->ToggleExpandState(true); lastItem->SetArrowDirection(lastItem->IsExpanded() ? BControlLook::B_DOWN_ARROW : BControlLook::B_RIGHT_ARROW); Invalidate(lastItem->ExpanderBounds()); }
void TExpandoMenuBar::_Track(BPoint point, uint32) { TTeamMenuItem* lastItem = dynamic_cast<TTeamMenuItem*>(fLastClickedItem); if (lastItem == NULL) return; if (lastItem->ExpanderBounds().Contains(point)) lastItem->SetArrowDirection(BControlLook::B_RIGHT_DOWN_ARROW); else { lastItem->SetArrowDirection(lastItem->IsExpanded() ? BControlLook::B_DOWN_ARROW : BControlLook::B_RIGHT_ARROW); } Invalidate(lastItem->ExpanderBounds()); }
void TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message) { if (message == NULL) { // force a cleanup _FinishedDrag(); switch (code) { case B_ENTERED_VIEW: case B_INSIDE_VIEW: { TTeamMenuItem* item = TeamItemAtPoint(where); if (item == NULL) { // item is NULL, break out fLastMousedOverItem = NULL; break; } if (item->HasLabel()) { // item has a visible label, set the item and break out fLastMousedOverItem = item; break; } if (item == fLastMousedOverItem) { // already set the tooltip for this item, break out break; } // new item, update the tooltip with the item name SetToolTip(item->Name()); // save the current item for the next MouseMoved() call fLastMousedOverItem = item; break; } case B_OUTSIDE_VIEW: case B_EXITED_VIEW: fLastMousedOverItem = NULL; break; } BMenuBar::MouseMoved(where, code, message); return; } uint32 buttons; if (Window()->CurrentMessage() == NULL || Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons) < B_OK) { buttons = 0; } if (buttons == 0) return; switch (code) { case B_ENTERED_VIEW: // fPreviousDragTargetItem should always be NULL here anyways. if (fPreviousDragTargetItem) _FinishedDrag(); fBarView->CacheDragData(message); fPreviousDragTargetItem = NULL; break; case B_OUTSIDE_VIEW: // NOTE: Should not be here, but for the sake of defensive // programming... case B_EXITED_VIEW: _FinishedDrag(); break; case B_INSIDE_VIEW: if (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::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) return; float largeStep; float smallStep; scrollView->GetSteps(&smallStep, &largeStep); // pressing the option/command/control key scrolls faster 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::CheckItemSizes(int32 delta) { if (fBarView->Vertical()) return; int32 iconSize = static_cast<TBarApp*>(be_app)->IconSize(); float maxContentWidth = sMinimumWindowWidth + iconSize - kMinimumIconSize; // There are 2 extra items: // The Be Menu // The little separator item int32 count = CountItems() - 2; float maxWidth = Frame().Width() - fDeskbarMenuWidth - kSepItemWidth * 2; float fullWidth = maxContentWidth * count + fDeskbarMenuWidth + kSepItemWidth; float iconOnlyWidth = kIconPadding + iconSize + kIconPadding; bool reset = false; float newWidth = 0.0f; if (delta >= 0 && fullWidth > maxWidth) { fOverflow = true; reset = true; if (fDrawLabel) newWidth = floorf(maxWidth / count); else newWidth = iconOnlyWidth; } else if (delta < 0 && fOverflow) { reset = true; if (fullWidth > maxWidth) { if (fDrawLabel) newWidth = floorf(maxWidth / count); else newWidth = iconOnlyWidth; } else newWidth = maxContentWidth; } if (newWidth > maxContentWidth) newWidth = maxContentWidth; if (reset) { SetMaxContentWidth(newWidth); if (newWidth == maxContentWidth) fOverflow = false; InvalidateLayout(); for (int32 index = fFirstApp; ; index++) { TTeamMenuItem* item = (TTeamMenuItem*)ItemAt(index); if (!item) break; if (!fDrawLabel && newWidth > iconOnlyWidth) { item->SetOverrideWidth(iconOnlyWidth); } else { item->SetOverrideWidth(newWidth); } } Invalidate(); Window()->UpdateIfNeeded(); } }
void TExpandoMenuBar::MouseDown(BPoint where) { BMessage* message = Window()->CurrentMessage(); BMenuItem* menuItem; TTeamMenuItem* item = TeamItemAtPoint(where, &menuItem); // check for three finger salute, a.k.a. Vulcan Death Grip if (message != NULL && item != NULL && !fBarView->Dragging()) { int32 modifiers = 0; message->FindInt32("modifiers", &modifiers); if ((modifiers & B_COMMAND_KEY) != 0 && (modifiers & B_CONTROL_KEY) != 0 && (modifiers & B_SHIFT_KEY) != 0) { const BList* teams = item->Teams(); int32 teamCount = teams->CountItems(); team_id teamID; for (int32 team = 0; team < teamCount; team++) { teamID = (team_id)teams->ItemAt(team); kill_team(teamID); // remove the team immediately from display RemoveTeam(teamID, false); } return; } // control click - show all/hide all shortcut if ((modifiers & B_CONTROL_KEY) != 0) { // show/hide item's teams BMessage showMessage((modifiers & B_SHIFT_KEY) != 0 ? kMinimizeTeam : kBringTeamToFront); showMessage.AddInt32("itemIndex", IndexOf(item)); Window()->PostMessage(&showMessage, this); return; } // Check the bounds of the expand Team icon if (fShowTeamExpander && fVertical) { BRect expanderRect = item->ExpanderBounds(); if (expanderRect.Contains(where)) { // Let the update thread wait... BAutolock locker(sMonLocker); // Toggle the item item->ToggleExpandState(true); item->Draw(); // Absorb the message. return; } } // double-click on an item brings the team to front int32 clicks; if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1 && item == menuItem && item == fLastClickItem) { // activate this team be_roster->ActivateApp((team_id)item->Teams()->ItemAt(0)); return; } fLastClickItem = item; } BMenuBar::MouseDown(where); }
void TExpandoMenuBar::MouseDown(BPoint where) { BMessage* message = Window()->CurrentMessage(); BMenuItem* menuItem; TTeamMenuItem* item = TeamItemAtPoint(where, &menuItem); if (message == NULL || item == NULL || fBarView->Dragging()) { BMenuBar::MouseDown(where); return; } int32 modifiers = 0; message->FindInt32("modifiers", &modifiers); // check for three finger salute, a.k.a. Vulcan Death Grip if ((modifiers & B_COMMAND_KEY) != 0 && (modifiers & B_CONTROL_KEY) != 0 && (modifiers & B_SHIFT_KEY) != 0) { const BList* teams = item->Teams(); int32 teamCount = teams->CountItems(); team_id teamID; for (int32 team = 0; team < teamCount; team++) { teamID = (addr_t)teams->ItemAt(team); kill_team(teamID); RemoveTeam(teamID, false); // remove the team from display immediately } return; // absorb the message } // control click - show all/hide all shortcut if ((modifiers & B_CONTROL_KEY) != 0) { // show/hide item's teams BMessage showMessage((modifiers & B_SHIFT_KEY) != 0 ? kMinimizeTeam : kBringTeamToFront); showMessage.AddInt32("itemIndex", IndexOf(item)); Window()->PostMessage(&showMessage, this); return; // absorb the message } // check if within expander bounds to expand window items if (fVertical && static_cast<TBarApp*>(be_app)->Settings()->superExpando && item->ExpanderBounds().Contains(where)) { // start the animation here, finish on mouse up fLastClickedItem = item; MouseDownThread<TExpandoMenuBar>::TrackMouse(this, &TExpandoMenuBar::_DoneTracking, &TExpandoMenuBar::_Track); Invalidate(item->ExpanderBounds()); return; // absorb the message } // double-click on an item brings the team to front int32 clicks; if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1 && item == menuItem && item == fLastClickedItem) { be_roster->ActivateApp((addr_t)item->Teams()->ItemAt(0)); // activate this team return; // absorb the message } fLastClickedItem = item; 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) { // force a cleanup _FinishedDrag(); switch (code) { case B_INSIDE_VIEW: { BMenuItem* menuItem; TTeamMenuItem* item = TeamItemAtPoint(where, &menuItem); TWindowMenuItem* windowMenuItem = dynamic_cast<TWindowMenuItem*>(menuItem); if (item == NULL || menuItem == NULL) { // item is NULL, remove the tooltip and break out fLastMousedOverItem = NULL; SetToolTip((const char*)NULL); break; } if (menuItem == fLastMousedOverItem) { // already set the tooltip for this item, break out break; } if (windowMenuItem != NULL && fBarView->Vertical() && fBarView->ExpandoState() && item->IsExpanded()) { // expando mode window menu item fLastMousedOverItem = menuItem; if (strcasecmp(windowMenuItem->TruncatedLabel(), windowMenuItem->Label()) > 0) { // label is truncated, set tooltip SetToolTip(windowMenuItem->Label()); } else SetToolTip((const char*)NULL); break; } if (!dynamic_cast<TBarApp*>(be_app)->Settings()->hideLabels) { // item has a visible label, set tool tip if truncated fLastMousedOverItem = menuItem; if (strcasecmp(item->TruncatedLabel(), item->Label()) > 0) { // label is truncated, set tooltip SetToolTip(item->Label()); } else SetToolTip((const char*)NULL); break; } SetToolTip(item->Label()); // new item, set the tooltip to the item label fLastMousedOverItem = menuItem; // save the current menuitem for the next MouseMoved() call break; } } BMenuBar::MouseMoved(where, code, message); return; } if (buttons == 0) return; switch (code) { case B_ENTERED_VIEW: // fPreviousDragTargetItem should always be NULL here anyways. if (fPreviousDragTargetItem != NULL) _FinishedDrag(); fBarView->CacheDragData(message); fPreviousDragTargetItem = NULL; break; case B_OUTSIDE_VIEW: // NOTE: Should not be here, but for the sake of defensive // programming... fall-through case B_EXITED_VIEW: _FinishedDrag(); break; case B_INSIDE_VIEW: if (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 TTeamMenu::AttachedToWindow() { RemoveItems(0, CountItems(), true); // remove all items BMessenger self(this); BList teamList; TBarApp::Subscribe(self, &teamList); TBarView* barview = (dynamic_cast<TBarApp*>(be_app))->BarView(); bool dragging = barview && barview->Dragging(); int32 iconSize = static_cast<TBarApp*>(be_app)->IconSize(); desk_settings* settings = ((TBarApp*)be_app)->Settings(); float width = sMinimumWindowWidth - iconSize - 4; if (settings->sortRunningApps) teamList.SortItems(CompareByName); int32 count = teamList.CountItems(); for (int32 i = 0; i < count; i++) { // add items back BarTeamInfo* barInfo = (BarTeamInfo*)teamList.ItemAt(i); TTeamMenuItem* item = new TTeamMenuItem(barInfo->teams, barInfo->icon, barInfo->name, barInfo->sig, width, -1, !settings->hideLabels, true); if (settings->trackerAlwaysFirst && strcmp(barInfo->sig, kTrackerSignature) == 0) { AddItem(item, 0); } else AddItem(item); if (dragging && item != NULL) { bool canhandle = (dynamic_cast<TBarApp*>(be_app))->BarView()-> AppCanHandleTypes(item->Signature()); if (item->IsEnabled() != canhandle) item->SetEnabled(canhandle); BMenu* menu = item->Submenu(); if (menu) menu->SetTrackingHook(barview->MenuTrackingHook, barview->GetTrackingHookData()); } } if (CountItems() == 0) { BMenuItem* item = new BMenuItem("no application running", NULL); item->SetEnabled(false); AddItem(item); } if (dragging && barview->LockLooper()) { SetTrackingHook(barview->MenuTrackingHook, barview->GetTrackingHookData()); barview->DragStart(); barview->UnlockLooper(); } BMenu::AttachedToWindow(); }
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(); // Set all WindowMenuItems to require an update. TWindowMenuItem* item = NULL; for (int32 i = 0; i < totalItems; i++) { if (!teamMenu->SubmenuAt(i)) { item = static_cast<TWindowMenuItem*>(teamMenu->ItemAt(i)); item->SetRequireUpdate(true); } } // Perform SetTo() on all the items that still exist as well as add // new items. 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++) { // The following code is almost a copy/paste from // WindowMenu.cpp 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; if (TWindowMenu::WindowShouldBeListed(wInfo)) { // Check if we have a matching window item... item = teamItem->ExpandedWindowItem( wInfo->server_token); if (item != NULL) { item->SetTo(wInfo->name, wInfo->server_token, wInfo->is_mini, ((1 << current_workspace()) & wInfo->workspaces) != 0); if (strcasecmp(item->Label(), wInfo->name) > 0) item->SetLabel(wInfo->name); if (item->Modified()) itemModified = true; } else if (teamItem->IsExpanded()) { // Add the item item = new TWindowMenuItem(wInfo->name, 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); } } } // Remove any remaining items which require an update. 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 any of the WindowMenuItems changed state, we need to force a // repaint. if (itemModified || resize) { teamMenu->Invalidate(); if (resize) teamMenu->SizeWindow(1); } teamMenu->Window()->Unlock(); } sMonLocker.Unlock(); // sleep for a bit... snooze(150000); } return B_OK; }
void TExpandoMenuBar::MouseDown(BPoint where) { BMessage *message = Window()->CurrentMessage(); // check for three finger salute, a.k.a. Vulcan Death Grip if (message != NULL) { int32 modifiers = 0; message->FindInt32("modifiers", &modifiers); if ((modifiers & B_COMMAND_KEY) != 0 && (modifiers & B_OPTION_KEY) != 0 && (modifiers & B_SHIFT_KEY) != 0 && !fBarView->Dragging()) { TTeamMenuItem *item = ItemAtPoint(where); if (item) { const BList *teams = item->Teams(); int32 teamCount = teams->CountItems(); team_id teamID; for (int32 team = 0; team < teamCount; team++) { teamID = (team_id)teams->ItemAt(team); kill_team(teamID); // remove the team immediately // from display RemoveTeam(teamID, false); } return; } } } const int32 count = CountItems(); // This feature is broken because the menu bar never receives // the second click #ifdef DOUBLECLICKBRINGSTOFRONT // doubleclick on an item brings all to front for (int32 i = fFirstApp; i < count; i++) { TTeamMenuItem *item = (TTeamMenuItem *)ItemAt(i); if (item->Frame().Contains(where)) { bigtime_t clickSpeed = 0; get_click_speed(&clickSpeed); if ( (fLastClickItem == i) && (clickSpeed > (system_time() - fLastClickTime)) ) { // bring this team's window to the front BMessage showMessage(M_BRING_TEAM_TO_FRONT); showMessage.AddInt32("itemIndex", i); Window()->PostMessage(&showMessage, this); return; } fLastClickItem = i; fLastClickTime = system_time(); break; } } #endif // control click - show all/hide all shortcut if (message != NULL) { int32 modifiers = 0; message->FindInt32("modifiers", &modifiers); if ((modifiers & B_CONTROL_KEY) != 0 && ! fBarView->Dragging()) { int32 lastApp = -1; // find the clicked item for (int32 i = fFirstApp; i < count; i++) { const TTeamMenuItem *item = (TTeamMenuItem *)ItemAt(i); // check if this item is really a team item (what a cruel way...) // "lastApp" will always point to the last application in // the list - the other entries might be windows (due to the team expander) if (item->Submenu()) lastApp = i; if (item->Frame().Contains(where)) { // show/hide item's teams BMessage showMessage((modifiers & B_SHIFT_KEY) != 0 ? M_MINIMIZE_TEAM : M_BRING_TEAM_TO_FRONT); showMessage.AddInt32("itemIndex", lastApp); Window()->PostMessage(&showMessage, this); return; } } } } // Check the bounds of the expand Team icon if (fShowTeamExpander && fVertical && !fBarView->Dragging()) { TTeamMenuItem *item = ItemAtPoint(where); if (item->Submenu()){ BRect expanderRect = item->ExpanderBounds(); if (expanderRect.Contains(where)) { item->ToggleExpandState(true); item->Draw(); // Absorb the message. return; } } } BMenuBar::MouseDown(where); }
void TWindowMenu::AttachedToWindow() { SetFont(be_plain_font); RemoveItems(0, CountItems(), true); int32 miniCount = 0; bool dragging = false; TBarView* barview =(static_cast<TBarApp*>(be_app))->BarView(); if (barview && barview->LockLooper()) { // 'dragging' mode set in BarView::CacheDragData // invoke in MouseEnter in ExpandoMenuBar dragging = barview->Dragging(); if (dragging) { // We don't want to show the menu when dragging, but it's not // possible to remove a submenu once it exists, so we simply hide it // Don't call BMenu::Hide(), it causes the menu to pop up every now // and then. Window()->Hide(); // if in expando (horizontal or vertical) if (barview->Expando()) { SetTrackingHook(barview->MenuTrackingHook, barview->GetTrackingHookData()); } barview->DragStart(); } barview->UnlockLooper(); } int32 parentMenuItems = 0; int32 numTeams = fTeam->CountItems(); for (int32 i = 0; i < numTeams; i++) { team_id theTeam = (team_id)fTeam->ItemAt(i); int32 count = 0; int32* tokens = get_token_list(theTeam, &count); for (int32 j = 0; j < count; j++) { client_window_info* wInfo = get_window_info(tokens[j]); if (wInfo == NULL) continue; if (WindowShouldBeListed(wInfo->feel) && (wInfo->show_hide_level <= 0 || wInfo->is_mini)) { // Don't add new items if we're expanded. We've already done // this, they've just been moved. int32 numItems = CountItems(); int32 addIndex = 0; for (; addIndex < numItems; addIndex++) if (strcasecmp(ItemAt(addIndex)->Label(), wInfo->name) > 0) break; if (!fExpanded) { TWindowMenuItem* item = new TWindowMenuItem(wInfo->name, wInfo->server_token, wInfo->is_mini, ((1 << current_workspace()) & wInfo->workspaces) != 0, dragging); // disable app's window dropping for now if (dragging) item->SetEnabled(false); AddItem(item, TWindowMenuItem::InsertIndexFor(this, 0, item)); } else { TTeamMenuItem* parentItem = static_cast<TTeamMenuItem*>(Superitem()); if (parentItem->ExpandedWindowItem(wInfo->server_token)) { TWindowMenuItem* item = parentItem->ExpandedWindowItem( wInfo->server_token); if (item == NULL) continue; item->SetTo(wInfo->name, wInfo->server_token, wInfo->is_mini, ((1 << current_workspace()) & wInfo->workspaces) != 0, dragging); parentMenuItems++; } } if (wInfo->is_mini) miniCount++; } free(wInfo); } free(tokens); } int32 itemCount = CountItems() + parentMenuItems; if (itemCount < 1) { TWindowMenuItem* noWindowsItem = new TWindowMenuItem("No windows", -1, false, false); noWindowsItem->SetEnabled(false); AddItem(noWindowsItem); // if an application has no windows, this feature makes it easy to quit // it. (but we only add this option if the application is not Tracker.) if (fApplicationSignature.ICompare(kTrackerSignature) != 0) { AddSeparatorItem(); AddItem(new TShowHideMenuItem("Quit application", fTeam, B_QUIT_REQUESTED)); } } else { // if we are in drag mode, then don't add the window controls // to the menu if (!dragging) { TShowHideMenuItem* hide = new TShowHideMenuItem("Hide all", fTeam, B_MINIMIZE_WINDOW); TShowHideMenuItem* show = new TShowHideMenuItem("Show all", fTeam, B_BRING_TO_FRONT); TShowHideMenuItem* close = new TShowHideMenuItem("Close all", fTeam, B_QUIT_REQUESTED); if (miniCount == itemCount) hide->SetEnabled(false); else if (miniCount == 0) show->SetEnabled(false); if (!parentMenuItems) AddSeparatorItem(); AddItem(hide); AddItem(show); AddItem(close); } } BMenu::AttachedToWindow(); }
void TExpandoMenuBar::AddTeam(BList* team, BBitmap* icon, char* name, char* signature) { int32 iconSize = static_cast<TBarApp*>(be_app)->IconSize(); desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings(); float itemWidth = -1.0f; if (fVertical) itemWidth = fBarView->Bounds().Width(); else { itemWidth = iconSize; if (!settings->hideLabels) itemWidth += gMinimumWindowWidth - kMinimumIconSize; else itemWidth += kIconPadding * 2; } float itemHeight = -1.0f; TTeamMenuItem* item = new TTeamMenuItem(team, icon, name, signature, itemWidth, itemHeight); if (settings->trackerAlwaysFirst && strcasecmp(signature, kTrackerSignature) == 0) { AddItem(item, 0); } else if (settings->sortRunningApps) { TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(ItemAt(0)); int32 firstApp = 0; // if Tracker should always be the first item, we need to skip it // when sorting in the current item 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++; } // was the item added to the list yet? if (i == itemCount) AddItem(item); } else AddItem(item); if (fVertical && settings->superExpando && settings->expandNewTeams) item->ToggleExpandState(false); SizeWindow(1); Window()->UpdateIfNeeded(); }
void TExpandoMenuBar::BuildItems() { BMessenger self(this); TBarApp::Subscribe(self, &fTeamList); int32 iconSize = static_cast<TBarApp*>(be_app)->IconSize(); desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings(); float itemWidth = -1.0f; if (fVertical) itemWidth = Frame().Width(); else { itemWidth = iconSize; if (!settings->hideLabels) itemWidth += gMinimumWindowWidth - kMinimumIconSize; else itemWidth += kIconPadding * 2; } float itemHeight = -1.0f; 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()) { // new team TTeamMenuItem* item = new TTeamMenuItem(barInfo->teams, barInfo->icon, barInfo->name, barInfo->sig, itemWidth, itemHeight); if (settings->trackerAlwaysFirst && strcasecmp(barInfo->sig, kTrackerSignature) == 0) { AddItem(item, 0); } else AddItem(item); if (fFirstBuild && fVertical && settings->expandNewTeams) item->ToggleExpandState(true); } else { // existing team, update info and add it TTeamMenuItem* item = iter->second; item->SetIcon(barInfo->icon); item->SetOverrideWidth(itemWidth); item->SetOverrideHeight(itemHeight); if (settings->trackerAlwaysFirst && strcasecmp(barInfo->sig, kTrackerSignature) == 0) { AddItem(item, 0); } else AddItem(item); // add window items back 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 (fVertical) AddItem(windowItem); else { delete windowItem; hasWindowItems = submenu != NULL; } } // unexpand if turn off show team expander if (fVertical && !settings->superExpando && item->IsExpanded()) item->ToggleExpandState(false); if (hasWindowItems) { // add (new) window items in submenu submenu->SetExpanded(false, 0); submenu->AttachedToWindow(); } } } if (CountItems() == 0) { // If we're empty, BMenuBar::AttachedToWindow() resizes us to some // weird value - we just override it again ResizeTo(itemWidth, 0); } fFirstBuild = false; }
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 *sig; if (message->FindString("sig", &sig) == B_OK &&strcasecmp(sig, TASK_BAR_MIME_SIG) == 0) { delete teams; delete icon; break; } uint32 flags; if (message->FindInt32("flags", ((int32*) &flags)) == B_OK && (flags & B_BACKGROUND_APP) != 0) { delete teams; delete icon; break; } const char *name = NULL; message->FindString("name", &name); AddTeam(teams, icon, strdup(name), strdup(sig)); break; } case msg_AddTeam: AddTeam(message->FindInt32("team"), message->FindString("sig")); break; case msg_RemoveTeam: { 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 M_MINIMIZE_TEAM: { 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 M_BRING_TEAM_TO_FRONT: { 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::CheckItemSizes(int32 delta) { if (fBarView->Vertical()) return; bool drawLabels = !static_cast<TBarApp*>(be_app)->Settings()->hideLabels; float maxWidth = fBarView->DragRegion()->Frame().left - fDeskbarMenuWidth - kSepItemWidth; int32 iconSize = static_cast<TBarApp*>(be_app)->IconSize(); float iconOnlyWidth = kIconPadding + iconSize + kIconPadding; float minItemWidth = drawLabels ? iconOnlyWidth + kMinMenuItemWidth : iconOnlyWidth - kIconPadding; float maxItemWidth = drawLabels ? gMinimumWindowWidth + iconSize - kMinimumIconSize : iconOnlyWidth; float menuWidth = maxItemWidth * CountItems() + fDeskbarMenuWidth + kSepItemWidth; bool reset = false; float newWidth = -1.0f; if (delta >= 0 && menuWidth > maxWidth) { fOverflow = true; reset = true; newWidth = floorf(maxWidth / CountItems()); } else if (delta < 0 && fOverflow) { reset = true; if (menuWidth > maxWidth) newWidth = floorf(maxWidth / CountItems()); else newWidth = maxItemWidth; } if (reset) { if (newWidth > maxItemWidth) newWidth = maxItemWidth; else if (newWidth < minItemWidth) newWidth = minItemWidth; SetMaxContentWidth(newWidth); if (newWidth == maxItemWidth) fOverflow = false; InvalidateLayout(); for (int32 index = 0; ; index++) { TTeamMenuItem* item = (TTeamMenuItem*)ItemAt(index); if (item == NULL) break; item->SetOverrideWidth(newWidth); } Invalidate(); Window()->UpdateIfNeeded(); fBarView->CheckForScrolling(); } }
int32 TExpandoMenuBar::monitor_team_windows(void *arg) { TExpandoMenuBar *teamMenu = (TExpandoMenuBar *)arg; int32 totalItems = 0; bool itemModified = false; TWindowMenuItem *item = NULL; TTeamMenuItem *teamItem = NULL; int32 *tokens = NULL; while (teamMenu->sDoMonitor) { totalItems = teamMenu->CountItems(); // Set all WindowMenuItems to require an update. item = NULL; for (int32 i = 0; i < totalItems; i++) { if (!teamMenu->SubmenuAt(i)){ item = static_cast<TWindowMenuItem *>(teamMenu->ItemAt(i)); item->SetRequireUpdate(); } } // Perform SetTo() on all the items that still exist as well as add new items. itemModified = false; teamItem = NULL; for (int32 i = 0; i < totalItems; i++) { if (teamMenu->SubmenuAt(i)){ teamItem = static_cast<TTeamMenuItem *>(teamMenu->ItemAt(i)); if (teamItem->IsExpanded()) { int32 teamCount = teamItem->Teams()->CountItems(); for (int32 j = 0; j < teamCount; j++) { // The following code is almost a copy/paste from // WindowMenu.cpp team_id theTeam = (team_id)teamItem->Teams()->ItemAt(j); int32 count = 0; tokens = get_token_list(theTeam, &count); for (int32 k = 0; k < count; k++) { window_info *wInfo = get_window_info(tokens[k]); if (wInfo == NULL) continue; if (TWindowMenu::WindowShouldBeListed(wInfo->w_type) && (wInfo->show_hide_level <= 0 || wInfo->is_mini)) { // Check if we have a matching window item... item = teamItem->ExpandedWindowItem(wInfo->id); if (item) { // Lock the window, changing workspaces will fry this. item->SetTo(wInfo->name, wInfo->id, wInfo->is_mini, ((1 << current_workspace()) & wInfo->workspaces) != 0); if (strcmp(wInfo->name, item->Label()) != 0) item->SetLabel(wInfo->name); if (item->ChangedState()) itemModified = true; } else if (teamItem->IsExpanded()) { // Add the item item = new TWindowMenuItem(wInfo->name, wInfo->id, wInfo->is_mini, ((1 << current_workspace()) & wInfo->workspaces) != 0, false); item->ExpandedItem(true); teamMenu->AddItem(item, i + 1); itemModified = true; teamMenu->Window()->Lock(); teamMenu->SizeWindow(); teamMenu->Window()->Unlock(); } } free(wInfo); } free(tokens); } } } } // Remove any remaining items which require an update. 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--; teamMenu->Window()->Lock(); teamMenu->SizeWindow(); teamMenu->Window()->Unlock(); } } } // If any of the WindowMenuItems changed state, we need to force a repaint. if (itemModified) { teamMenu->Window()->Lock(); teamMenu->Invalidate(); teamMenu->Window()->Unlock(); } // sleep for a bit... snooze(150000); } return B_OK; }
void TBarView::ChangeState(int32 state, bool vertical, bool left, bool top) { bool vertSwap = (fVertical != vertical); bool leftSwap = (fLeft != left); fState = state; fVertical = vertical; fLeft = left; fTop = top; BRect screenFrame = (BScreen(Window())).Frame(); PlaceBeMenu(); if (fVertical){ #if SA_CLOCK PlaceClock(); // tray dependent on clock location #endif PlaceTray(vertSwap, leftSwap, screenFrame); } else { PlaceTray(vertSwap, leftSwap, screenFrame); #if SA_CLOCK PlaceClock(); // clock is dependent on tray location #endif } // We need to keep track of what apps are expanded. BList expandedItems; BString *signature = NULL; if (fVertical && Expando() && static_cast<TBarApp *>(be_app)->Settings()->superExpando) { // Get a list of the Signatures of expanded apps - Can't use team_id because // there can be more than one team per application if (fVertical && Expando() && vertical && fExpando) { for (int index = 0; index < fExpando->CountItems(); index++) { TTeamMenuItem *item = dynamic_cast<TTeamMenuItem *>(fExpando->ItemAt(index)); if (item != NULL && item->IsExpanded()) { signature = new BString(item->Signature()); expandedItems.AddItem((void *)signature); } } } } PlaceApplicationBar(screenFrame); SizeWindow(screenFrame); PositionWindow(screenFrame); Window()->UpdateIfNeeded(); // Re-expand those apps. if (expandedItems.CountItems() > 0) { for (int sigIndex = expandedItems.CountItems(); sigIndex-- > 0;) { signature = static_cast<BString *>(expandedItems.ItemAt(sigIndex)); if (signature == NULL) continue; // Start at the 'bottom' of the list working up. // Prevents being thrown off by expanding items. for (int teamIndex = fExpando->CountItems(); teamIndex-- > 0;) { TTeamMenuItem *item = dynamic_cast<TTeamMenuItem *>(fExpando->ItemAt(teamIndex)); if (item != NULL && !signature->Compare(item->Signature())) { item->ToggleExpandState(false); break; } } } // Clean up expanded signature list. while (!expandedItems.IsEmpty()) { delete static_cast<BString *>(expandedItems.RemoveItem((int32)0)); } fExpando->SizeWindow(); } Invalidate(); }