From 18cbc2e574007a48ee0eb1bd384b3e0f012b0894 Mon Sep 17 00:00:00 2001 From: Leland Lucius Date: Sat, 18 Apr 2020 01:49:17 -0500 Subject: [PATCH] Bug 1119 - Mac: Window menu's list of open windows not available --- src/AudacityApp.cpp | 38 ++++++++++++++++++ src/AudacityApp.h | 4 ++ src/Project.cpp | 9 +++++ src/ProjectFileIO.cpp | 9 +++++ src/menus/WindowMenus.cpp | 82 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 138 insertions(+), 4 deletions(-) diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index 9a8457e7a..223f82dd8 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -109,6 +109,10 @@ It handles initialization and termination by subclassing wxApp. #include "tracks/ui/Scrubbing.h" #include "widgets/FileHistory.h" +#if defined(__WXMAC__) +#include "menus/WindowMenus.h" +#endif + #ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS #include "prefs/KeyConfigPrefs.h" #endif @@ -885,6 +889,11 @@ BEGIN_EVENT_TABLE(AudacityApp, wxApp) EVT_MENU_RANGE(FileHistory::ID_RECENT_FIRST, FileHistory::ID_RECENT_LAST, AudacityApp::OnMRUFile) +#if defined(__WXMAC__) + // Window menu event handlers. + EVT_MENU_RANGE(WindowActions::ID_BASE, WindowActions::ID_LAST, AudacityApp::OnWindow) +#endif + // Handle AppCommandEvents (usually from a script) EVT_APP_COMMAND(wxID_ANY, AudacityApp::OnReceiveCommand) @@ -978,6 +987,35 @@ void AudacityApp::OnMRUFile(wxCommandEvent& event) { history.RemoveFileFromHistory(n); } +#if defined(__WXMAC__) +// Handles switching projects when an item in the Window menu is selected +void AudacityApp::OnWindow(wxCommandEvent& event) +{ + // Get the project's number + int projectNumber = event.GetId() - WindowActions::ID_BASE; + + // Search for it + for (auto project : AllProjects{}) + { + if (project->GetProjectNumber() == projectNumber) + { + // Make it the active project + SetActiveProject(project.get()); + + // And ensure it's visible + wxFrame *frame = project->GetFrame(); + if (frame->IsIconized()) + { + frame->Restore(); + } + frame->Raise(); + + break; + } + } +} +#endif + void AudacityApp::OnTimer(wxTimerEvent& WXUNUSED(event)) { // Filenames are queued when Audacity receives a few of the diff --git a/src/AudacityApp.h b/src/AudacityApp.h index 6886d1d94..a75cf306a 100644 --- a/src/AudacityApp.h +++ b/src/AudacityApp.h @@ -69,6 +69,10 @@ class AudacityApp final : public wxApp { // A wrapper of the above that does not throw bool SafeMRUOpen(const wxString &fileName); +#if defined(__WXMAC__) + void OnWindow(wxCommandEvent &event); +#endif + void OnReceiveCommand(AppCommandEvent &event); void OnKeyDown(wxKeyEvent &event); diff --git a/src/Project.cpp b/src/Project.cpp index 98d507c18..fa4f4f2bd 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -15,6 +15,10 @@ #include "KeyboardCapture.h" #include "ondemand/ODTaskThread.h" +#if defined(__WXMAC__) +#include "menus/WindowMenus.h" +#endif + #include #include @@ -113,6 +117,11 @@ void SetActiveProject(AudacityProject * project) KeyboardCapture::Capture( nullptr ); } wxTheApp->SetTopWindow( FindProjectFrame( project ) ); + +#if defined(__WXMAC__) + // Refresh the Window menu + WindowActions::Refresh(); +#endif } AudacityProject::AudacityProject() diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index b5dd1a20c..adb7a3509 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -24,6 +24,10 @@ Paul Licameli split from AudacityProject.cpp #include "widgets/AudacityMessageBox.h" #include "widgets/NumericTextCtrl.h" +#if defined(__WXMAC__) +#include "menus/WindowMenus.h" +#endif + static void RefreshAllTitles(bool bShowProjectNumbers ) { for ( auto pProject : AllProjects{} ) { @@ -132,6 +136,11 @@ void ProjectFileIO::SetProjectTitle( int number) window.SetTitle( name ); window.SetName(name); // to make the nvda screen reader read the correct title + +#if defined(__WXMAC__) + // Refresh the Window menu + WindowActions::Refresh(); +#endif } // Most of this string was duplicated 3 places. Made the warning consistent in this global. diff --git a/src/menus/WindowMenus.cpp b/src/menus/WindowMenus.cpp index 38b3afe43..c576842a4 100644 --- a/src/menus/WindowMenus.cpp +++ b/src/menus/WindowMenus.cpp @@ -7,12 +7,16 @@ #ifdef __WXMAC__ +#include "WindowMenus.h" + #include "../CommonCommandFlags.h" #include "../Menus.h" #include "../Project.h" #include "../commands/CommandContext.h" #include +#include +#include #undef USE_COCOA @@ -57,7 +61,68 @@ void DoMacMinimize(AudacityProject *project) namespace WindowActions { // exported helper functions -// none + +// Refreshes the Window menu in all projects +void Refresh() +{ + // Must do it in all projects + for (auto thisProject : AllProjects{}) + { + // Need the projects frame, but this should always be successful + wxFrame *frame = thisProject->GetFrame(); + wxASSERT(frame != NULL); + if (!frame) + { + continue; + } + + // This can happen if we are called before the menubar is set in the frame + wxMenuBar *bar = frame->GetMenuBar(); + if (!bar) + { + continue; + } + + // Should always find the Window menu + int pos = bar->FindMenu(wxT("Window")); + wxASSERT(pos != wxNOT_FOUND); + if (pos == wxNOT_FOUND) + { + continue; + } + + // We can not get the menu proper + wxMenu *menu = bar->GetMenu(pos); + + // Remove all existing window items + for (auto item : menu->GetMenuItems()) + { + if (item->GetId() >= WindowActions::ID_BASE) + { + menu->Destroy(item); + } + } + + // Add all projects to this project's Window menu + for (auto project : AllProjects{}) + { + int itemId = WindowActions::ID_BASE + project->GetProjectNumber(); + wxString itemName = project->GetFrame()->GetTitle(); + bool isActive = (GetActiveProject() == project.get()); + + // This should never really happen, but a menu item must have a name + if (itemName.empty()) + { + itemName = _(""); + } + + // Add it to the menu and check it if it's the active project + wxMenuItem *item = menu->Append(itemId, itemName); + item->SetCheckable(true); + item->Check(isActive); + } + } +} // Menu handler functions @@ -122,9 +187,9 @@ namespace { using namespace MenuTable; BaseItemSharedPtr WindowMenu() { - ////////////////////////////////////////////////////////////////////////// - // poor imitation of the Mac Windows Menu - ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + // poor imitation of the Mac Windows Menu + ////////////////////////////////////////////////////////////////////////// static BaseItemSharedPtr menu{ ( FinderScope{ findCommandHandler }, Menu( wxT("Window"), XO("&Window"), @@ -144,7 +209,16 @@ BaseItemSharedPtr WindowMenu() * windows un-hidden */ Command( wxT("MacBringAllToFront"), XXO("&Bring All to Front"), FN(OnMacBringAllToFront), AlwaysEnabledFlag ) + ), + + Section( "", + Special( wxT("PopulateWindowsStep"), + [](AudacityProject &, wxMenu &theMenu) + { + // Should something be done here??? + } ) ) + ) ) }; return menu; }