diff --git a/build/wxExtend.props b/build/wxExtend.props
index cd4b458..77b3d9f 100644
--- a/build/wxExtend.props
+++ b/build/wxExtend.props
@@ -26,6 +26,7 @@
Create
+
@@ -40,7 +41,8 @@
-
+
+
diff --git a/build/wxExtendDll-10.0.vcxproj.filters b/build/wxExtendDll-10.0.vcxproj.filters
index 3b17acd..1ac4ea9 100644
--- a/build/wxExtendDll-10.0.vcxproj.filters
+++ b/build/wxExtendDll-10.0.vcxproj.filters
@@ -23,6 +23,9 @@
{be99b1e7-e013-4c69-8966-6b34932a1711}
+
+ {e7ddefe0-5d58-4fda-943c-717689ad974c}
+
@@ -55,6 +58,9 @@
Source Files
+
+ Source Files
+
@@ -81,21 +87,30 @@
Header Files\persist
-
- Header Files\persist
-
Header Files
Header Files
+
+ Header Files
+
Header Files
Header Files\aui
+
+ Header Files
+
+
+ Header Files\private
+
+
+ Header Files\persist
+
diff --git a/build/wxExtendDll-15.0.vcxproj.filters b/build/wxExtendDll-15.0.vcxproj.filters
index 1f92ab5..23c82e6 100644
--- a/build/wxExtendDll-15.0.vcxproj.filters
+++ b/build/wxExtendDll-15.0.vcxproj.filters
@@ -23,6 +23,9 @@
{be99b1e7-e013-4c69-8966-6b34932a1711}
+
+ {e7ddefe0-5d58-4fda-943c-717689ad974c}
+
@@ -55,6 +58,9 @@
Source Files
+
+ Source Files
+
@@ -81,15 +87,15 @@
Header Files\persist
-
- Header Files\persist
-
Header Files
Header Files
+
+ Header Files
+
Header Files
@@ -99,6 +105,12 @@
Header Files
+
+ Header Files\private
+
+
+ Header Files\persist
+
diff --git a/build/wxExtendLib-10.0.vcxproj.filters b/build/wxExtendLib-10.0.vcxproj.filters
index 0971bbd..c345585 100644
--- a/build/wxExtendLib-10.0.vcxproj.filters
+++ b/build/wxExtendLib-10.0.vcxproj.filters
@@ -20,6 +20,12 @@
{33d4709f-47d3-42c1-9562-bc4743799b49}
+
+ {be99b1e7-e013-4c69-8966-6b34932a1711}
+
+
+ {e7ddefe0-5d58-4fda-943c-717689ad974c}
+
@@ -52,6 +58,9 @@
Source Files
+
+ Source Files
+
@@ -78,9 +87,6 @@
Header Files\persist
-
- Header Files\persist
-
Header Files
@@ -93,6 +99,18 @@
Header Files
+
+ Header Files\aui
+
+
+ Header Files
+
+
+ Header Files\private
+
+
+ Header Files\persist
+
@@ -188,9 +206,4 @@
Resource Files\Localization
-
-
- Resource Files
-
-
\ No newline at end of file
diff --git a/build/wxExtendLib-15.0.vcxproj.filters b/build/wxExtendLib-15.0.vcxproj.filters
index ff50048..8a6dd33 100644
--- a/build/wxExtendLib-15.0.vcxproj.filters
+++ b/build/wxExtendLib-15.0.vcxproj.filters
@@ -20,6 +20,12 @@
{33d4709f-47d3-42c1-9562-bc4743799b49}
+
+ {be99b1e7-e013-4c69-8966-6b34932a1711}
+
+
+ {e7ddefe0-5d58-4fda-943c-717689ad974c}
+
@@ -52,6 +58,9 @@
Source Files
+
+ Source Files
+
@@ -78,9 +87,6 @@
Header Files\persist
-
- Header Files\persist
-
Header Files
@@ -94,8 +100,17 @@
Header Files
+ Header Files\aui
+
+
Header Files
+
+ Header Files\private
+
+
+ Header Files\persist
+
diff --git a/include/wxex/persist/dialog.h b/include/wxex/persist/toplevel.h
similarity index 61%
rename from include/wxex/persist/dialog.h
rename to include/wxex/persist/toplevel.h
index aabb4d9..da7da08 100644
--- a/include/wxex/persist/dialog.h
+++ b/include/wxex/persist/toplevel.h
@@ -1,106 +1,98 @@
-/*
- Copyright 2015-2018 Amebis
- Copyright 2016 GÉANT
-
- This file is part of wxExtend.
-
- wxExtend is free software: you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- wxExtend is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with wxExtend. If not, see .
-*/
-
-#pragma once
-
-#include "../common.h"
-
-#include
-#include
-#include
-#include
-
-/// \addtogroup wxExtend
-/// @{
-
-///
-/// `wxPersistentDialog` kind for persistent storage
-///
-#define wxPERSIST_DIALOG_KIND "Dialog"
-
-///
-/// Supports saving/restoring wxDialog state
-///
-class wxPersistentDialog :
- public wxPersistentWindow,
- private wxTopLevelWindow::GeometrySerializer
-{
-public:
- ///
- /// Constructs a persistent dialog object
- ///
- wxPersistentDialog(wxDialog *mgr) : wxPersistentWindow(mgr)
- {
- }
-
- ///
- /// \returns `wxT(wxPERSIST_DIALOG_KIND)`
- ///
- virtual wxString GetKind() const wxOVERRIDE
- {
- return wxT(wxPERSIST_DIALOG_KIND);
- }
-
- ///
- /// Saves dialog state
- ///
- virtual void Save() const wxOVERRIDE
- {
- const wxDialog * const wnd = Get();
-
- // Code copied from wxPersistentTLW::Save()
- wnd->SaveGeometry(*this);
- }
-
- ///
- /// Restores dialog state
- ///
- virtual bool Restore() wxOVERRIDE
- {
- wxDialog * const wnd = Get();
-
- return wnd->RestoreToGeometry(*this);
- }
-
-private:
- wxDECLARE_NO_COPY_CLASS(wxPersistentDialog);
-
-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);
- }
-};
-
-
-///
-/// wxDialog's instantiation of wxCreatePersistentObject template
-///
-inline wxPersistentObject *wxCreatePersistentObject(wxDialog *mgr)
-{
- return new wxPersistentDialog(mgr);
-}
-
-/// @}
+/*
+ Copyright 2015-2018 Amebis
+ Copyright 2016 GÉANT
+
+ This file is part of wxExtend.
+
+ wxExtend is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ wxExtend is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wxExtend. If not, see .
+*/
+
+#pragma once
+
+#include "../common.h"
+#include "../private/tlwgeom.h"
+
+#include
+#include
+#include
+#include
+
+/// \addtogroup wxExtend
+/// @{
+
+///
+/// Supports saving/restoring wxTopLevelWindow state
+///
+class wxPersistentTLWEx :
+ public wxPersistentWindow,
+ private wxTopLevelWindow::GeometrySerializer
+{
+public:
+ ///
+ /// Constructs a persistent dialog object
+ ///
+ wxPersistentTLWEx(wxTopLevelWindow *mgr) : wxPersistentWindow(mgr)
+ {
+ }
+
+ ///
+ /// \returns `wxT(wxPERSIST_TLW_KIND)`
+ ///
+ virtual wxString GetKind() const wxOVERRIDE
+ {
+ return wxT(wxPERSIST_TLW_KIND);
+ }
+
+ ///
+ /// Saves dialog state
+ ///
+ virtual void Save() const wxOVERRIDE
+ {
+ const wxTopLevelWindow * const wnd = Get();
+
+ wxTLWGeometryEx geom;
+ if (geom.GetFrom(wnd))
+ geom.Save(*this);
+ }
+
+ ///
+ /// Restores dialog state
+ ///
+ virtual bool Restore() wxOVERRIDE
+ {
+ wxTopLevelWindow * const wnd = Get();
+
+ wxTLWGeometryEx geom;
+ if (!geom.Restore(*this))
+ return false;
+
+ return geom.ApplyTo(wnd);
+ }
+
+private:
+ wxDECLARE_NO_COPY_CLASS(wxPersistentTLWEx);
+
+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);
+ }
+};
+
+/// @}
diff --git a/include/wxex/private/tlwgeom.h b/include/wxex/private/tlwgeom.h
new file mode 100644
index 0000000..9b325f6
--- /dev/null
+++ b/include/wxex/private/tlwgeom.h
@@ -0,0 +1,346 @@
+/*
+ Copyright 2015-2018 Amebis
+ Copyright 2016 GÉANT
+
+ This file is part of wxExtend.
+
+ wxExtend is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ wxExtend is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wxExtend. If not, see .
+*/
+
+#pragma once
+
+#include
+#include
+
+#ifndef USER_DEFAULT_SCREEN_DPI
+#define USER_DEFAULT_SCREEN_DPI 96
+#endif
+
+/// \addtogroup wxExtend
+/// @{
+
+///
+/// `wxPersistentDialog` kind for persistent storage
+///
+#define wxPERSIST_TLW_MONITOR_X "xmon"
+#define wxPERSIST_TLW_MONITOR_Y "ymon"
+#define wxPERSIST_TLW_MONITOR_W "wmon"
+#define wxPERSIST_TLW_MONITOR_H "hmon"
+#define wxPERSIST_TLW_DPI_HORZ "xdpi"
+#define wxPERSIST_TLW_DPI_VERT "ydpi"
+
+
+class wxTLWGeometryEx : public wxTLWGeometryBase
+{
+public:
+ wxTLWGeometryEx()
+ {
+ wxZeroMemory(m_placement);
+ m_placement.length = sizeof(m_placement);
+
+ wxZeroMemory(m_mntinfo);
+ m_mntinfo.cbSize = sizeof(m_mntinfo);
+
+ m_dpiHorz = USER_DEFAULT_SCREEN_DPI;
+ m_dpiVert = USER_DEFAULT_SCREEN_DPI;
+ }
+
+ 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) ||
+ !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.
+
+ // Monitor position and size.
+ const RECT& rcMon = m_mntinfo.rcWork;
+ if (!ser.SaveField(wxPERSIST_TLW_MONITOR_X, rcMon.left) ||
+ !ser.SaveField(wxPERSIST_TLW_MONITOR_Y, rcMon.top) ||
+ !ser.SaveField(wxPERSIST_TLW_MONITOR_W, rcMon.right - rcMon.left) ||
+ !ser.SaveField(wxPERSIST_TLW_MONITOR_H, rcMon.bottom - rcMon.top))
+ return false;
+
+ // DPI.
+ if (!ser.SaveField(wxPERSIST_TLW_DPI_HORZ, m_dpiHorz) ||
+ !ser.SaveField(wxPERSIST_TLW_DPI_VERT, m_dpiVert))
+ return false;
+
+ 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.
+ //
+ // 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;
+ UINT& show = m_placement.showCmd;
+ if (ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp)
+ show = SW_MAXIMIZE;
+ else if (ser.RestoreField(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))
+ {
+ m_placement.ptMaxPosition.x = r.x;
+ m_placement.ptMaxPosition.y = r.y;
+ } else {
+ m_placement.ptMaxPosition.x = -1;
+ m_placement.ptMaxPosition.y = -1;
+ }
+
+ m_placement.ptMinPosition.x = -1;
+ m_placement.ptMinPosition.y = -1;
+
+ // Monitor position and size.
+ wxRect rmon;
+ if (!ser.RestoreField(wxPERSIST_TLW_MONITOR_X, &rmon.x) ||
+ !ser.RestoreField(wxPERSIST_TLW_MONITOR_Y, &rmon.y) ||
+ !ser.RestoreField(wxPERSIST_TLW_MONITOR_W, &rmon.width) ||
+ !ser.RestoreField(wxPERSIST_TLW_MONITOR_H, &rmon.height))
+ return false;
+ wxCopyRectToRECT(rmon, m_mntinfo.rcWork);
+
+ // DPI.
+ if (!ser.RestoreField(wxPERSIST_TLW_DPI_HORZ, &r.x) ||
+ !ser.RestoreField(wxPERSIST_TLW_DPI_VERT, &r.y))
+ return false;
+ m_dpiHorz = r.x;
+ m_dpiVert = r.y;
+
+ return true;
+ }
+
+ virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE
+ {
+ WXHWND hWnd = GetHwndOf(tlw);
+ if (!::GetWindowPlacement(hWnd, &m_placement))
+ {
+ wxLogLastError(wxS("GetWindowPlacement"));
+ return false;
+ }
+
+ HMONITOR hMonitor = ::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
+ wxASSERT_MSG(hMonitor, wxT("error locating monitor"));
+ if (!::GetMonitorInfo(hMonitor, &m_mntinfo))
+ {
+ wxLogLastError(wxS("GetMonitorInfo"));
+ return false;
+ }
+
+ GetDPI(hWnd, &m_dpiHorz, &m_dpiVert) || GetDPI(hMonitor, &m_dpiHorz, &m_dpiVert);
+
+ return true;
+ }
+
+ 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;
+ }
+
+ // Get monitor to restore window to.
+ HMONITOR hMonitor = ::MonitorFromRect(&m_mntinfo.rcWork, MONITOR_DEFAULTTONEAREST);
+ wxASSERT_MSG(hMonitor, wxT("error locating monitor"));
+ MONITORINFO mntinfo;
+ mntinfo.cbSize = sizeof(mntinfo);
+ if (!::GetMonitorInfo(hMonitor, &mntinfo))
+ {
+ wxLogLastError(wxS("GetMonitorInfo"));
+ return false;
+ }
+
+ UINT dpiHorz, dpiVert;
+ GetDPI(hMonitor, &dpiHorz, &dpiVert);
+
+ SIZE
+ sizeWorkPrev = {
+ m_mntinfo.rcWork.right - m_mntinfo.rcWork.left,
+ m_mntinfo.rcWork.bottom - m_mntinfo.rcWork.top
+ },
+ sizeWork = {
+ mntinfo.rcWork.right - mntinfo.rcWork.left,
+ mntinfo.rcWork.bottom - mntinfo.rcWork.top
+ };
+
+ //
+ // Project the coordinates:
+ // - Position relative to monitor working area center.
+ // - Scale according to DPI.
+ //
+
+ if (m_placement.ptMaxPosition.x != -1 && m_placement.ptMaxPosition.y != -1) {
+ m_placement.ptMaxPosition.x = wxMulDivInt32(m_placement.ptMaxPosition.x - m_mntinfo.rcWork.left, sizeWork.cx, sizeWorkPrev.cx) + mntinfo.rcWork.left;
+ m_placement.ptMaxPosition.y = wxMulDivInt32(m_placement.ptMaxPosition.y - m_mntinfo.rcWork.top, sizeWork.cy, sizeWorkPrev.cy) + mntinfo.rcWork.top;
+ }
+
+ SIZE sizeWndPrev, sizeWnd;
+ HWND hWnd = GetHwndOf(tlw);
+
+ if (tlw->GetWindowStyle() & wxRESIZE_BORDER) {
+ sizeWndPrev.cx = m_placement.rcNormalPosition.right - m_placement.rcNormalPosition.left;
+ sizeWndPrev.cy = m_placement.rcNormalPosition.bottom - m_placement.rcNormalPosition.top;
+ sizeWnd.cx = wxMulDivInt32(sizeWndPrev.cx, dpiHorz, m_dpiHorz);
+ sizeWnd.cy = wxMulDivInt32(sizeWndPrev.cy, dpiVert, m_dpiVert);
+ } else {
+ // The window is not resizable. Do not change its size.
+ WINDOWPLACEMENT placement = { sizeof(placement) };
+ if (!::GetWindowPlacement(hWnd, &placement))
+ {
+ wxLogLastError(wxS("GetWindowPlacement"));
+ return false;
+ }
+ SIZE size = {
+ placement.rcNormalPosition.right - placement.rcNormalPosition.left,
+ placement.rcNormalPosition.bottom - placement.rcNormalPosition.top
+ };
+
+ UINT dpiWndHorz, dpiWndVert;
+ GetDPI(hWnd, &dpiWndHorz, &dpiWndVert) || GetDPI(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &dpiWndHorz, &dpiWndVert);
+
+ sizeWndPrev.cx = wxMulDivInt32(size.cx, m_dpiHorz, dpiWndHorz);
+ sizeWndPrev.cy = wxMulDivInt32(size.cy, m_dpiVert, dpiWndVert);
+ sizeWnd.cx = wxMulDivInt32(size.cx, dpiHorz, dpiWndHorz);
+ sizeWnd.cy = wxMulDivInt32(size.cy, dpiVert, dpiWndVert);
+ }
+
+ m_placement.rcNormalPosition.left = wxMulDivInt32(m_placement.rcNormalPosition.left + sizeWndPrev.cx / 2 - m_mntinfo.rcWork.left, sizeWork.cx, sizeWorkPrev.cx) + mntinfo.rcWork.left - sizeWnd.cx / 2;
+ m_placement.rcNormalPosition.top = wxMulDivInt32(m_placement.rcNormalPosition.top + sizeWndPrev.cy / 2 - m_mntinfo.rcWork.top, sizeWork.cy, sizeWorkPrev.cy) + mntinfo.rcWork.top - sizeWnd.cy / 2;
+ m_placement.rcNormalPosition.right = m_placement.rcNormalPosition.left + sizeWnd.cx;
+ m_placement.rcNormalPosition.bottom = m_placement.rcNormalPosition.top + sizeWnd.cy;
+
+ if (!::SetWindowPlacement(hWnd, &m_placement))
+ {
+ wxLogLastError(wxS("SetWindowPlacement"));
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ static bool GetDPI(HWND hWnd, UINT *dpiHorz, UINT *dpiVert)
+ {
+ wxASSERT(dpiHorz);
+ wxASSERT(dpiVert);
+
+#if wxUSE_DYNLIB_CLASS
+ typedef HRESULT(WINAPI *GetDpiForWindow_t)(HWND);
+ static GetDpiForWindow_t s_pfnGetDpiForWindow = NULL;
+ if (!s_pfnGetDpiForWindow && s_dllUser32.IsLoaded())
+ s_pfnGetDpiForWindow = (GetDpiForWindow_t)s_dllUser32.GetSymbol(wxT("GetDpiForWindow"));
+
+ if (s_pfnGetDpiForWindow) {
+ *dpiHorz = *dpiVert = s_pfnGetDpiForWindow(hWnd);
+ return true;
+ }
+#endif
+
+ *dpiHorz = *dpiVert = USER_DEFAULT_SCREEN_DPI;
+ return false;
+ }
+
+ static bool GetDPI(HMONITOR hMonitor, UINT *dpiHorz, UINT *dpiVert)
+ {
+ wxASSERT(dpiHorz);
+ wxASSERT(dpiVert);
+
+#if wxUSE_DYNLIB_CLASS
+ enum MONITOR_DPI_TYPE {
+ MDT_EFFECTIVE_DPI = 0,
+ MDT_ANGULAR_DPI = 1,
+ MDT_RAW_DPI = 2,
+ MDT_DEFAULT = MDT_EFFECTIVE_DPI
+ };
+ typedef HRESULT(WINAPI *GetDpiForMonitor_t)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *);
+ static GetDpiForMonitor_t s_pfnGetDpiForMonitor = NULL;
+ if (!s_pfnGetDpiForMonitor) {
+ if (s_dllShCore.IsLoaded())
+ s_pfnGetDpiForMonitor = (GetDpiForMonitor_t)s_dllShCore.GetSymbol(wxT("GetDpiForMonitor"));
+ }
+
+ if (s_pfnGetDpiForMonitor) {
+ s_pfnGetDpiForMonitor(hMonitor, MDT_DEFAULT, dpiHorz, dpiVert);
+ return true;
+ }
+#endif
+
+ *dpiHorz = *dpiVert = USER_DEFAULT_SCREEN_DPI;
+ return false;
+ }
+
+private:
+ WINDOWPLACEMENT m_placement;
+ MONITORINFO m_mntinfo;
+ UINT m_dpiHorz;
+ UINT m_dpiVert;
+
+#if wxUSE_DYNLIB_CLASS
+ static wxDynamicLibrary s_dllUser32;
+ static wxDynamicLibrary s_dllShCore;
+#endif
+};
diff --git a/src/stdafx.h b/src/stdafx.h
index df826ea..902ab00 100644
--- a/src/stdafx.h
+++ b/src/stdafx.h
@@ -26,6 +26,9 @@
#include "../include/wxex/aui/framemanager.h"
+#include "../include/wxex/persist/auimanager.h"
+#include "../include/wxex/persist/toplevel.h"
+
#include "../include/wxex/appbar.h"
#include "../include/wxex/comutils.h"
#include "../include/wxex/crypto.h"
@@ -37,3 +40,5 @@
#include "../include/wxex/xml.h"
#include "../include/wxex/common.h"
+
+#include "../include/wxex/private/tlwgeom.h"
diff --git a/src/tlwgeom.cpp b/src/tlwgeom.cpp
new file mode 100644
index 0000000..5567b0c
--- /dev/null
+++ b/src/tlwgeom.cpp
@@ -0,0 +1,28 @@
+/*
+ Copyright 2015-2018 Amebis
+ Copyright 2016 GÉANT
+ Based on code written by Jeffrey Richter.
+
+ This file is part of wxExtend.
+
+ wxExtend is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ wxExtend is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wxExtend. If not, see .
+*/
+
+#include "stdafx.h"
+
+
+#if wxUSE_DYNLIB_CLASS
+wxDynamicLibrary wxTLWGeometryEx::s_dllUser32(wxT("user32.dll"));
+wxDynamicLibrary wxTLWGeometryEx::s_dllShCore(wxT("shcore.dll"));
+#endif