Fix bug with showing TLW in wxMSW when restoring its geometry

Since the changes of 6ae7aa4443, the
windows were shown when their geometry was restored as a side effect of
calling ::SetWindowPlacement(). This was unexpected and resulted in
flicker on startup, so fix this by explicitly passing SW_HIDE to
SetWindowPlacement() if the window is currently hidden and storing the
real show command inside wxTLW itself, where it will be used when it's
finally shown.
This commit is contained in:
Vadim Zeitlin
2018-06-22 03:25:43 +02:00
parent 3518f1a7d8
commit cf20a9ced5
3 changed files with 31 additions and 2 deletions

View File

@@ -77,12 +77,20 @@ public:
wxCopyRectToRECT(r, m_placement.rcNormalPosition); wxCopyRectToRECT(r, m_placement.rcNormalPosition);
// Maximized/minimized state. // Maximized/minimized state.
//
// Note the special case of SW_MINIMIZE: while GetWindowPlacement()
// returns SW_SHOWMINIMIZED when the window is iconized, we restore it
// as SW_MINIMIZE as this is what the code in wxTLW checks to determine
// whether the window is supposed to be iconized or not.
//
// Just to confuse matters further, note that SW_MAXIMIZE is exactly
// the same thing as SW_SHOWMAXIMIZED.
int tmp; int tmp;
UINT& show = m_placement.showCmd; UINT& show = m_placement.showCmd;
if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp ) if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp )
show = SW_SHOWMAXIMIZED; show = SW_MAXIMIZE;
else if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) && tmp ) else if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) && tmp )
show = SW_SHOWMINIMIZED; show = SW_MINIMIZE;
else else
show = SW_SHOWNORMAL; show = SW_SHOWNORMAL;
@@ -110,6 +118,18 @@ public:
virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE
{ {
// There is a subtlety here: if the window is currently hidden,
// restoring its geometry shouldn't show it, so we must use SW_HIDE as
// show command, but showing it later should restore it to the correct
// state, so we need to remember it in wxTLW itself. And even if it's
// currently shown, we still need to update its show command, so that
// it matches the real window state after SetWindowPlacement() call.
tlw->MSWSetShowCommand(m_placement.showCmd);
if ( !tlw->IsShown() )
{
m_placement.showCmd = SW_HIDE;
}
if ( !::SetWindowPlacement(GetHwndOf(tlw), &m_placement) ) if ( !::SetWindowPlacement(GetHwndOf(tlw), &m_placement) )
{ {
wxLogLastError(wxS("SetWindowPlacement")); wxLogLastError(wxS("SetWindowPlacement"));

View File

@@ -116,6 +116,9 @@ public:
// returns true if the platform should explicitly apply a theme border // returns true if the platform should explicitly apply a theme border
virtual bool CanApplyThemeBorder() const wxOVERRIDE { return false; } virtual bool CanApplyThemeBorder() const wxOVERRIDE { return false; }
// This function is only for internal use.
void MSWSetShowCommand(WXUINT showCmd) { m_showCmd = showCmd; }
protected: protected:
// common part of all ctors // common part of all ctors
void Init(); void Init();

View File

@@ -743,6 +743,12 @@ bool wxFrame::MSWDoTranslateMessage(wxFrame *frame, WXMSG *pMsg)
bool wxFrame::HandleSize(int WXUNUSED(x), int WXUNUSED(y), WXUINT id) bool wxFrame::HandleSize(int WXUNUSED(x), int WXUNUSED(y), WXUINT id)
{ {
// We can get a WM_SIZE when restoring a hidden window using
// SetWindowPlacement(), don't do anything in this case as our state will
// be really updated later, when (and if) we're shown.
if ( !IsShown() )
return true;
switch ( id ) switch ( id )
{ {
case SIZE_RESTORED: case SIZE_RESTORED: