From 0586415946169ac21b2bf186a35560a6ab593a1f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sat, 1 Aug 2015 12:25:39 +0200 Subject: [PATCH] Instead of resetting the focus back to the parent on the WM_DESTROY message, do it right before the progress dialog closes but after attaching the thread to the main window queue Based on TortoiseSVN revision 26347. This also relates to issue #1536 and is a better fix for issue #1786. Signed-off-by: Sven Strickroth --- src/Utils/MiscUI/SysProgressDlg.cpp | 59 ++++++++----------------------------- src/Utils/MiscUI/SysProgressDlg.h | 6 +--- 2 files changed, 14 insertions(+), 51 deletions(-) diff --git a/src/Utils/MiscUI/SysProgressDlg.cpp b/src/Utils/MiscUI/SysProgressDlg.cpp index ee4dcb22c..507340e6f 100644 --- a/src/Utils/MiscUI/SysProgressDlg.cpp +++ b/src/Utils/MiscUI/SysProgressDlg.cpp @@ -1,7 +1,7 @@ // TortoiseGit - a Windows shell extension for easy version control // Copyright (C) 2010-2013 - TortoiseGit -// Copyright (C) 2003-2006,2008-2011 - TortoiseSVN +// Copyright (C) 2003-2006,2008-2011,2015 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -26,7 +26,6 @@ CSysProgressDlg::CSysProgressDlg() , m_dwDlgFlags(PROGDLG_NORMAL) , m_hWndProgDlg(NULL) , m_hWndParent(NULL) - , m_OrigProc(0) { EnsureValid(); } @@ -203,28 +202,6 @@ HRESULT CSysProgressDlg::ShowModal(HWND hWndParent, BOOL immediately /* = true * hr2 = pOleWindow->GetWindow(&m_hWndProgDlg); if(SUCCEEDED(hr2)) { - // StartProgressDialog creates a new thread to host the progress window. - // When the window receives WM_DESTROY message StopProgressDialog() wrongly - // attempts to re-enable the parent in the calling thread (our thread), - // after the progress window is destroyed and the progress thread has died. - // When the progress window dies, the system tries to assign a new foreground window. - // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window. - // So the system hands the foreground activation to the next process that wants it in the - // system foreground queue. Thus we lose our right to recapture the foreground window. - // The way to fix this bug is to insert a call to EnableWindow(hWndParent) in the WM_DESTROY - // handler for the progress window in the progress thread. - - // To do that, we Subclass the progress dialog - // Since the window and thread created by the progress dialog object live on a few - // milliseconds after calling Stop() and Release(), we must not store anything - // in member variables of this class but must only store everything in the window - // itself: thus we use SetProp()/GetProp() to store the data. - if (!m_isVisible) - { - m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass); - SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent); - SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc); - } if(immediately) ShowWindow(m_hWndProgDlg, SW_SHOW); } @@ -252,13 +229,6 @@ HRESULT CSysProgressDlg::ShowModeless(HWND hWndParent, BOOL immediately) hr2 = pOleWindow->GetWindow(&m_hWndProgDlg); if(SUCCEEDED(hr2)) { - // see comment in ShowModal() for why we subclass the window - if (!m_isVisible) - { - m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass); - SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent); - SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc); - } if (immediately) ShowWindow(m_hWndProgDlg, SW_SHOW); } @@ -320,7 +290,19 @@ void CSysProgressDlg::Stop() // all messages until there are no more messages: that's when // the progress dialog is really gone. AttachThreadInput(GetWindowThreadProcessId(m_hWndProgDlg, 0), GetCurrentThreadId(), TRUE); + // StartProgressDialog creates a new thread to host the progress window. + // When the window receives WM_DESTROY message StopProgressDialog() wrongly + // attempts to re-enable the parent in the calling thread (our thread), + // after the progress window is destroyed and the progress thread has died. + // When the progress window dies, the system tries to assign a new foreground window. + // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window. + // So the system hands the foreground activation to the next process that wants it in the + // system foreground queue. Thus we lose our right to recapture the foreground window. + // To fix this problem, we enable the parent window and set to focus to it here, after + // we've attached to the window thread. ShowWindow(m_hWndProgDlg, SW_HIDE); + EnableWindow(m_hWndParent, TRUE); + SetFocus(m_hWndParent); auto start = GetTickCount64(); while (::IsWindow(m_hWndProgDlg) && ((GetTickCount64() - start) < 3000)) { @@ -344,18 +326,3 @@ void CSysProgressDlg::ResetTimer() m_pIDlg->Timer(PDTIMER_RESET, NULL); } } - -LRESULT CSysProgressDlg::fnSubclass(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - LONG_PTR origproc = (LONG_PTR)GetProp(hwnd, L"OrigProc"); - if (uMsg == WM_DESTROY) - { - HWND hParent = (HWND)GetProp(hwnd, L"ParentWindow"); - EnableWindow(hParent, TRUE); - SetFocus(hParent); - SetWindowLongPtr (hwnd, GWLP_WNDPROC, origproc); - RemoveProp(hwnd, L"ParentWindow"); - RemoveProp(hwnd, L"OrigProc"); - } - return CallWindowProc ((WNDPROC)origproc, hwnd, uMsg, wParam, lParam); -} diff --git a/src/Utils/MiscUI/SysProgressDlg.h b/src/Utils/MiscUI/SysProgressDlg.h index a916ba51a..e80743237 100644 --- a/src/Utils/MiscUI/SysProgressDlg.h +++ b/src/Utils/MiscUI/SysProgressDlg.h @@ -1,6 +1,6 @@ // TortoiseGit - a Windows shell extension for easy version control -// Copyright (C) 2003-2011 - TortoiseSVN +// Copyright (C) 2003-2011, 2015 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -173,14 +173,10 @@ public: */ bool EnsureValid(); -private: - static LRESULT fnSubclass(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - protected: ATL::CComPtr m_pIDlg; bool m_isVisible; DWORD m_dwDlgFlags; HWND m_hWndProgDlg; HWND m_hWndParent; - WNDPROC m_OrigProc; }; -- 2.11.4.GIT