Add menu option to allow screenshots

* Fix #7580
* Also refactor the code to move everything into MainWindow
This commit is contained in:
Jonathan White 2022-11-24 21:09:01 -05:00
parent f9f82e9705
commit 0a2e716525
8 changed files with 48 additions and 28 deletions

View File

@ -5420,6 +5420,10 @@ We recommend you use the AppImage available on our downloads page.</source>
<source>You must restart the application to apply this setting. Would you like to restart now?</source> <source>You must restart the application to apply this setting. Would you like to restart now?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Allow Screen Capture</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ManageDatabase</name> <name>ManageDatabase</name>
@ -7887,10 +7891,6 @@ Kernel: %3 %4</source>
<source>KeePassXC - Error</source> <source>KeePassXC - Error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Warning: Failed to prevent screenshots on a top level window!</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Database password: </source> <source>Database password: </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -7913,6 +7913,10 @@ Kernel: %3 %4</source>
<source>Failed to sign challenge using Windows Hello.</source> <source>Failed to sign challenge using Windows Hello.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Warning: Failed to block screenshot capture on a top-level window.</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Invalid Cipher</source> <source>Invalid Cipher</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View File

@ -259,6 +259,7 @@ MainWindow::MainWindow()
m_showToolbarSeparator = config()->get(Config::GUI_ApplicationTheme).toString() != "classic"; m_showToolbarSeparator = config()->get(Config::GUI_ApplicationTheme).toString() != "classic";
m_ui->actionEntryAutoType->setVisible(autoType()->isAvailable()); m_ui->actionEntryAutoType->setVisible(autoType()->isAvailable());
m_ui->actionAllowScreenCapture->setVisible(osUtils->canPreventScreenCapture());
m_inactivityTimer = new InactivityTimer(this); m_inactivityTimer = new InactivityTimer(this);
connect(m_inactivityTimer, SIGNAL(inactivityDetected()), this, SLOT(lockDatabasesAfterInactivity())); 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->actionUserGuide, SIGNAL(triggered()), SLOT(openUserGuide()));
connect(m_ui->actionOnlineHelp, SIGNAL(triggered()), SLOT(openOnlineHelp())); connect(m_ui->actionOnlineHelp, SIGNAL(triggered()), SLOT(openOnlineHelp()));
connect(m_ui->actionKeyboardShortcuts, SIGNAL(triggered()), SLOT(openKeyboardShortcuts())); connect(m_ui->actionKeyboardShortcuts, SIGNAL(triggered()), SLOT(openKeyboardShortcuts()));
connect(m_ui->actionAllowScreenCapture, &QAction::toggled, this, &MainWindow::setAllowScreenCapture);
connect(osUtils, &OSUtilsBase::statusbarThemeChanged, this, &MainWindow::updateTrayIcon); connect(osUtils, &OSUtilsBase::statusbarThemeChanged, this, &MainWindow::updateTrayIcon);
@ -1658,11 +1660,27 @@ void MainWindow::applySettingsChanges()
updateTrayIcon(); 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(); 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) void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason)

View File

@ -52,6 +52,7 @@ public:
QList<DatabaseWidget*> getOpenDatabases(); QList<DatabaseWidget*> getOpenDatabases();
void restoreConfigState(); void restoreConfigState();
void setAllowScreenCapture(bool state);
enum StackedWidgetIndex enum StackedWidgetIndex
{ {
@ -192,6 +193,7 @@ private:
bool m_restartRequested = false; bool m_restartRequested = false;
bool m_contextMenuFocusLock = false; bool m_contextMenuFocusLock = false;
bool m_showToolbarSeparator = false; bool m_showToolbarSeparator = false;
bool m_allowScreenCapture = false;
qint64 m_lastFocusOutTime = 0; qint64 m_lastFocusOutTime = 0;
qint64 m_lastShowTime = 0; qint64 m_lastShowTime = 0;
QTimer m_updateCheckTimer; QTimer m_updateCheckTimer;

View File

@ -385,6 +385,7 @@
<addaction name="menuTheme"/> <addaction name="menuTheme"/>
<addaction name="actionCompactMode"/> <addaction name="actionCompactMode"/>
<addaction name="actionAlwaysOnTop"/> <addaction name="actionAlwaysOnTop"/>
<addaction name="actionAllowScreenCapture"/>
<addaction name="actionShowPreviewPanel"/> <addaction name="actionShowPreviewPanel"/>
<addaction name="actionShowToolbar"/> <addaction name="actionShowToolbar"/>
<addaction name="actionHideUsernames"/> <addaction name="actionHideUsernames"/>
@ -1113,6 +1114,14 @@
<string>XML File…</string> <string>XML File…</string>
</property> </property>
</action> </action>
<action name="actionAllowScreenCapture">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Allow Screen Capture</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -27,5 +27,5 @@ OSUtilsBase::~OSUtilsBase() = default;
bool OSUtilsBase::setPreventScreenCapture(QWindow*, bool) const bool OSUtilsBase::setPreventScreenCapture(QWindow*, bool) const
{ {
// Do nothing by default // Do nothing by default
return false; return true;
} }

View File

@ -166,11 +166,9 @@ bool MacUtils::canPreventScreenCapture() const
bool MacUtils::setPreventScreenCapture(QWindow* window, bool prevent) const bool MacUtils::setPreventScreenCapture(QWindow* window, bool prevent) const
{ {
if (!window) { if (window) {
return false; m_appkit->setWindowSecurity(window, prevent);
} }
m_appkit->setWindowSecurity(window, prevent);
return true; return true;
} }

View File

@ -58,11 +58,12 @@ bool WinUtils::canPreventScreenCapture() const
bool WinUtils::setPreventScreenCapture(QWindow* window, bool prevent) const bool WinUtils::setPreventScreenCapture(QWindow* window, bool prevent) const
{ {
bool ret = true;
if (window) { if (window) {
HWND handle = reinterpret_cast<HWND>(window->winId()); HWND handle = reinterpret_cast<HWND>(window->winId());
return SetWindowDisplayAffinity(handle, prevent ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE); ret = SetWindowDisplayAffinity(handle, prevent ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE);
} }
return false; return ret;
} }
/** /**

View File

@ -183,21 +183,9 @@ int main(int argc, char** argv)
MainWindow mainWindow; MainWindow mainWindow;
#ifndef QT_DEBUG // Disable screen capture if not explicitly allowed
// Disable screen capture if capable and not explicitly allowed // This ensures any top-level windows (Main Window, Modal Dialogs, etc.) are excluded from screenshots
if (osUtils->canPreventScreenCapture() && !parser.isSet(allowScreenCaptureOption)) { mainWindow.setAllowScreenCapture(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
const bool pwstdin = parser.isSet(pwstdinOption); const bool pwstdin = parser.isSet(pwstdinOption);
if (!fileNames.isEmpty() && pwstdin) { if (!fileNames.isEmpty() && pwstdin) {