diff options
-rw-r--r-- | changelog/unreleased/8979 | 1 | ||||
-rw-r--r-- | src/gui/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/gui/guiutility.cpp | 72 |
3 files changed, 60 insertions, 18 deletions
diff --git a/changelog/unreleased/8979 b/changelog/unreleased/8979 index 6dba41338..9116eedbe 100644 --- a/changelog/unreleased/8979 +++ b/changelog/unreleased/8979 @@ -5,3 +5,4 @@ We now ensure that we receive the window messages dispatched by the system. https://github.com/owncloud/client/issues/8979 https://github.com/owncloud/client/pull/9142 https://github.com/owncloud/client/pull/9220 +https://github.com/owncloud/client/pull/9227 diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 714417848..95ac47a57 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -2,6 +2,10 @@ include(ECMAddAppIcon) find_package(Qt5 REQUIRED COMPONENTS Widgets) +#if (WIN32) +# find_package(Qt5 REQUIRED COMPONENTS WinExtras) +#endif() + add_subdirectory(updater) set(client_UI_SRCS @@ -169,6 +173,7 @@ elseif( WIN32 ) target_sources(owncloudCore PRIVATE folderwatcher_win.cpp navigationpanehelper.cpp) +# target_link_libraries(owncloudCore PUBLIC Qt5::WinExtras) elseif(UNIX AND NOT APPLE ) ## handle DBUS for Fdo notifications find_package(Qt5 COMPONENTS DBus) diff --git a/src/gui/guiutility.cpp b/src/gui/guiutility.cpp index b8fbaac92..8414d0c5c 100644 --- a/src/gui/guiutility.cpp +++ b/src/gui/guiutility.cpp @@ -23,8 +23,15 @@ #include <QIcon> #ifdef Q_OS_WIN -#include <QThread> -#include <QTimer> +#include <QMetaMethod> + +#include <chrono> +#include <thread> + +using namespace std::chrono; +using namespace std::chrono_literals; + +#include "version.h" #endif #include "theme.h" @@ -38,47 +45,76 @@ Q_LOGGING_CATEGORY(lcUtility, "gui.utility", QtInfoMsg) namespace { #ifdef Q_OS_WIN -void watchWM() +// TODO: 2.11 move to the new Platform class +struct +{ + HANDLE windowMessageWatcherEvent = CreateEventW(nullptr, true, false, L"watchWMEvent"); + bool windowMessageWatcherRun = true; +} watchWMCtx; + +void startShutdownWatcher() { // Qt only receives window message if a window was displayed at least once // create an invisible window to handle WM_ENDSESSION - QThread::create([] { + // We also block a system shutdown until we are properly shutdown our selfs + // In the unlikely case that we require more than 5s Windows will require a fullscreen message + // with our icon, title and the reason why we are blocking the shutdown. + new std::thread([] { WNDCLASS wc = {}; wc.hInstance = GetModuleHandle(nullptr); wc.lpszClassName = L"ocWindowMessageWatcher"; +#if MIRALL_VERSION_MINOR > 9 +// TODO: for now we won't display a proper icon +#error "Please add the QtWinExtras dependency" + wc.hIcon = QtWin::toHICON(Theme::instance()->applicationIcon().pixmap(64, 64)); +#endif wc.lpfnWndProc = [](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT { // qDebug() << MSG { hwnd, msg, wParam, lParam, 0, {} }; if (msg == WM_QUERYENDSESSION) { + qCDebug(OCC::lcUtility) << "Received WM_QUERYENDSESSION"; return 1; } else if (msg == WM_ENDSESSION) { - qCInfo(OCC::lcUtility) << "Received WM_ENDSESSION quitting"; - QTimer::singleShot(0, qApp, &QApplication::quit); + qCDebug(OCC::lcUtility) << "Received WM_ENDSESSION quitting"; + QMetaObject::invokeMethod(qApp, &QApplication::quit); + QElapsedTimer shutdownTimer; + if (lParam == ENDSESSION_LOGOFF) { + // block the windows shutdown until we are done + const QString description = QApplication::translate("Utility", "Shutting down %1").arg(Theme::instance()->appNameGUI()); + OC_ASSERT(ShutdownBlockReasonCreate(hwnd, reinterpret_cast<const wchar_t *>(description.utf16()))); + } + WaitForSingleObject(watchWMCtx.windowMessageWatcherEvent, INFINITE); + if (lParam == ENDSESSION_LOGOFF) { + OC_ASSERT(ShutdownBlockReasonDestroy(hwnd)); + } + qCInfo(OCC::lcUtility) << "WM_ENDSESSION successfully shut down" << shutdownTimer.elapsed(); + watchWMCtx.windowMessageWatcherRun = false; return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); }; - OC_ASSERT(RegisterClass(&wc)); - auto window = CreateWindowW(wc.lpszClassName, L"watcher", WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, wc.hInstance, nullptr); - OC_ASSERT_X(window, Utility::formatWinError(GetLastError()).toUtf8().constData()); + auto watcherWindow = CreateWindowW(wc.lpszClassName, reinterpret_cast<const wchar_t *>(Theme::instance()->appNameGUI().utf16()), + WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, wc.hInstance, nullptr); + OC_ASSERT_X(watcherWindow, Utility::formatWinError(GetLastError()).toUtf8().constData()); - bool run = true; - QObject::connect(qApp, &QApplication::aboutToQuit, [&run] { - run = false; - }); MSG msg; - while (run) { - if (!PeekMessageW(&msg, window, 0, 0, PM_REMOVE)) { - QThread::msleep(100); + while (watchWMCtx.windowMessageWatcherRun) { + if (!PeekMessageW(&msg, watcherWindow, 0, 0, PM_REMOVE)) { + std::this_thread::sleep_for(100ms); } else { TranslateMessage(&msg); DispatchMessage(&msg); } } - })->start(); + }); + + qAddPostRoutine([] { + qCDebug(OCC::lcUtility) << "app closed"; + SetEvent(watchWMCtx.windowMessageWatcherEvent); + }); } -Q_COREAPP_STARTUP_FUNCTION(watchWM); +Q_COREAPP_STARTUP_FUNCTION(startShutdownWatcher); #endif } |