diff --git a/src/core/Clock.cpp b/src/core/Clock.cpp index be9e91dcf..5704d4bff 100644 --- a/src/core/Clock.cpp +++ b/src/core/Clock.cpp @@ -34,6 +34,11 @@ uint Clock::currentSecondsSinceEpoch() return instance().currentDateTimeImpl().toTime_t(); } +qint64 Clock::currentMilliSecondsSinceEpoch() +{ + return instance().currentDateTimeImpl().toMSecsSinceEpoch(); +} + QDateTime Clock::serialized(const QDateTime& dateTime) { auto time = dateTime.time(); diff --git a/src/core/Clock.h b/src/core/Clock.h index 8f81b0961..4d1ee2537 100644 --- a/src/core/Clock.h +++ b/src/core/Clock.h @@ -28,6 +28,7 @@ public: static QDateTime currentDateTime(); static uint currentSecondsSinceEpoch(); + static qint64 currentMilliSecondsSinceEpoch(); static QDateTime serialized(const QDateTime& dateTime); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 3d6598fb2..0eb713dad 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -49,6 +49,7 @@ #include "gui/EntryPreviewWidget.h" #include "gui/FileDialog.h" #include "gui/KeePass1OpenWidget.h" +#include "gui/MainWindow.h" #include "gui/MessageBox.h" #include "gui/OpVaultOpenWidget.h" #include "gui/TotpDialog.h" @@ -677,7 +678,7 @@ void DatabaseWidget::setClipboardTextAndMinimize(const QString& text) clipboard()->setText(text); if (config()->get("HideWindowOnCopy").toBool()) { if (config()->get("MinimizeOnCopy").toBool()) { - window()->showMinimized(); + getMainWindow()->minimizeOrHide(); } else if (config()->get("DropToBackgroundOnCopy").toBool()) { window()->lower(); } @@ -782,7 +783,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry) QProcess::startDetached(cmdString.mid(6)); if (config()->get("MinimizeOnOpenUrl").toBool()) { - window()->showMinimized(); + getMainWindow()->minimizeOrHide(); } } } else { @@ -791,7 +792,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry) QDesktopServices::openUrl(url); if (config()->get("MinimizeOnOpenUrl").toBool()) { - window()->showMinimized(); + getMainWindow()->minimizeOrHide(); } } } @@ -972,7 +973,7 @@ void DatabaseWidget::loadDatabase(bool accepted) m_saveAttempts = 0; emit databaseUnlocked(); if (config()->get("MinimizeAfterUnlock").toBool()) { - window()->showMinimized(); + getMainWindow()->minimizeOrHide(); } } else { if (m_databaseOpenWidget->database()) { diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index b225165a6..620a509bc 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -294,7 +294,7 @@ MainWindow::MainWindow() connect(m_ui->menuGroups, SIGNAL(aboutToHide()), SLOT(releaseContextFocusLock())); // Control window state - new QShortcut(Qt::CTRL + Qt::Key_M, this, SLOT(showMinimized())); + new QShortcut(Qt::CTRL + Qt::Key_M, this, SLOT(minimizeOrHide())); new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_M, this, SLOT(hideWindow())); // Control database tabs new QShortcut(Qt::CTRL + Qt::Key_Tab, this, SLOT(selectNextDatabaseTab())); @@ -1072,7 +1072,7 @@ void MainWindow::changeEvent(QEvent* event) if (isTrayIconEnabled() && m_trayIcon && m_trayIcon->isVisible() && config()->get("GUI/MinimizeToTray").toBool()) { event->ignore(); - QTimer::singleShot(0, this, SLOT(hide())); + hide(); } if (config()->get("security/lockdatabaseminimize").toBool()) { @@ -1245,7 +1245,7 @@ void MainWindow::applySettingsChanges() void MainWindow::focusWindowChanged(QWindow* focusWindow) { if (focusWindow != windowHandle()) { - m_lastFocusOutTime = Clock::currentSecondsSinceEpoch(); + m_lastFocusOutTime = Clock::currentMilliSecondsSinceEpoch(); } } @@ -1269,9 +1269,9 @@ void MainWindow::processTrayIconTrigger() || m_trayIconTriggerReason == QSystemTrayIcon::MiddleClick) { // Toggle window if is not in front. #ifdef Q_OS_WIN - // If on Windows, check if focus switched within the last second because + // If on Windows, check if focus switched within the 500 milliseconds since // clicking the tray icon removes focus from main window. - if (isHidden() || (Clock::currentSecondsSinceEpoch() - m_lastFocusOutTime) <= 1) { + if (isHidden() || (Clock::currentMilliSecondsSinceEpoch() - m_lastFocusOutTime) <= 500) { #else // If on Linux or macOS, check if the window has focus. if (hasFocus() || isHidden() || windowHandle()->isActive()) { @@ -1283,16 +1283,43 @@ void MainWindow::processTrayIconTrigger() } } +void MainWindow::show() +{ +#ifndef Q_OS_WIN + m_lastShowTime = Clock::currentMilliSecondsSinceEpoch(); +#endif + QMainWindow::show(); +} + +bool MainWindow::shouldHide() +{ +#ifndef Q_OS_WIN + qint64 current_time = Clock::currentMilliSecondsSinceEpoch(); + + if (current_time - m_lastShowTime < 50) { + return false; + } +#endif + return true; +} + +void MainWindow::hide() +{ + if (shouldHide()) { + QMainWindow::hide(); + } +} + void MainWindow::hideWindow() { saveWindowInformation(); -#if !defined(Q_OS_LINUX) && !defined(Q_OS_MACOS) - // On some Linux systems, the window should NOT be minimized and hidden (i.e. not shown), at - // the same time (which would happen if both minimize on startup and minimize to tray are set) - // since otherwise it causes problems on restore as seen on issue #1595. Hiding it is enough. - // TODO: Add an explanation for why this is also not done on Mac (or remove the check) - setWindowState(windowState() | Qt::WindowMinimized); -#endif + if (QGuiApplication::platformName() != "xcb") { + // In X11 the window should NOT be minimized and hidden (i.e. not + // shown) at the same time (which would happen if both minimize on + // startup and minimize to tray are set) since otherwise it causes + // problems on restore as seen on issue #1595. Hiding it is enough. + setWindowState(windowState() | Qt::WindowMinimized); + } // Only hide if tray icon is active, otherwise window will be gone forever if (isTrayIconEnabled()) { hide(); @@ -1305,6 +1332,15 @@ void MainWindow::hideWindow() } } +void MainWindow::minimizeOrHide() +{ + if (config()->get("GUI/MinimizeToTray").toBool()) { + hideWindow(); + } else { + showMinimized(); + } +} + void MainWindow::toggleWindow() { if (isVisible() && !isMinimized()) { diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 0e74edf60..83a504f82 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -70,7 +70,10 @@ public slots: void hideGlobalMessage(); void showYubiKeyPopup(); void hideYubiKeyPopup(); + void hide(); + void show(); void hideWindow(); + void minimizeOrHide(); void toggleWindow(); void bringToFront(); void closeAllDatabases(); @@ -133,6 +136,7 @@ private: static const QString BaseWindowTitle; + bool shouldHide(); void saveWindowInformation(); bool saveLastDatabases(); void updateTrayIcon(); @@ -163,7 +167,8 @@ private: bool m_appExitCalled = false; bool m_appExiting = false; bool m_contextMenuFocusLock = false; - uint m_lastFocusOutTime = 0; + qint64 m_lastFocusOutTime = 0; + qint64 m_lastShowTime = 0; QTimer m_trayIconTriggerTimer; QSystemTrayIcon::ActivationReason m_trayIconTriggerReason; }; diff --git a/src/gui/TotpDialog.cpp b/src/gui/TotpDialog.cpp index 639eb0ebd..7292cfcd3 100644 --- a/src/gui/TotpDialog.cpp +++ b/src/gui/TotpDialog.cpp @@ -67,7 +67,7 @@ void TotpDialog::copyToClipboard() clipboard()->setText(m_entry->totp()); if (config()->get("HideWindowOnCopy").toBool()) { if (config()->get("MinimizeOnCopy").toBool()) { - getMainWindow()->showMinimized(); + getMainWindow()->minimizeOrHide(); } else if (config()->get("DropToBackgroundOnCopy").toBool()) { getMainWindow()->lower(); window()->lower(); diff --git a/src/gui/TotpExportSettingsDialog.cpp b/src/gui/TotpExportSettingsDialog.cpp index 178cd6d96..ea14eabdb 100644 --- a/src/gui/TotpExportSettingsDialog.cpp +++ b/src/gui/TotpExportSettingsDialog.cpp @@ -105,7 +105,7 @@ void TotpExportSettingsDialog::copyToClipboard() clipboard()->setText(m_totpUri); if (config()->get("HideWindowOnCopy").toBool()) { if (config()->get("MinimizeOnCopy").toBool()) { - getMainWindow()->showMinimized(); + getMainWindow()->minimizeOrHide(); } else if (config()->get("DropToBackgroundOnCopy").toBool()) { getMainWindow()->lower(); window()->lower();