From 0a2e7165250552fd0c5116dceb2d47edc39be3b7 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Thu, 24 Nov 2022 21:09:01 -0500 Subject: [PATCH] Add menu option to allow screenshots * Fix #7580 * Also refactor the code to move everything into MainWindow --- share/translations/keepassxc_en.ts | 12 ++++++++---- src/gui/MainWindow.cpp | 22 ++++++++++++++++++++-- src/gui/MainWindow.h | 2 ++ src/gui/MainWindow.ui | 9 +++++++++ src/gui/osutils/OSUtilsBase.cpp | 2 +- src/gui/osutils/macutils/MacUtils.cpp | 6 ++---- src/gui/osutils/winutils/WinUtils.cpp | 5 +++-- src/main.cpp | 18 +++--------------- 8 files changed, 48 insertions(+), 28 deletions(-) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index af7b9de6f..c86e69d48 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -5420,6 +5420,10 @@ We recommend you use the AppImage available on our downloads page. You must restart the application to apply this setting. Would you like to restart now? + + Allow Screen Capture + + ManageDatabase @@ -7887,10 +7891,6 @@ Kernel: %3 %4 KeePassXC - Error - - Warning: Failed to prevent screenshots on a top level window! - - Database password: @@ -7913,6 +7913,10 @@ Kernel: %3 %4 Failed to sign challenge using Windows Hello. + + Warning: Failed to block screenshot capture on a top-level window. + + Invalid Cipher diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index f7e29df44..3acfcb4a8 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -259,6 +259,7 @@ MainWindow::MainWindow() m_showToolbarSeparator = config()->get(Config::GUI_ApplicationTheme).toString() != "classic"; m_ui->actionEntryAutoType->setVisible(autoType()->isAvailable()); + m_ui->actionAllowScreenCapture->setVisible(osUtils->canPreventScreenCapture()); m_inactivityTimer = new InactivityTimer(this); connect(m_inactivityTimer, SIGNAL(inactivityDetected()), this, SLOT(lockDatabasesAfterInactivity())); @@ -563,6 +564,7 @@ MainWindow::MainWindow() connect(m_ui->actionUserGuide, SIGNAL(triggered()), SLOT(openUserGuide())); connect(m_ui->actionOnlineHelp, SIGNAL(triggered()), SLOT(openOnlineHelp())); connect(m_ui->actionKeyboardShortcuts, SIGNAL(triggered()), SLOT(openKeyboardShortcuts())); + connect(m_ui->actionAllowScreenCapture, &QAction::toggled, this, &MainWindow::setAllowScreenCapture); connect(osUtils, &OSUtilsBase::statusbarThemeChanged, this, &MainWindow::updateTrayIcon); @@ -1658,11 +1660,27 @@ void MainWindow::applySettingsChanges() updateTrayIcon(); } -void MainWindow::focusWindowChanged(QWindow* focusWindow) +void MainWindow::setAllowScreenCapture(bool state) { - if (focusWindow != windowHandle()) { + m_allowScreenCapture = state; + for (auto window : qApp->allWindows()) { + osUtils->setPreventScreenCapture(window, !m_allowScreenCapture); + } + m_ui->actionAllowScreenCapture->blockSignals(true); + m_ui->actionAllowScreenCapture->setChecked(m_allowScreenCapture); + m_ui->actionAllowScreenCapture->blockSignals(false); +} + +void MainWindow::focusWindowChanged(QWindow* window) +{ + if (window != windowHandle()) { m_lastFocusOutTime = Clock::currentMilliSecondsSinceEpoch(); } + + if (!osUtils->setPreventScreenCapture(window, !m_allowScreenCapture) && !m_allowScreenCapture) { + displayGlobalMessage(QObject::tr("Warning: Failed to block screenshot capture on a top-level window."), + MessageWidget::Error); + } } void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index ed9c506a3..8436bf4ec 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -52,6 +52,7 @@ public: QList getOpenDatabases(); void restoreConfigState(); + void setAllowScreenCapture(bool state); enum StackedWidgetIndex { @@ -192,6 +193,7 @@ private: bool m_restartRequested = false; bool m_contextMenuFocusLock = false; bool m_showToolbarSeparator = false; + bool m_allowScreenCapture = false; qint64 m_lastFocusOutTime = 0; qint64 m_lastShowTime = 0; QTimer m_updateCheckTimer; diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index bbc06c180..cbaea45a3 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -385,6 +385,7 @@ + @@ -1113,6 +1114,14 @@ XML Fileā€¦ + + + true + + + Allow Screen Capture + + diff --git a/src/gui/osutils/OSUtilsBase.cpp b/src/gui/osutils/OSUtilsBase.cpp index d0d83f8f5..8a95b7f55 100644 --- a/src/gui/osutils/OSUtilsBase.cpp +++ b/src/gui/osutils/OSUtilsBase.cpp @@ -27,5 +27,5 @@ OSUtilsBase::~OSUtilsBase() = default; bool OSUtilsBase::setPreventScreenCapture(QWindow*, bool) const { // Do nothing by default - return false; + return true; } diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp index bc4503a8a..0f2cc6161 100644 --- a/src/gui/osutils/macutils/MacUtils.cpp +++ b/src/gui/osutils/macutils/MacUtils.cpp @@ -166,11 +166,9 @@ bool MacUtils::canPreventScreenCapture() const bool MacUtils::setPreventScreenCapture(QWindow* window, bool prevent) const { - if (!window) { - return false; + if (window) { + m_appkit->setWindowSecurity(window, prevent); } - - m_appkit->setWindowSecurity(window, prevent); return true; } diff --git a/src/gui/osutils/winutils/WinUtils.cpp b/src/gui/osutils/winutils/WinUtils.cpp index b2dd9b967..188b91348 100644 --- a/src/gui/osutils/winutils/WinUtils.cpp +++ b/src/gui/osutils/winutils/WinUtils.cpp @@ -58,11 +58,12 @@ bool WinUtils::canPreventScreenCapture() const bool WinUtils::setPreventScreenCapture(QWindow* window, bool prevent) const { + bool ret = true; if (window) { HWND handle = reinterpret_cast(window->winId()); - return SetWindowDisplayAffinity(handle, prevent ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE); + ret = SetWindowDisplayAffinity(handle, prevent ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE); } - return false; + return ret; } /** diff --git a/src/main.cpp b/src/main.cpp index f426a76e9..3797e8998 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -183,21 +183,9 @@ int main(int argc, char** argv) MainWindow mainWindow; -#ifndef QT_DEBUG - // Disable screen capture if capable and not explicitly allowed - if (osUtils->canPreventScreenCapture() && !parser.isSet(allowScreenCaptureOption)) { - // This ensures any top-level windows (Main Window, Modal Dialogs, etc.) are excluded from screenshots - QObject::connect(&app, &QGuiApplication::focusWindowChanged, &mainWindow, [&](QWindow* window) { - if (window) { - if (!osUtils->setPreventScreenCapture(window, true)) { - mainWindow.displayGlobalMessage( - QObject::tr("Warning: Failed to prevent screenshots on a top level window!"), - MessageWidget::Error); - } - } - }); - } -#endif + // Disable screen capture if not explicitly allowed + // This ensures any top-level windows (Main Window, Modal Dialogs, etc.) are excluded from screenshots + mainWindow.setAllowScreenCapture(parser.isSet(allowScreenCaptureOption)); const bool pwstdin = parser.isSet(pwstdinOption); if (!fileNames.isEmpty() && pwstdin) {