Replace wxTopLevelWindow::GeometrySerializer with GeometryStore

The old class used incorrect const qualifiers on its member functions:
saving function typically modifies the object being saved into, and so
must not be const, while loading function should be const, but the old
class reversed this.

Do it right this time in the new GeometryStore class and keep the old
class for compatibility only.

See #26602.
This commit is contained in:
Vadim Zeitlin
2026-06-19 17:14:39 +02:00
parent e743d674cf
commit 934705ef82
7 changed files with 126 additions and 83 deletions
+12 -12
View File
@@ -14,9 +14,9 @@ class wxTLWGeometry : public wxTLWGeometryGeneric
{
typedef wxTLWGeometryGeneric BaseType;
public:
virtual bool Save(const Serializer& ser) const override
virtual bool Save(Store& store) const override
{
if ( !wxTLWGeometryGeneric::Save(ser) )
if ( !wxTLWGeometryGeneric::Save(store) )
return false;
// Don't save the decoration sizes if we don't really have any values
@@ -24,24 +24,24 @@ public:
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);
store.SaveValue("decor_l", m_decorSize.left);
store.SaveValue("decor_r", m_decorSize.right);
store.SaveValue("decor_t", m_decorSize.top);
store.SaveValue("decor_b", m_decorSize.bottom);
}
return true;
}
virtual bool Restore(Serializer& ser) override
virtual bool Restore(const Store& store) override
{
if ( !wxTLWGeometryGeneric::Restore(ser) )
if ( !wxTLWGeometryGeneric::Restore(store) )
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);
store.RestoreValue("decor_l", &m_decorSize.left);
store.RestoreValue("decor_r", &m_decorSize.right);
store.RestoreValue("decor_t", &m_decorSize.top);
store.RestoreValue("decor_b", &m_decorSize.bottom);
return true;
}
+18 -18
View File
@@ -27,7 +27,7 @@ public:
m_placement.length = sizeof(m_placement);
}
virtual bool Save(const Serializer& ser) const override
virtual bool Save(Store& store) const override
{
// For compatibility with the existing saved positions/sizes, use the
// same keys as the generic version (which was previously used under
@@ -35,26 +35,26 @@ public:
// 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) )
if ( !store.SaveValue(wxPERSIST_TLW_X, rc.left) ||
!store.SaveValue(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) )
if ( !store.SaveValue(wxPERSIST_TLW_W, rc.right - rc.left) ||
!store.SaveValue(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) )
if ( !store.SaveValue(wxPERSIST_TLW_MAXIMIZED, show == SW_SHOWMAXIMIZED) )
return false;
if ( !ser.SaveField(wxPERSIST_TLW_ICONIZED, show == SW_SHOWMINIMIZED) )
if ( !store.SaveValue(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) )
if ( !store.SaveValue(wxPERSIST_TLW_MAX_X, pt.x) ||
!store.SaveValue(wxPERSIST_TLW_MAX_Y, pt.y) )
return false;
// We don't currently save the minimized window position, it doesn't
@@ -65,14 +65,14 @@ public:
return true;
}
virtual bool Restore(Serializer& ser) override
virtual bool Restore(const Store& store) override
{
// 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) )
if ( !store.RestoreValue(wxPERSIST_TLW_X, &r.x) ||
!store.RestoreValue(wxPERSIST_TLW_Y, &r.y) ||
!store.RestoreValue(wxPERSIST_TLW_W, &r.width) ||
!store.RestoreValue(wxPERSIST_TLW_H, &r.height) )
return false;
wxCopyRectToRECT(r, m_placement.rcNormalPosition);
@@ -87,16 +87,16 @@ public:
// the same thing as SW_SHOWMAXIMIZED.
int tmp;
UINT& show = m_placement.showCmd;
if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp )
if ( store.RestoreValue(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp )
show = SW_MAXIMIZE;
else if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) && tmp )
else if ( store.RestoreValue(wxPERSIST_TLW_ICONIZED, &tmp) && tmp )
show = SW_MINIMIZE;
else
show = SW_SHOWNORMAL;
// Maximized window position.
if ( ser.RestoreField(wxPERSIST_TLW_MAX_X, &r.x) &&
ser.RestoreField(wxPERSIST_TLW_MAX_Y, &r.y) )
if ( store.RestoreValue(wxPERSIST_TLW_MAX_X, &r.x) &&
store.RestoreValue(wxPERSIST_TLW_MAX_Y, &r.y) )
{
m_placement.ptMaxPosition.x = r.x;
m_placement.ptMaxPosition.y = r.y;
+29 -12
View File
@@ -28,12 +28,12 @@
// as maximized/iconized/restore state
// ----------------------------------------------------------------------------
class wxPersistentTLW : public wxPersistentWindow<wxTopLevelWindow>,
private wxTopLevelWindow::GeometrySerializer
class wxPersistentTLW : public wxPersistentWindow<wxTopLevelWindow>
{
public:
wxPersistentTLW(wxTopLevelWindow *tlw)
: wxPersistentWindow<wxTopLevelWindow>(tlw)
: wxPersistentWindow<wxTopLevelWindow>(tlw),
m_store{this}
{
}
@@ -41,28 +41,45 @@ public:
{
const wxTopLevelWindow * const tlw = Get();
tlw->SaveGeometry(*this);
tlw->SaveGeometry(m_store);
}
virtual bool Restore() override
{
wxTopLevelWindow * const tlw = Get();
return tlw->RestoreToGeometry(*this);
return tlw->RestoreToGeometry(m_store);
}
virtual wxString GetKind() const override { return wxASCII_STR(wxPERSIST_TLW_KIND); }
private:
virtual bool SaveField(const wxString& name, int value) const override
class PersistentStore : public wxTopLevelWindow::GeometryStore
{
return SaveValue(name, value);
}
public:
explicit PersistentStore(wxPersistentTLW *pers)
: m_pers(pers)
{
}
virtual bool RestoreField(const wxString& name, int* value) override
{
return RestoreValue(name, value);
}
virtual bool SaveValue(const wxString& name, int value) override
{
return m_pers->SaveValue(name, value);
}
virtual bool RestoreValue(const wxString& name, int* value) const override
{
return m_pers->RestoreValue(name, value);
}
private:
wxPersistentTLW* const m_pers;
};
// This is mutable because we need to be able to call SaveValue() from
// const Save(). It is fine for the object which doesn't have any internal
// state anyhow.
mutable PersistentStore m_store;
};
inline wxPersistentObject *wxCreatePersistentObject(wxTopLevelWindow *tlw)
+17 -17
View File
@@ -27,7 +27,7 @@
class wxTLWGeometryBase
{
public:
typedef wxTopLevelWindow::GeometrySerializer Serializer;
typedef wxTopLevelWindow::GeometryStore Store;
wxTLWGeometryBase() = default;
virtual ~wxTLWGeometryBase() = default;
@@ -40,8 +40,8 @@ public:
// 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;
virtual bool Save(Store& store) const = 0;
virtual bool Restore(const Store& store) = 0;
};
// ----------------------------------------------------------------------------
@@ -71,38 +71,38 @@ public:
m_maximized = false;
}
virtual bool Save(const Serializer& ser) const override
virtual bool Save(Store& store) const override
{
if ( !ser.SaveField(wxPERSIST_TLW_X, m_rectScreen.x) ||
!ser.SaveField(wxPERSIST_TLW_Y, m_rectScreen.y) )
if ( !store.SaveValue(wxPERSIST_TLW_X, m_rectScreen.x) ||
!store.SaveValue(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) )
if ( !store.SaveValue(wxPERSIST_TLW_W, m_rectScreen.width) ||
!store.SaveValue(wxPERSIST_TLW_H, m_rectScreen.height) )
return false;
if ( !ser.SaveField(wxPERSIST_TLW_MAXIMIZED, m_maximized) )
if ( !store.SaveValue(wxPERSIST_TLW_MAXIMIZED, m_maximized) )
return false;
if ( !ser.SaveField(wxPERSIST_TLW_ICONIZED, m_iconized) )
if ( !store.SaveValue(wxPERSIST_TLW_ICONIZED, m_iconized) )
return false;
return true;
}
virtual bool Restore(Serializer& ser) override
virtual bool Restore(const Store& store) override
{
m_hasPos = ser.RestoreField(wxPERSIST_TLW_X, &m_rectScreen.x) &&
ser.RestoreField(wxPERSIST_TLW_Y, &m_rectScreen.y);
m_hasPos = store.RestoreValue(wxPERSIST_TLW_X, &m_rectScreen.x) &&
store.RestoreValue(wxPERSIST_TLW_Y, &m_rectScreen.y);
m_hasSize = ser.RestoreField(wxPERSIST_TLW_W, &m_rectScreen.width) &&
ser.RestoreField(wxPERSIST_TLW_H, &m_rectScreen.height);
m_hasSize = store.RestoreValue(wxPERSIST_TLW_W, &m_rectScreen.width) &&
store.RestoreValue(wxPERSIST_TLW_H, &m_rectScreen.height);
int tmp;
if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) )
if ( store.RestoreValue(wxPERSIST_TLW_MAXIMIZED, &tmp) )
m_maximized = tmp != 0;
if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) )
if ( store.RestoreValue(wxPERSIST_TLW_ICONIZED, &tmp) )
m_iconized = tmp != 0;
// If we restored at least something, return true.
+35 -9
View File
@@ -260,32 +260,58 @@ public:
wxWindow *SetTmpDefaultItem(wxWindow *win);
// Class for saving/restoring fields describing the window geometry.
// Class for saving/restoring values 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
class GeometryStore
{
public:
virtual ~GeometrySerializer() = default;
virtual ~GeometryStore() = default;
// If saving a field returns false, it's fatal error and SaveGeometry()
// If saving a value returns false, it's fatal error and SaveGeometry()
// will return false.
virtual bool SaveField(const wxString& name, int value) const = 0;
virtual bool SaveValue(const wxString& name, int value) = 0;
// If restoring a field returns false, it just means that the field is
// If restoring a value returns false, it just means that the value is
// not present and RestoreToGeometry() still continues with restoring
// the other values.
virtual bool RestoreField(const wxString& name, int* value) = 0;
virtual bool RestoreValue(const wxString& name, int* value) const = 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);
bool SaveGeometry(GeometryStore& store) const;
bool RestoreToGeometry(const GeometryStore& store);
// Deprecated class using wrong const qualifiers for its member functions,
// change your code to use GeometryStore instead and don't use in new code.
class wxDEPRECATED_MSG("Use GeometryStore instead") GeometrySerializer
: public GeometryStore
{
public:
virtual bool SaveValue(const wxString& name, int value) override
{
return SaveField(name, value);
}
virtual bool RestoreValue(const wxString& name, int* value) const override
{
// gcc 4.8 gives a warning for const-cast below.
wxGCC_WARNING_SUPPRESS(deprecated-declarations)
return const_cast<GeometrySerializer*>(this)->RestoreField(name, value);
wxGCC_WARNING_RESTORE(deprecated-declarations)
}
virtual bool SaveField(const wxString& name, int value) const = 0;
virtual bool RestoreField(const wxString& name, int* value) = 0;
};
// implementation only from now on
+11 -11
View File
@@ -408,16 +408,16 @@ public:
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.
derived class implementing the pure virtual SaveValue() and
RestoreValue() 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
@since 3.3.0
*/
class GeometrySerializer
class GeometryStore
{
/**
Save a single field with the given value.
@@ -434,12 +434,12 @@ public:
@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;
virtual bool SaveValue(const wxString& name, int value) = 0;
/**
Try to restore a single field.
Unlike for SaveField(), returning @false from this function may
Unlike for SaveValue(), 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.
@@ -451,7 +451,7 @@ public:
@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;
virtual bool RestoreValue(const wxString& name, int* value) const = 0;
};
/**
@@ -460,7 +460,7 @@ public:
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.
@param ser An object implementing GeometryStore 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
@@ -468,7 +468,7 @@ public:
@since 3.1.2
*/
bool RestoreToGeometry(GeometrySerializer& ser);
bool RestoreToGeometry(const GeometryStore& ser);
/**
Save the current window geometry to allow restoring it later.
@@ -484,13 +484,13 @@ public:
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.
@param ser An object implementing GeometryStore virtual methods.
@return @true if the geometry was saved, @false if doing it failed
@since 3.1.2
*/
bool SaveGeometry(const GeometrySerializer& ser) const;
bool SaveGeometry(GeometryStore& ser) const;
/**
Changes the default item for the panel, usually @a win is a button.
+4 -4
View File
@@ -333,19 +333,19 @@ wxWindow* wxTopLevelWindowBase::SetTmpDefaultItem(wxWindow* win)
// Saving/restoring geometry
// ----------------------------------------------------------------------------
bool wxTopLevelWindowBase::SaveGeometry(const GeometrySerializer& ser) const
bool wxTopLevelWindowBase::SaveGeometry(GeometryStore& store) const
{
wxTLWGeometry geom;
if ( !geom.GetFrom(static_cast<const wxTopLevelWindow*>(this)) )
return false;
return geom.Save(ser);
return geom.Save(store);
}
bool wxTopLevelWindowBase::RestoreToGeometry(GeometrySerializer& ser)
bool wxTopLevelWindowBase::RestoreToGeometry(const GeometryStore& store)
{
wxTLWGeometry geom;
if ( !geom.Restore(ser) )
if ( !geom.Restore(store) )
return false;
return geom.ApplyTo(static_cast<wxTopLevelWindow*>(this));