From f04a46364c3fe1e5f8efc616854fc1fe3cfb3216 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 29 Apr 2018 01:20:45 +0200 Subject: [PATCH 1/3] Remove useless forward declaration of wxTopLevelWindowBase This class is fully declared just below, so there is no need to forward-declare it. --- include/wx/toplevel.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/wx/toplevel.h b/include/wx/toplevel.h index 47c5798ebc..50b5e26121 100644 --- a/include/wx/toplevel.h +++ b/include/wx/toplevel.h @@ -24,8 +24,6 @@ // the default names for various classes extern WXDLLIMPEXP_DATA_CORE(const char) wxFrameNameStr[]; -class WXDLLIMPEXP_FWD_CORE wxTopLevelWindowBase; - // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- From d97c0555141ac28e7cd8fbc9688c0a998c58e781 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 29 Apr 2018 19:37:42 +0200 Subject: [PATCH 2/3] Introduce platform-dependent wxTLWGeometry class Previously, TLW geometry was implicitly defined as just its position, size and the maximized/iconized state by wxPersistentTLW code. This already wasn't enough for wxGTK which added the decoration sizes to the geometry being saved/restored, but this had to be done using conditional compilation, which was not ideal. And it didn't allow using an entirely different geometry representation as will be done for wxMSW soon. Change the code to use wxTLWGeometry class defining the geometry, as used by the current port, explicitly and move wxPersistentTLW logic into it, as wxPersistentXXX classes are supposed to be very simple, which wasn't really the case. Also provide public SaveGeometry() and RestoreToGeometry() methods in wxTopLevelWindow, which can be useful even to people not using wxPersistentTLW for whatever reason. There should be no changes in behaviour so far. --- include/wx/gtk/private/tlwgeom.h | 77 ++++++++++++++ include/wx/persist/toplevel.h | 107 +++---------------- include/wx/private/tlwgeom.h | 177 +++++++++++++++++++++++++++++++ include/wx/toplevel.h | 29 +++++ interface/wx/toplevel.h | 88 +++++++++++++++ src/common/toplvcmn.cpp | 24 +++++ 6 files changed, 410 insertions(+), 92 deletions(-) create mode 100644 include/wx/gtk/private/tlwgeom.h create mode 100644 include/wx/private/tlwgeom.h diff --git a/include/wx/gtk/private/tlwgeom.h b/include/wx/gtk/private/tlwgeom.h new file mode 100644 index 0000000000..31cc355997 --- /dev/null +++ b/include/wx/gtk/private/tlwgeom.h @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/gtk/private/tlwgeom.h +// Purpose: wxGTK-specific wxTLWGeometry class. +// Author: Vadim Zeitlin +// Created: 2018-04-29 +// Copyright: (c) 2018 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_GTK_PRIVATE_TLWGEOM_H_ +#define _WX_GTK_PRIVATE_TLWGEOM_H_ + +class wxTLWGeometry : public wxTLWGeometryGeneric +{ +public: + virtual bool Save(const Serializer& ser) const wxOVERRIDE + { + if ( !wxTLWGeometryGeneric::Save(ser) ) + return false; + + // Don't save the decoration sizes if we don't really have any values + // for them. + if ( m_decorSize.left || m_decorSize.right || + m_decorSize.top || m_decorSize.bottom ) + { + ser.SaveField("decor_l", m_decorSize.left); + ser.SaveField("decor_r", m_decorSize.right); + ser.SaveField("decor_t", m_decorSize.top); + ser.SaveField("decor_b", m_decorSize.bottom); + } + + return true; + } + + virtual bool Restore(Serializer& ser) wxOVERRIDE + { + if ( !wxTLWGeometryGeneric::Restore(ser) ) + return false; + + ser.RestoreField("decor_l", &m_decorSize.left); + ser.RestoreField("decor_r", &m_decorSize.right); + ser.RestoreField("decor_t", &m_decorSize.top); + ser.RestoreField("decor_b", &m_decorSize.bottom); + + return true; + } + + virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE + { + if ( !wxTLWGeometryGeneric::GetFrom(tlw) ) + return false; + + m_decorSize = tlw->m_decorSize; + + return true; + } + + virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE + { + if ( !wxTLWGeometryGeneric::ApplyTo(tlw) ) + return false; + + // Don't overwrite the current decoration size if we already have it. + if ( !tlw->m_decorSize.left && !tlw->m_decorSize.right && + !tlw->m_decorSize.top && !tlw->m_decorSize.bottom ) + { + tlw->m_decorSize = m_decorSize; + } + + return true; + } + +private: + wxTopLevelWindow::DecorSize m_decorSize; +}; + +#endif // _WX_GTK_PRIVATE_TLWGEOM_H_ diff --git a/include/wx/persist/toplevel.h b/include/wx/persist/toplevel.h index 07c1d61ae2..c1bec8667a 100644 --- a/include/wx/persist/toplevel.h +++ b/include/wx/persist/toplevel.h @@ -13,7 +13,6 @@ #include "wx/persist/window.h" #include "wx/toplevel.h" -#include "wx/display.h" // ---------------------------------------------------------------------------- // string constants used by wxPersistentTLW @@ -24,21 +23,13 @@ // windows, just persistent controls which have their own specific kind strings #define wxPERSIST_TLW_KIND "Window" -// names for various persistent options -#define wxPERSIST_TLW_X "x" -#define wxPERSIST_TLW_Y "y" -#define wxPERSIST_TLW_W "w" -#define wxPERSIST_TLW_H "h" - -#define wxPERSIST_TLW_MAXIMIZED "Maximized" -#define wxPERSIST_TLW_ICONIZED "Iconized" - // ---------------------------------------------------------------------------- // wxPersistentTLW: supports saving/restoring window position and size as well // as maximized/iconized/restore state // ---------------------------------------------------------------------------- -class wxPersistentTLW : public wxPersistentWindow +class wxPersistentTLW : public wxPersistentWindow, + private wxTopLevelWindow::GeometrySerializer { public: wxPersistentTLW(wxTopLevelWindow *tlw) @@ -50,96 +41,28 @@ public: { const wxTopLevelWindow * const tlw = Get(); - const wxPoint pos = tlw->GetScreenPosition(); - SaveValue(wxPERSIST_TLW_X, pos.x); - SaveValue(wxPERSIST_TLW_Y, pos.y); - - // notice that we use GetSize() here and not GetClientSize() because - // the latter doesn't return correct results for the minimized windows - // (at least not under Windows) - // - // of course, it shouldn't matter anyhow usually, the client size - // should be preserved as well unless the size of the decorations - // changed between the runs - const wxSize size = tlw->GetSize(); - SaveValue(wxPERSIST_TLW_W, size.x); - SaveValue(wxPERSIST_TLW_H, size.y); - - SaveValue(wxPERSIST_TLW_MAXIMIZED, tlw->IsMaximized()); - SaveValue(wxPERSIST_TLW_ICONIZED, tlw->IsIconized()); -#ifdef __WXGTK20__ - SaveValue("decor_l", tlw->m_decorSize.left); - SaveValue("decor_r", tlw->m_decorSize.right); - SaveValue("decor_t", tlw->m_decorSize.top); - SaveValue("decor_b", tlw->m_decorSize.bottom); -#endif + tlw->SaveGeometry(*this); } virtual bool Restore() wxOVERRIDE { wxTopLevelWindow * const tlw = Get(); - wxPoint pos; - wxSize size; - - const bool hasPos = RestoreValue(wxPERSIST_TLW_X, &pos.x) && - RestoreValue(wxPERSIST_TLW_Y, &pos.y); - const bool hasSize = RestoreValue(wxPERSIST_TLW_W, &size.x) && - RestoreValue(wxPERSIST_TLW_H, &size.y); -#ifdef __WXGTK20__ - wxTopLevelWindowGTK::DecorSize decorSize; - if (tlw->m_decorSize.top == 0 && - RestoreValue("decor_l", &decorSize.left) && - RestoreValue("decor_r", &decorSize.right) && - RestoreValue("decor_t", &decorSize.top) && - RestoreValue("decor_b", &decorSize.bottom)) - { - tlw->m_decorSize = decorSize; - } -#endif - - if ( hasPos ) - { - // to avoid making the window completely invisible if it had been - // shown on a monitor which was disconnected since the last run - // (this is pretty common for notebook with external displays) - // - // NB: we should allow window position to be (slightly) off screen, - // it's not uncommon to position the window so that its upper - // left corner has slightly negative coordinate - if ( wxDisplay::GetFromPoint(pos) != wxNOT_FOUND || - (hasSize && wxDisplay::GetFromPoint(pos + size) != wxNOT_FOUND) ) - { - tlw->Move(pos, wxSIZE_ALLOW_MINUS_ONE); - } - //else: should we try to adjust position/size somehow? - } - - if ( hasSize ) - { - // a previous version of the program could have saved the window - // size which used to be big enough, but which is not big enough - // any more for the new version, so check that the size we restore - // doesn't cut off parts of the window - size.IncTo(tlw->GetBestSize()); - tlw->SetSize(size); - } - - // note that the window can be both maximized and iconized - bool maximized; - if ( RestoreValue(wxPERSIST_TLW_MAXIMIZED, &maximized) && maximized ) - tlw->Maximize(); - - bool iconized; - if ( RestoreValue(wxPERSIST_TLW_ICONIZED, &iconized) && iconized ) - tlw->Iconize(); - - // the most important property of the window that we restore is its - // size, so disregard the value of hasPos here - return hasSize; + return tlw->RestoreToGeometry(*this); } virtual wxString GetKind() const wxOVERRIDE { return wxPERSIST_TLW_KIND; } + +private: + virtual bool SaveField(const wxString& name, int value) const wxOVERRIDE + { + return SaveValue(name, value); + } + + virtual bool RestoreField(const wxString& name, int* value) wxOVERRIDE + { + return RestoreValue(name, value); + } }; inline wxPersistentObject *wxCreatePersistentObject(wxTopLevelWindow *tlw) diff --git a/include/wx/private/tlwgeom.h b/include/wx/private/tlwgeom.h new file mode 100644 index 0000000000..aa601f14e3 --- /dev/null +++ b/include/wx/private/tlwgeom.h @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/private/tlwgeom.h +// Purpose: Declaration of platform-specific and private wxTLWGeometry. +// Author: Vadim Zeitlin +// Created: 2018-04-29 +// Copyright: (c) 2018 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_TLWGEOM_H_ +#define _WX_PRIVATE_TLWGEOM_H_ + +#include "wx/display.h" +#include "wx/toplevel.h" + +// ---------------------------------------------------------------------------- +// wxTLWGeometryBase: abstract base class for platform-specific classes +// ---------------------------------------------------------------------------- + +// wxTLWGeometry contains full information about the window geometry, which may +// include things other than the obvious ones like its current position and +// size (e.g. under MSW it also stores the position of the maximized window, +// under GTK the size of non-client decorations etc). It is private to wx and +// is only used indirectly, via wxTopLevelWindow::SaveGeometry() and +// RestoreToGeometry() methods, in the public API. + +class wxTLWGeometryBase +{ +public: + typedef wxTopLevelWindow::GeometrySerializer Serializer; + + wxTLWGeometryBase() {} + virtual ~wxTLWGeometryBase() {} + + // Initialize from the given window. + virtual bool GetFrom(const wxTopLevelWindow* tlw) = 0; + + // Resize the window to use this geometry. + virtual bool ApplyTo(wxTopLevelWindow* tlw) = 0; + + // Serialize or deserialize the object by using the provided object for + // writing/reading the values of the different fields of this object. + virtual bool Save(const Serializer& ser) const = 0; + virtual bool Restore(Serializer& ser) = 0; +}; + +// ---------------------------------------------------------------------------- +// wxTLWGeometryGeneric: simplest possible generic implementation +// ---------------------------------------------------------------------------- + +// names for various persistent options +#define wxPERSIST_TLW_X "x" +#define wxPERSIST_TLW_Y "y" +#define wxPERSIST_TLW_W "w" +#define wxPERSIST_TLW_H "h" + +#define wxPERSIST_TLW_MAXIMIZED "Maximized" +#define wxPERSIST_TLW_ICONIZED "Iconized" + +class wxTLWGeometryGeneric : public wxTLWGeometryBase +{ +public: + wxTLWGeometryGeneric() + { + m_hasPos = + m_hasSize = + m_iconized = + m_maximized = false; + } + + virtual bool Save(const Serializer& ser) const wxOVERRIDE + { + if ( !ser.SaveField(wxPERSIST_TLW_X, m_rectScreen.x) || + !ser.SaveField(wxPERSIST_TLW_Y, m_rectScreen.y) ) + return false; + + if ( !ser.SaveField(wxPERSIST_TLW_W, m_rectScreen.width) || + !ser.SaveField(wxPERSIST_TLW_H, m_rectScreen.height) ) + return false; + + if ( !ser.SaveField(wxPERSIST_TLW_MAXIMIZED, m_maximized) ) + return false; + + if ( !ser.SaveField(wxPERSIST_TLW_ICONIZED, m_iconized) ) + return false; + + return true; + } + + virtual bool Restore(Serializer& ser) wxOVERRIDE + { + m_hasPos = ser.RestoreField(wxPERSIST_TLW_X, &m_rectScreen.x) && + ser.RestoreField(wxPERSIST_TLW_Y, &m_rectScreen.y); + + m_hasSize = ser.RestoreField(wxPERSIST_TLW_W, &m_rectScreen.width) && + ser.RestoreField(wxPERSIST_TLW_H, &m_rectScreen.height); + + int tmp; + if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) ) + m_maximized = tmp != 0; + + if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) ) + m_iconized = tmp != 0; + + // If we restored at least something, return true. + return m_hasPos || m_hasSize || m_maximized || m_iconized; + } + + virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE + { + m_rectScreen = tlw->GetScreenRect(); + m_hasPos = + m_hasSize = true; + m_iconized = tlw->IsIconized(); + m_maximized = tlw->IsMaximized(); + + return true; + } + + virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE + { + if ( m_hasPos ) + { + // to avoid making the window completely invisible if it had been + // shown on a monitor which was disconnected since the last run + // (this is pretty common for notebook with external displays) + // + // NB: we should allow window position to be (slightly) off screen, + // it's not uncommon to position the window so that its upper + // left corner has slightly negative coordinate + if ( wxDisplay::GetFromPoint(m_rectScreen.GetTopLeft()) != wxNOT_FOUND || + (m_hasSize && + wxDisplay::GetFromPoint(m_rectScreen.GetBottomRight()) != wxNOT_FOUND) ) + { + tlw->Move(m_rectScreen.GetTopLeft(), wxSIZE_ALLOW_MINUS_ONE); + } + //else: should we try to adjust position/size somehow? + } + + if ( m_hasSize ) + { + // a previous version of the program could have saved the window + // size which used to be big enough, but which is not big enough + // any more for the new version, so check that the size we restore + // doesn't cut off parts of the window + wxSize size = m_rectScreen.GetSize(); + size.IncTo(tlw->GetBestSize()); + tlw->SetSize(size); + } + + // note that the window can be both maximized and iconized + if ( m_maximized ) + tlw->Maximize(); + + if ( m_iconized ) + tlw->Iconize(); + + return true; + } + +private: + wxRect m_rectScreen; + bool m_hasPos; + bool m_hasSize; + bool m_iconized; + bool m_maximized; +}; + +#ifdef __WXGTK20__ + #include "wx/gtk/private/tlwgeom.h" +#else + class wxTLWGeometry : public wxTLWGeometryGeneric + { + }; +#endif + +#endif // _WX_PRIVATE_TLWGEOM_H_ diff --git a/include/wx/toplevel.h b/include/wx/toplevel.h index 50b5e26121..9927d67db1 100644 --- a/include/wx/toplevel.h +++ b/include/wx/toplevel.h @@ -238,6 +238,35 @@ public: wxWindow *SetTmpDefaultItem(wxWindow *win) { wxWindow *old = GetDefaultItem(); m_winTmpDefault = win; return old; } + + // Class for saving/restoring fields describing the window geometry. + // + // This class is used by the functions below to allow saving the geometry + // of the window and restoring it later. The components describing geometry + // are platform-dependent, so there is no struct containing them and + // instead the methods of this class are used to save or [try to] restore + // whichever components are used under the current platform. + class GeometrySerializer + { + public: + virtual ~GeometrySerializer() {} + + // If saving a field returns false, it's fatal error and SaveGeometry() + // will return false. + virtual bool SaveField(const wxString& name, int value) const = 0; + + // If restoring a field returns false, it just means that the field is + // not present and RestoreToGeometry() still continues with restoring + // the other values. + virtual bool RestoreField(const wxString& name, int* value) = 0; + }; + + // Save the current window geometry using the provided serializer and + // restore the window to the previously saved geometry. + bool SaveGeometry(const GeometrySerializer& ser) const; + bool RestoreToGeometry(GeometrySerializer& ser); + + // implementation only from now on // ------------------------------- diff --git a/interface/wx/toplevel.h b/interface/wx/toplevel.h index 0dd1befbc8..44731c8790 100644 --- a/interface/wx/toplevel.h +++ b/interface/wx/toplevel.h @@ -350,6 +350,94 @@ public: */ void Restore(); + /** + Class used with SaveGeometry() and RestoreToGeometry(). + + This is an abstract base class, i.e. to use it you must define a + derived class implementing the pure virtual SaveField() and + RestoreField() methods. + + For example, if you wished to store the window geometry in a database, + you could derive a class saving fields such as "width" or "height" in a + table in this database and restoring them from it later. + + @since 3.1.2 + */ + class GeometrySerializer + { + /** + Save a single field with the given value. + + Note that if this function returns @false, SaveGeometry() supposes + that saving the geometry failed and returns @false itself, without + even trying to save anything else. + + @param name uniquely identifies the field but is otherwise + arbitrary. + @param value value of the field (can be positive or negative, i.e. + it can't be assumed that a value like -1 is invalid). + + @return @true if the field was saved or @false if saving it failed, + resulting in wxTopLevelWindow::SaveGeometry() failure. + */ + virtual bool SaveField(const wxString& name, int value) const = 0; + + /** + Try to restore a single field. + + Unlike for SaveField(), returning @false from this function may + indicate that the value simply wasn't present and doesn't prevent + RestoreToGeometry() from continuing with trying to restore the + other values. + + @param name uniquely identifies the field + @param value non-@NULL pointer to the value to be filled by this + function + + @return @true if the value was retrieved or @false if it wasn't + found or an error occurred. + */ + virtual bool RestoreField(const wxString& name, int* value) = 0; + }; + + /** + Restores the window to the previously saved geometry. + + This is a companion function to SaveGeometry() and can be called later + to restore the window to the geometry it had when it was saved. + + @param ser An object implementing GeometrySerializer virtual methods. + + @return @true if any (and, usually, but not necessarily, all) of the + window geometry attributes were restored or @false if there was no + saved geometry information at all or restoring it failed. + + @since 3.1.2 + */ + bool RestoreToGeometry(GeometrySerializer& ser); + + /** + Save the current window geometry to allow restoring it later. + + After calling this function, window geometry is saved in the provided + serializer and calling RestoreToGeometry() with the same serializer + later (i.e. usually during a subsequent program execution) would + restore the window to the same position, size, maximized/minimized + state etc. + + This function is used by wxPersistentTLW, so it is not necessary to use + it if the goal is to just save and restore window geometry in the + simplest possible way. However is more flexibility is required, it can + be also used directly with a custom serializer object. + + @param ser An object implementing GeometrySerializer virtual methods. + + @return @true if the geometry was saved, @false if doing it failed + + @since 3.1.2 + */ + bool SaveGeometry(const GeometrySerializer& ser) const; + /** Changes the default item for the panel, usually @a win is a button. diff --git a/src/common/toplvcmn.cpp b/src/common/toplvcmn.cpp index c5eff7f463..a5660a3b23 100644 --- a/src/common/toplvcmn.cpp +++ b/src/common/toplvcmn.cpp @@ -31,6 +31,8 @@ #include "wx/display.h" +#include "wx/private/tlwgeom.h" + // ---------------------------------------------------------------------------- // event table // ---------------------------------------------------------------------------- @@ -310,6 +312,28 @@ void wxTopLevelWindowBase::DoCentre(int dir) SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); } +// ---------------------------------------------------------------------------- +// Saving/restoring geometry +// ---------------------------------------------------------------------------- + +bool wxTopLevelWindowBase::SaveGeometry(const GeometrySerializer& ser) const +{ + wxTLWGeometry geom; + if ( !geom.GetFrom(static_cast(this)) ) + return false; + + return geom.Save(ser); +} + +bool wxTopLevelWindowBase::RestoreToGeometry(GeometrySerializer& ser) +{ + wxTLWGeometry geom; + if ( !geom.Restore(ser) ) + return false; + + return geom.ApplyTo(static_cast(this)); +} + // ---------------------------------------------------------------------------- // wxTopLevelWindow size management: we exclude the areas taken by // menu/status/toolbars from the client area, so the client area is what's From 6ae7aa444358cd2618a57e9ab29826f1714dbb4b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 29 Apr 2018 20:30:30 +0200 Subject: [PATCH 3/3] Fix saving/restoring window position for maximized windows Save both the normal window geometry and its maximized position instead of saving just its current position. This fixes restoring geometry of the maximized windows as previously they were always restored on the primary monitor, as their original position was lost. Use the native {Get,Set}WindowPlacement() functions for a MSW-specific wxTLWGeometry implementation to achieve this. Closes #16335. --- docs/changes.txt | 1 + include/wx/msw/private/tlwgeom.h | 126 +++++++++++++++++++++++++++++++ include/wx/private/tlwgeom.h | 7 ++ tests/persistence/tlw.cpp | 53 +++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 include/wx/msw/private/tlwgeom.h diff --git a/docs/changes.txt b/docs/changes.txt index b9c6f3a7f3..2d67ba9c11 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -88,6 +88,7 @@ wxMSW: - Fix hang after clearing wxTAB_TRAVERSAL style on a window with children. - Fix handling of AUX2 mouse button events (Trylz). +- Fix saving/restoring window position for maximized windows. 3.1.1: (released 2018-02-19) diff --git a/include/wx/msw/private/tlwgeom.h b/include/wx/msw/private/tlwgeom.h new file mode 100644 index 0000000000..1142f94c6a --- /dev/null +++ b/include/wx/msw/private/tlwgeom.h @@ -0,0 +1,126 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/msw/private/tlwgeom.h +// Purpose: wxMSW-specific wxTLWGeometry class. +// Author: Vadim Zeitlin +// Created: 2018-04-29 +// Copyright: (c) 2018 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MSW_PRIVATE_TLWGEOM_H_ +#define _WX_MSW_PRIVATE_TLWGEOM_H_ + +#include "wx/log.h" + +#include "wx/msw/private.h" + +// names for MSW-specific options +#define wxPERSIST_TLW_MAX_X "xmax" +#define wxPERSIST_TLW_MAX_Y "ymax" + +class wxTLWGeometry : public wxTLWGeometryBase +{ +public: + wxTLWGeometry() + { + wxZeroMemory(m_placement); + m_placement.length = sizeof(m_placement); + } + + virtual bool Save(const Serializer& ser) const wxOVERRIDE + { + // For compatibility with the existing saved positions/sizes, use the + // same keys as the generic version (which was previously used under + // MSW too). + + // Normal position and size. + const RECT& rc = m_placement.rcNormalPosition; + if ( !ser.SaveField(wxPERSIST_TLW_X, rc.left) || + !ser.SaveField(wxPERSIST_TLW_Y, rc.top) ) + return false; + + if ( !ser.SaveField(wxPERSIST_TLW_W, rc.right - rc.left) || + !ser.SaveField(wxPERSIST_TLW_H, rc.bottom - rc.top) ) + return false; + + // Maximized/minimized state. + UINT show = m_placement.showCmd; + if ( !ser.SaveField(wxPERSIST_TLW_MAXIMIZED, show == SW_SHOWMAXIMIZED) ) + return false; + + if ( !ser.SaveField(wxPERSIST_TLW_ICONIZED, show == SW_SHOWMINIMIZED) ) + return false; + + // Maximized window position. + const POINT pt = m_placement.ptMaxPosition; + if ( !ser.SaveField(wxPERSIST_TLW_MAX_X, pt.x) || + !ser.SaveField(wxPERSIST_TLW_MAX_Y, pt.y) ) + return false; + + // We don't currently save the minimized window position, it doesn't + // seem useful for anything and is probably just a left over from + // Windows 3.1 days, when icons were positioned on the desktop instead + // of being located in the taskbar. + + return true; + } + + virtual bool Restore(Serializer& ser) wxOVERRIDE + { + // Normal position and size. + wxRect r; + if ( !ser.RestoreField(wxPERSIST_TLW_X, &r.x) || + !ser.RestoreField(wxPERSIST_TLW_Y, &r.y) || + !ser.RestoreField(wxPERSIST_TLW_W, &r.width) || + !ser.RestoreField(wxPERSIST_TLW_H, &r.height) ) + return false; + wxCopyRectToRECT(r, m_placement.rcNormalPosition); + + // Maximized/minimized state. + int tmp; + UINT& show = m_placement.showCmd; + if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp ) + show = SW_SHOWMAXIMIZED; + else if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) && tmp ) + show = SW_SHOWMINIMIZED; + else + show = SW_SHOWNORMAL; + + // Maximized window position. + if ( ser.RestoreField(wxPERSIST_TLW_MAX_X, &r.x) && + ser.RestoreField(wxPERSIST_TLW_MAX_Y, &r.y) ) + { + m_placement.ptMaxPosition.x = r.x; + m_placement.ptMaxPosition.y = r.y; + } + + return true; + } + + virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE + { + if ( !::GetWindowPlacement(GetHwndOf(tlw), &m_placement) ) + { + wxLogLastError(wxS("GetWindowPlacement")); + return false; + } + + return true; + } + + virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE + { + if ( !::SetWindowPlacement(GetHwndOf(tlw), &m_placement) ) + { + wxLogLastError(wxS("SetWindowPlacement")); + return false; + } + + return true; + } + +private: + WINDOWPLACEMENT m_placement; +}; + +#endif // _WX_MSW_PRIVATE_TLWGEOM_H_ diff --git a/include/wx/private/tlwgeom.h b/include/wx/private/tlwgeom.h index aa601f14e3..0a273b8b8d 100644 --- a/include/wx/private/tlwgeom.h +++ b/include/wx/private/tlwgeom.h @@ -57,6 +57,9 @@ public: #define wxPERSIST_TLW_MAXIMIZED "Maximized" #define wxPERSIST_TLW_ICONIZED "Iconized" +// MSW has its own native implementation and doesn't use this class. +#ifndef __WXMSW__ + class wxTLWGeometryGeneric : public wxTLWGeometryBase { public: @@ -166,8 +169,12 @@ private: bool m_maximized; }; +#endif // !__WXMSW__ + #ifdef __WXGTK20__ #include "wx/gtk/private/tlwgeom.h" +#elif defined(__WXMSW__) + #include "wx/msw/private/tlwgeom.h" #else class wxTLWGeometry : public wxTLWGeometryGeneric { diff --git a/tests/persistence/tlw.cpp b/tests/persistence/tlw.cpp index 021f1bed64..e78d7e36ac 100644 --- a/tests/persistence/tlw.cpp +++ b/tests/persistence/tlw.cpp @@ -101,6 +101,59 @@ TEST_CASE_METHOD(PersistenceTests, "wxPersistTLW", "[persist][tlw]") CHECK(!frame->IsMaximized()); CHECK(!frame->IsIconized()); + // Next try that restoring a minimized frame works correctly: for + // Iconize() to have effect, we must show the frame first. + frame->Iconize(); + frame->Show(); + delete frame; } + + // Check geometry after restoring the minimized frame. + { + wxFrame* const frame = CreatePersistenceTestFrame(); + + CHECK(wxPersistenceManager::Get().RegisterAndRestore(frame)); + + CHECK(!frame->IsMaximized()); + CHECK(frame->IsIconized()); + + frame->Restore(); + + CHECK(pos.x == frame->GetPosition().x); + CHECK(pos.y == frame->GetPosition().y); + CHECK(size.x == frame->GetSize().GetWidth()); + CHECK(size.y == frame->GetSize().GetHeight()); + + // Next try that restoring a maximized frame works correctly: again, + // for it to be really maximized, it must be shown. + frame->Maximize(); + frame->Show(); + + delete frame; + } + + // Check geometry after restoring the maximized frame. + // + // This test currently fails under non-MSW platforms as they only save the + // maximized frame size, and its normal size is lost and can't be restored. +#ifdef __WXMSW__ + { + wxFrame* const frame = CreatePersistenceTestFrame(); + + CHECK(wxPersistenceManager::Get().RegisterAndRestore(frame)); + + CHECK(frame->IsMaximized()); + CHECK(!frame->IsIconized()); + + frame->Restore(); + + CHECK(pos.x == frame->GetPosition().x); + CHECK(pos.y == frame->GetPosition().y); + CHECK(size.x == frame->GetSize().GetWidth()); + CHECK(size.y == frame->GetSize().GetHeight()); + + delete frame; + } +#endif // __WXMSW__ }