From 6130a64be563e543a40b4569a87e57e7998927e2 Mon Sep 17 00:00:00 2001 From: Sebastian Livoni <29739749+sebastianlivoni@users.noreply.github.com> Date: Sun, 2 Nov 2025 16:16:22 +0100 Subject: [PATCH] Add Window menu for macOS and specify Help menu to AppKit (#12357) * Add Window menu for macOS and specify Help menu to AppKit * Fix potential NSString dangling pointers of temporary QStrings --- share/translations/keepassxc_en.ts | 19 +++++++++++++++ src/gui/MainWindow.cpp | 4 ++++ src/gui/osutils/macutils/AppKit.h | 3 +++ src/gui/osutils/macutils/AppKitImpl.h | 1 + src/gui/osutils/macutils/AppKitImpl.mm | 32 ++++++++++++++++++++++++-- src/gui/osutils/macutils/MacUtils.cpp | 6 +++++ src/gui/osutils/macutils/MacUtils.h | 2 ++ 7 files changed, 65 insertions(+), 2 deletions(-) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index 8b3026950..caa33e301 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -157,6 +157,25 @@ + + AppKit + + Window + + + + Minimize + + + + Zoom + + + + Bring All to Front + + + ApplicationSettingsWidget diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index caaf4bc2c..2142dba4a 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -93,6 +93,10 @@ MainWindow::MainWindow() m_ui->setupUi(this); +#ifdef Q_OS_MACOS + macUtils()->configureWindowAndHelpMenus(this, m_ui->menuHelp); +#endif + #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) && !defined(QT_NO_DBUS) new MainWindowAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); diff --git a/src/gui/osutils/macutils/AppKit.h b/src/gui/osutils/macutils/AppKit.h index 260b6c208..1f8eec489 100644 --- a/src/gui/osutils/macutils/AppKit.h +++ b/src/gui/osutils/macutils/AppKit.h @@ -21,6 +21,8 @@ #include #include +#include +#include #include class QWindow; @@ -45,6 +47,7 @@ public: bool enableScreenRecording(); void toggleForegroundApp(bool foreground); void setWindowSecurity(QWindow* window, bool state); + void configureWindowAndHelpMenus(QMainWindow* mainWindow, QMenu* helpMenu); signals: void userSwitched(); diff --git a/src/gui/osutils/macutils/AppKitImpl.h b/src/gui/osutils/macutils/AppKitImpl.h index c03fc2948..4da637852 100644 --- a/src/gui/osutils/macutils/AppKitImpl.h +++ b/src/gui/osutils/macutils/AppKitImpl.h @@ -42,5 +42,6 @@ - (bool) enableScreenRecording; - (void) toggleForegroundApp:(bool) foreground; - (void) setWindowSecurity:(NSWindow*) window state:(bool) state; +- (void) configureWindowAndHelpMenus:(QMainWindow*) mainWindow helpMenu:(QMenu*) helpMenu; @end diff --git a/src/gui/osutils/macutils/AppKitImpl.mm b/src/gui/osutils/macutils/AppKitImpl.mm index a2b30e553..43b3f3723 100644 --- a/src/gui/osutils/macutils/AppKitImpl.mm +++ b/src/gui/osutils/macutils/AppKitImpl.mm @@ -18,6 +18,8 @@ #import "AppKitImpl.h" #import +#import +#import #import #if __clang_major__ >= 13 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_3 #import @@ -184,7 +186,7 @@ // // Check if screen recording is enabled, may show an popup asking for permissions // -- (bool) enableScreenRecording +- (bool) enableScreenRecording { #if __clang_major__ >= 13 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_3 if (@available(macOS 12.3, *)) { @@ -192,7 +194,7 @@ dispatch_semaphore_t sema = dispatch_semaphore_create(0); // Attempt to use SCShareableContent to check for screen recording permission - [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent * _Nullable content, + [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent * _Nullable content, NSError * _Nullable error) { Q_UNUSED(error); if (content) { @@ -231,8 +233,29 @@ [window setSharingType: state ? NSWindowSharingNone : NSWindowSharingReadOnly]; } +- (void) configureWindowAndHelpMenus:(QMainWindow*) mainWindow helpMenu:(QMenu*) helpMenu +{ + QMenu *qtWindowMenu = new QMenu(AppKit::tr("Window")); + NSMenu *nsWindowMenu = qtWindowMenu->toNSMenu(); + + QString minimizeStr = AppKit::tr("Minimize"); + [nsWindowMenu addItemWithTitle:minimizeStr.toNSString() action:@selector(performMiniaturize:) keyEquivalent:@""]; + QString zoomStr = AppKit::tr("Zoom"); + [nsWindowMenu addItemWithTitle:zoomStr.toNSString() action:@selector(performZoom:) keyEquivalent:@""]; + [nsWindowMenu addItem:[NSMenuItem separatorItem]]; + QString bringAllToFrontStr = AppKit::tr("Bring All to Front"); + [nsWindowMenu addItemWithTitle:bringAllToFrontStr.toNSString() action:@selector(arrangeInFront:) keyEquivalent:@""]; + + NSApp.windowsMenu = nsWindowMenu; + + mainWindow->menuBar()->insertMenu(helpMenu->menuAction(), qtWindowMenu); + + NSApp.helpMenu = helpMenu->toNSMenu(); +} + @end + // // ------------------------- C++ Trampolines ------------------------- // @@ -312,3 +335,8 @@ void AppKit::setWindowSecurity(QWindow* window, bool state) auto view = reinterpret_cast(window->winId()); [static_cast(self) setWindowSecurity:view.window state:state]; } + +void AppKit::configureWindowAndHelpMenus(QMainWindow* window, QMenu* helpMenu) +{ + [static_cast(self) configureWindowAndHelpMenus:window helpMenu:helpMenu]; +} diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp index b943561dc..7da2ad430 100644 --- a/src/gui/osutils/macutils/MacUtils.cpp +++ b/src/gui/osutils/macutils/MacUtils.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -202,6 +203,11 @@ void MacUtils::registerNativeEventFilter() ::InstallApplicationEventHandler(MacUtils::hotkeyHandler, 1, &eventSpec, this, nullptr); } +void MacUtils::configureWindowAndHelpMenus(QMainWindow* mainWindow, QMenu* helpMenu) +{ + return m_appkit->configureWindowAndHelpMenus(mainWindow, helpMenu); +} + bool MacUtils::registerGlobalShortcut(const QString& name, Qt::Key key, Qt::KeyboardModifiers modifiers, QString* error) { auto keycode = qtToNativeKeyCode(key); diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h index 5e0e121d5..403419301 100644 --- a/src/gui/osutils/macutils/MacUtils.h +++ b/src/gui/osutils/macutils/MacUtils.h @@ -54,6 +54,8 @@ public: void registerNativeEventFilter() override; + void configureWindowAndHelpMenus(QMainWindow* mainWindow, QMenu* helpMenu); + bool registerGlobalShortcut(const QString& name, Qt::Key key, Qt::KeyboardModifiers modifiers,