Audacity 3.2.0
WindowMenus.cpp
Go to the documentation of this file.
1
2
3#include "../commands/CommandManager.h"
4
5// This file collects a few things specific to Mac and requiring some
6// Objective-C++ . Avoid mixing languages elsewhere.
7
8// Only needed when using wxWidgets < 3.1.3
9#if defined(__WXMAC__) && !wxCHECK_VERSION(3,1,3)
10
11#include "../CommonCommandFlags.h"
12#include "../Menus.h"
13#include "../Project.h"
14#include "../commands/CommandContext.h"
15
16#include <wx/frame.h>
17#include <wx/menu.h>
18
19#undef USE_COCOA
20
21#ifdef USE_COCOA
22#include <AppKit/AppKit.h>
23#include <wx/osx/private.h>
24#endif
25
26#include <AppKit/NSApplication.h>
27
28#include <objc/objc.h>
29#include <CoreFoundation/CoreFoundation.h>
30
31// private helper classes and functions
32namespace {
33
35{
36 if (project) {
37 auto window = &GetProjectFrame( *project );
38#ifdef USE_COCOA
39 // Adapted from mbarman.mm in wxWidgets 3.0.2
40 auto peer = window->GetPeer();
41 peer->GetWXPeer();
42 auto widget = static_cast<wxWidgetCocoaImpl*>(peer)->GetWXWidget();
43 auto nsWindow = [widget window];
44 if (nsWindow) {
45 [nsWindow performMiniaturize:widget];
46 }
47#else
48 window->Iconize(true);
49#endif
50
51 // So that the Minimize menu command disables
52 MenuManager::Get(*project).UpdateMenus();
53 }
54}
55
56std::vector< wxWindowID > sReservedIds;
57std::vector< std::weak_ptr< AudacityProject > > sProjects;
58
59void RebuildMenu(wxCommandEvent &evt)
60{
61 // Let other listeners hear it too
62 evt.Skip();
63
64 // This is a big hammer.
65 // Really we just need to recreate just the Window menu.
66 // This causes the checkmark to be put in the right place for the
67 // currently active project
69}
70
71wxWindowID ReservedID(
72 size_t index, const std::shared_ptr< AudacityProject > &pProject )
73{
74 if ( sReservedIds.empty() ) {
75 // Do this once only per session, and don't worry about unbinding
76 wxTheApp->Bind( EVT_PROJECT_ACTIVATION, RebuildMenu );
77 wxTheApp->Bind( EVT_PROJECT_TITLE_CHANGE, RebuildMenu );
78 }
79
80 while ( sReservedIds.size() <= index )
81 sReservedIds.emplace_back( wxIdManager::ReserveId() );
82
83 if ( sProjects.size() < sReservedIds.size() )
84 sProjects.resize( sReservedIds.size() );
85 sProjects[ index ] = pProject;
86
87 return sReservedIds[ index ];
88}
89
90void OnWindow( wxCommandEvent &evt )
91{
92 const auto begin = sReservedIds.begin(), end = sReservedIds.end(),
93 iter = std::find( begin, end, evt.GetId() );
94 size_t index = iter - begin;
95 if ( index < sProjects.size() ) {
96 auto pProject = sProjects[ index ].lock();
97 if ( pProject ) {
98 // Make it the active project
99 SetActiveProject(pProject.get());
100
101 // And ensure it's visible
102 wxFrame *frame = pProject->GetFrame();
103 if (frame->IsIconized())
104 {
105 frame->Restore();
106 }
107 frame->Raise();
108 }
109 }
110}
111
112} // namespace
113
115namespace WindowActions {
116
117// exported helper functions
118// none
119
120// Menu handler functions
121
123
124void OnMacMinimize(const CommandContext &context)
125{
126 DoMacMinimize(&context.project);
127}
128
129void OnMacZoom(const CommandContext &context)
130{
131 auto window = &GetProjectFrame( context.project );
132 auto topWindow = static_cast<wxTopLevelWindow*>(window);
133 auto maximized = topWindow->IsMaximized();
134 if (window) {
135#ifdef USE_COCOA
136 // Adapted from mbarman.mm in wxWidgets 3.0.2
137 auto peer = window->GetPeer();
138 peer->GetWXPeer();
139 auto widget = static_cast<wxWidgetCocoaImpl*>(peer)->GetWXWidget();
140 auto nsWindow = [widget window];
141 if (nsWindow)
142 [nsWindow performZoom:widget];
143#else
144 topWindow->Maximize(!maximized);
145#endif
146 }
147}
148
150{
151 // Really this de-miniaturizes all, which is not exactly the standard
152 // behavior.
153 for (const auto project : AllProjects{})
154 GetProjectFrame( *project ).Raise();
155}
156
158{
159 for (const auto project : AllProjects{}) {
160 DoMacMinimize(project.get());
161 }
162}
163
164}; // struct Handler
165
166} // namespace
167
169 // Handler is not stateful. Doesn't need a factory registered with
170 // AudacityProject.
171 static WindowActions::Handler instance;
172 return instance;
173};
174
175// Menu definitions
176
177#define FN(X) (& WindowActions::Handler :: X)
178
179namespace {
180using namespace MenuTable;
182{
184 // poor imitation of the Mac Windows Menu
186 static BaseItemSharedPtr menu{
188 Menu( wxT("Window"), XXO("&Window"),
189 Section( "",
190 /* i18n-hint: Standard Macintosh Window menu item: Make (the current
191 * window) shrink to an icon on the dock */
192 Command( wxT("MacMinimize"), XXO("&Minimize"), FN(OnMacMinimize),
193 NotMinimizedFlag(), wxT("Ctrl+M") ),
194 /* i18n-hint: Standard Macintosh Window menu item: Make (the current
195 * window) full sized */
196 Command( wxT("MacZoom"), XXO("&Zoom"),
197 FN(OnMacZoom), NotMinimizedFlag() )
198 ),
199
200 Section( "",
201 /* i18n-hint: Standard Macintosh Window menu item: Make all project
202 * windows un-hidden */
203 Command( wxT("MacBringAllToFront"), XXO("&Bring All to Front"),
204 FN(OnMacBringAllToFront), AlwaysEnabledFlag )
205 ),
206
207 Section( "",
208 Special( wxT("PopulateWindowsStep"),
209 [](AudacityProject &, wxMenu &theMenu)
210 {
211 // Undo previous bindings
212 for ( auto id : sReservedIds )
213 wxTheApp->Unbind( wxEVT_MENU, OnWindow, id );
214
215 // Add all projects to this project's Window menu
216 size_t ii = 0;
217 for (auto project : AllProjects{})
218 {
219 int itemId = ReservedID( ii++, project );
220 wxString itemName = project->GetFrame()->GetTitle();
221 bool isActive = (GetActiveProject() == project.get());
222
223 // This should never really happen, but a menu item must have a name
224 if (itemName.empty())
225 {
226 itemName = _("<untitled>");
227 }
228
229 // Add it to the menu and check it if it's the active project
230 wxMenuItem *item = theMenu.Append(itemId, itemName);
231 item->SetCheckable(true);
232 item->Check(isActive);
233
234 // Bind the callback
235 wxTheApp->Bind( wxEVT_MENU, OnWindow, itemId );
236 }
237 } )
238 )
239 ) ) };
240 return menu;
241}
242
244 wxT(""),
245 Shared( WindowMenu() )
246};
247
249{
250 static BaseItemSharedPtr items{
252 Items( wxT("MacWindows"),
253 /* i18n-hint: Shrink all project windows to icons on the Macintosh
254 tooldock */
255 Command( wxT("MacMinimizeAll"), XXO("Minimize All Projects"),
256 FN(OnMacMinimizeAll),
257 AlwaysEnabledFlag, wxT("Ctrl+Alt+M") )
258 ) ) };
259 return items;
260}
261
263 Placement{ wxT("Optional/Extra/Part2/Misc"), OrderingHint::End },
265};
266
267}
268
269#undef FN
270
271#else
272
273// Not WXMAC.
274
275#endif
AUDACITY_DLL_API std::weak_ptr< AudacityProject > GetActiveProject()
void SetActiveProject(AudacityProject *project)
wxT("CloseDown"))
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
wxEvtHandler CommandHandlerObject
const ReservedCommandFlag & NotMinimizedFlag()
#define XXO(s)
Definition: Internat.h:44
#define _(s)
Definition: Internat.h:75
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
for(int ii=0, nn=names.size();ii< nn;++ii)
static CommandHandlerObject & findCommandHandler(AudacityProject &)
#define FN(X)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
static void RebuildAllMenuBars()
Definition: Menus.cpp:687
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:71
void UpdateMenus(bool checkActive=true)
Definition: Menus.cpp:643
std::unique_ptr< MenuItem > Menu(const Identifier &internalName, const TranslatableString &title, Args &&... args)
std::unique_ptr< MenuPart > Section(const Identifier &internalName, Args &&... args)
std::unique_ptr< MenuItems > Items(const Identifier &internalName, Args &&... args)
std::unique_ptr< CommandItem > Command(const CommandID &name, const TranslatableString &label_in, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, const CommandManager::Options &options={}, CommandHandlerFinder finder=FinderScope::DefaultFinder())
std::unique_ptr< SpecialItem > Special(const Identifier &name, const SpecialItem::Appender &fn)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
std::shared_ptr< BaseItem > BaseItemSharedPtr
Definition: Registry.h:72
Namespace for functions for window management (mac only?)
wxWindowID ReservedID(size_t index, const std::shared_ptr< AudacityProject > &pProject)
Definition: WindowMenus.cpp:71
std::vector< wxWindowID > sReservedIds
Definition: WindowMenus.cpp:56
std::vector< std::weak_ptr< AudacityProject > > sProjects
Definition: WindowMenus.cpp:57
void DoMacMinimize(AudacityProject *project)
Definition: WindowMenus.cpp:34
void OnWindow(wxCommandEvent &evt)
Definition: WindowMenus.cpp:90
void RebuildMenu(wxCommandEvent &evt)
Definition: WindowMenus.cpp:59
void OnMacZoom(const CommandContext &context)
void OnMacBringAllToFront(const CommandContext &)
void OnMacMinimize(const CommandContext &context)
void OnMacMinimizeAll(const CommandContext &)