From c2f185df4770fd040d2b92776cb78325c264f9ba Mon Sep 17 00:00:00 2001 From: divyansharma001 Date: Sun, 1 Mar 2026 10:14:44 +0530 Subject: [PATCH 1/2] 202_106: fix Cmd+V paste not working in macOS save file dialog Temporarily disable QAction shortcuts while a native file dialog is open on macOS, then restore them after the dialog closes. This prevents menu bar NSMenuItem key equivalents from intercepting Cmd+V/C/X/A before the dialog's text field can handle them. Fixes: https://github.com/XmacsLabs/mogan/issues/2894 --- devel/202_106.md | 29 ++++++++++++++++++++++++++++ src/Plugins/Qt/qt_chooser_widget.cpp | 27 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 devel/202_106.md diff --git a/devel/202_106.md b/devel/202_106.md new file mode 100644 index 0000000000..c5ed3c6595 --- /dev/null +++ b/devel/202_106.md @@ -0,0 +1,29 @@ +# [202_106] Cmd+V paste not working in macOS save file dialog + +### How to test +1. Open Mogan on macOS +2. Copy some text to the clipboard +3. Open **Save As** dialog (File → Save as) +4. In the filename text field, press **Cmd+V** to paste +5. Verify the clipboard text is pasted into the filename field +6. Also verify **Cmd+C**, **Cmd+X**, **Cmd+A** work in the dialog +7. After closing the dialog, verify editor shortcuts still work normally + +## 2026/03/01 +### What +Temporarily disable QAction keyboard shortcuts while a native file dialog is open on macOS, then restore them after the dialog closes. + +### Why +On macOS, QAction shortcuts registered in the menu bar are converted to NSMenuItem key equivalents. When a native file dialog (NSSavePanel/NSOpenPanel) is shown via `QFileDialog::exec()`, pressing Cmd+V triggers the QAction for "Paste" in Mogan's menu bar instead of the standard Cocoa `paste:` action in the dialog's text field. This prevents users from pasting filenames in the Save As dialog. + +The `ShortcutOverride` mechanism in `QTMWidget::event()` does not help here because the QTMWidget does not have focus while a modal dialog is open. + +Fixes: https://github.com/XmacsLabs/mogan/issues/2894 + +### How +In `qt_chooser_widget_rep::perform_dialog()` in `src/Plugins/Qt/qt_chooser_widget.cpp`: + +- Before `dialog->exec()`: on macOS (`Q_OS_MACOS`), iterate all `QAction`s in the active window, save their shortcuts, then clear them via `action->setShortcut(QKeySequence())` +- After `dialog->exec()` returns: restore all saved shortcuts + +This removes the NSMenuItem key equivalents while the dialog is open, allowing the native dialog to process standard editing shortcuts (Cmd+V/C/X/A) through the Cocoa responder chain. diff --git a/src/Plugins/Qt/qt_chooser_widget.cpp b/src/Plugins/Qt/qt_chooser_widget.cpp index 86b48e9276..977803cc87 100644 --- a/src/Plugins/Qt/qt_chooser_widget.cpp +++ b/src/Plugins/Qt/qt_chooser_widget.cpp @@ -24,9 +24,11 @@ #include "mupdf_picture.hpp" #endif +#include #include #include #include +#include #include #include @@ -344,6 +346,24 @@ qt_chooser_widget_rep::perform_dialog () { r.moveCenter (pos); dialog->setGeometry (r); +#ifdef Q_OS_MACOS + // On macOS, QAction shortcuts registered in the menu bar become NSMenuItem + // key equivalents. When a native file dialog is open, these key equivalents + // intercept standard editing shortcuts (Cmd+V, Cmd+C, Cmd+X, Cmd+A) before + // the dialog's text field can handle them. Temporarily clearing all QAction + // shortcuts allows the native dialog to process these keys normally. + QList> savedShortcuts; + QWidget* mainWin= QApplication::activeWindow (); + if (mainWin) { + for (QAction* action : mainWin->findChildren ()) { + if (!action->shortcut ().isEmpty ()) { + savedShortcuts.append (qMakePair (action, action->shortcut ())); + action->setShortcut (QKeySequence ()); + } + } + } +#endif + QStringList fileNames; file= "#f"; if (dialog->exec ()) { @@ -429,6 +449,13 @@ qt_chooser_widget_rep::perform_dialog () { delete dialog; +#ifdef Q_OS_MACOS + // Restore menu shortcuts after the native dialog is closed + for (const auto& pair : savedShortcuts) { + pair.first->setShortcut (pair.second); + } +#endif + cmd (); if (!is_nil (quit)) quit (); } From c3741a83990d0e25f57c6ff85587a4559d85c2ec Mon Sep 17 00:00:00 2001 From: divyansharma001 Date: Mon, 16 Mar 2026 01:05:25 +0530 Subject: [PATCH 2/2] Fix Cmd+V paste functionality in macOS file dialog by temporarily removing native menu --- devel/202_106.md | 16 ++++++++++++--- src/Plugins/MacOS/mac_utilities.h | 3 +++ src/Plugins/MacOS/mac_utilities.mm | 17 ++++++++++++++++ src/Plugins/Qt/qt_chooser_widget.cpp | 29 ++++++++++------------------ 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/devel/202_106.md b/devel/202_106.md index c5ed3c6595..e9bb687461 100644 --- a/devel/202_106.md +++ b/devel/202_106.md @@ -3,12 +3,24 @@ ### How to test 1. Open Mogan on macOS 2. Copy some text to the clipboard -3. Open **Save As** dialog (File → Save as) +3. Open **Save As** dialog (File -> Save as) 4. In the filename text field, press **Cmd+V** to paste 5. Verify the clipboard text is pasted into the filename field 6. Also verify **Cmd+C**, **Cmd+X**, **Cmd+A** work in the dialog 7. After closing the dialog, verify editor shortcuts still work normally +## 2026/03/16 +### What +Temporarily remove the native macOS menu bar while a native file dialog is open, then restore it after the dialog closes. + +### Why +The previous approach (clearing QAction shortcuts via `setShortcut(QKeySequence())`) did not work because Qt converts QAction shortcuts to NSMenuItem key equivalents in the native Cocoa menu bar, and clearing the Qt-side shortcuts does not remove the already-cached NSMenuItem key equivalents. + +### How +Added `mac_save_and_clear_menu()` and `mac_restore_menu()` in `mac_utilities.mm` that use `[NSApp setMainMenu:nil]` to temporarily remove the entire native menu before `dialog->exec()`, then restore it after. This removes all NSMenuItem key equivalents from the Cocoa responder chain, allowing the native file dialog to process Cmd+V/C/X/A normally. + +Fixes: https://github.com/XmacsLabs/mogan/issues/2894 + ## 2026/03/01 ### What Temporarily disable QAction keyboard shortcuts while a native file dialog is open on macOS, then restore them after the dialog closes. @@ -18,8 +30,6 @@ On macOS, QAction shortcuts registered in the menu bar are converted to NSMenuIt The `ShortcutOverride` mechanism in `QTMWidget::event()` does not help here because the QTMWidget does not have focus while a modal dialog is open. -Fixes: https://github.com/XmacsLabs/mogan/issues/2894 - ### How In `qt_chooser_widget_rep::perform_dialog()` in `src/Plugins/Qt/qt_chooser_widget.cpp`: diff --git a/src/Plugins/MacOS/mac_utilities.h b/src/Plugins/MacOS/mac_utilities.h index 538327c264..a3e5f0a65f 100644 --- a/src/Plugins/MacOS/mac_utilities.h +++ b/src/Plugins/MacOS/mac_utilities.h @@ -25,4 +25,7 @@ void mac_fix_yosemite_bug(); void mac_begin_server (); void mac_end_server (); +void mac_save_and_clear_menu (); +void mac_restore_menu (); + #endif // MAC_UTILITIES_H diff --git a/src/Plugins/MacOS/mac_utilities.mm b/src/Plugins/MacOS/mac_utilities.mm index 5ede9a254b..68b89a23ce 100644 --- a/src/Plugins/MacOS/mac_utilities.mm +++ b/src/Plugins/MacOS/mac_utilities.mm @@ -504,6 +504,23 @@ unless we remove the duplicates and most plugins fail to start (since they are } +static NSMenu* savedMainMenu= nil; + +void +mac_save_and_clear_menu () { + savedMainMenu= [[NSApp mainMenu] retain]; + [NSApp setMainMenu:nil]; +} + +void +mac_restore_menu () { + if (savedMainMenu) { + [NSApp setMainMenu:savedMainMenu]; + [savedMainMenu release]; + savedMainMenu= nil; + } +} + static id background_activity= nil; void diff --git a/src/Plugins/Qt/qt_chooser_widget.cpp b/src/Plugins/Qt/qt_chooser_widget.cpp index 977803cc87..fd36c370f0 100644 --- a/src/Plugins/Qt/qt_chooser_widget.cpp +++ b/src/Plugins/Qt/qt_chooser_widget.cpp @@ -28,10 +28,13 @@ #include #include #include -#include #include #include +#ifdef OS_MACOS +#include "MacOS/mac_utilities.h" +#endif + #include using moebius::data::scm_quote; @@ -346,22 +349,13 @@ qt_chooser_widget_rep::perform_dialog () { r.moveCenter (pos); dialog->setGeometry (r); -#ifdef Q_OS_MACOS +#ifdef OS_MACOS // On macOS, QAction shortcuts registered in the menu bar become NSMenuItem // key equivalents. When a native file dialog is open, these key equivalents // intercept standard editing shortcuts (Cmd+V, Cmd+C, Cmd+X, Cmd+A) before - // the dialog's text field can handle them. Temporarily clearing all QAction - // shortcuts allows the native dialog to process these keys normally. - QList> savedShortcuts; - QWidget* mainWin= QApplication::activeWindow (); - if (mainWin) { - for (QAction* action : mainWin->findChildren ()) { - if (!action->shortcut ().isEmpty ()) { - savedShortcuts.append (qMakePair (action, action->shortcut ())); - action->setShortcut (QKeySequence ()); - } - } - } + // the dialog's text field can handle them. Temporarily removing the native + // menu allows the dialog to process these keys normally. + mac_save_and_clear_menu (); #endif QStringList fileNames; @@ -449,11 +443,8 @@ qt_chooser_widget_rep::perform_dialog () { delete dialog; -#ifdef Q_OS_MACOS - // Restore menu shortcuts after the native dialog is closed - for (const auto& pair : savedShortcuts) { - pair.first->setShortcut (pair.second); - } +#ifdef OS_MACOS + mac_restore_menu (); #endif cmd ();