diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp
index 625249148..9ab45d9e3 100644
--- a/PowerEditor/src/MISC/Common/Common.cpp
+++ b/PowerEditor/src/MISC/Common/Common.cpp
@@ -13,6 +13,7 @@
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+#include
#include
#include
#include
@@ -1903,3 +1904,56 @@ bool doesPathExist(const wchar_t* path, DWORD milliSec2wait, bool* isTimeoutReac
getFileAttributesExWithTimeout(path, &attributes, milliSec2wait, isTimeoutReached);
return (attributes.dwFileAttributes != INVALID_FILE_ATTRIBUTES);
}
+
+#if defined(__GNUC__)
+#define LAMBDA_STDCALL __attribute__((__stdcall__))
+#else
+#define LAMBDA_STDCALL
+#endif
+
+// check if the window rectangle intersects with any currently active monitor's working area
+// (this func handles also possible extended monitors mode aka the MS Virtual Screen)
+bool isWindowVisibleOnAnyMonitor(const RECT& rectWndIn)
+{
+ struct Param4InOut
+ {
+ const RECT& rectWndIn;
+ bool isWndVisibleOut = false;
+ };
+
+ // callback func to check for intersection with each existing monitor
+ auto callback = []([[maybe_unused]] HMONITOR hMon, [[maybe_unused]] HDC hdc, LPRECT lprcMon, LPARAM lpInOut) -> BOOL LAMBDA_STDCALL
+ {
+ Param4InOut* paramInOut = reinterpret_cast(lpInOut);
+ RECT rectIntersection{};
+ if (::IntersectRect(&rectIntersection, &(paramInOut->rectWndIn), lprcMon))
+ {
+ paramInOut->isWndVisibleOut = true; // the window is at least partially visible on this monitor
+ return FALSE; // ok, stop the enumeration
+ }
+ return TRUE; // continue enumeration as no intersection yet
+ };
+
+ // get scaled Virtual Screen size (scaled coordinates are saved by the Notepad++ into config.xml)
+ // - for unscaled, one has to 1st set the SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) & then use GetSystemMetricsForDpi with 96
+ // - for getting the VS RECT, we cannot use here the SystemParametersInfo with SPI_GETWORKAREA!
+ // (while the SPI_SETWORKAREA is working with the VS coordinates the SPI_GETWORKAREA not...)
+ RECT rectVirtualScreen{ ::GetSystemMetrics(SM_XVIRTUALSCREEN), ::GetSystemMetrics(SM_YVIRTUALSCREEN),
+ ::GetSystemMetrics(SM_CXVIRTUALSCREEN), ::GetSystemMetrics(SM_CYVIRTUALSCREEN) };
+
+ // 1) Before checking for intersections with individual monitors, we verify if the window's rectangle
+ // is within the MS Virtual Screen area. If it is outside, this func exits with false early,
+ // as the window in question cannot be visible on any individual monitor present.
+ RECT rectIntersection{};
+ if (!::IntersectRect(&rectIntersection, &rectWndIn, &rectVirtualScreen))
+ {
+ // the window in question is completely outside the overall Virtual Screen bounds
+ return false;
+ }
+
+ // 2) Using the EnumDisplayMonitors WINAPI to check each present monitor's visible area, we ensure that we are only looking
+ // at monitors that are part of the Virtual Screen but not at Virtual Space coordinates where is NOT a monitor present.
+ Param4InOut param4InOut{ rectWndIn, false };
+ ::EnumDisplayMonitors(NULL, &rectVirtualScreen, callback, reinterpret_cast(¶m4InOut));
+ return param4InOut.isWndVisibleOut;
+}
diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h
index 3d3548030..9ad19654c 100644
--- a/PowerEditor/src/MISC/Common/Common.h
+++ b/PowerEditor/src/MISC/Common/Common.h
@@ -287,4 +287,8 @@ BOOL getFileAttributesExWithTimeout(const wchar_t* filePath, WIN32_FILE_ATTRIBUT
bool doesFileExist(const wchar_t* filePath, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
bool doesDirectoryExist(const wchar_t* dirPath, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
-bool doesPathExist(const wchar_t* path, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
\ No newline at end of file
+bool doesPathExist(const wchar_t* path, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
+
+
+// check if the window rectangle intersects with any currently active monitor's working area
+bool isWindowVisibleOnAnyMonitor(const RECT& rectWndIn);
diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp
index 91bed4c82..aa32cdce3 100644
--- a/PowerEditor/src/Parameters.cpp
+++ b/PowerEditor/src/Parameters.cpp
@@ -6910,40 +6910,32 @@ void NppParameters::feedDockingManager(TiXmlNode *node)
int w = FWI_PANEL_WH_DEFAULT;
int h = FWI_PANEL_WH_DEFAULT;
+ bool bInputDataOk = false;
if (floatElement->Attribute(L"x", &x))
{
- if ((x > (maxMonitorSize.cx - 1)) || (x < 0))
- x = 0; // invalid, reset
+ if (floatElement->Attribute(L"y", &y))
+ {
+ if (floatElement->Attribute(L"width", &w))
+ {
+ if (floatElement->Attribute(L"height", &h))
+ {
+ RECT rect{ x,y,w,h };
+ bInputDataOk = isWindowVisibleOnAnyMonitor(rect);
+ }
+ }
+ }
}
- if (floatElement->Attribute(L"y", &y))
+
+ if (!bInputDataOk)
{
- if ((y > (maxMonitorSize.cy - 1)) || (y < 0))
- y = 0; // invalid, reset
- }
- if (floatElement->Attribute(L"width", &w))
- {
- if (w > maxMonitorSize.cx)
- {
- w = maxMonitorSize.cx; // invalid, reset
- }
- else
- {
- if (w < _nppGUI._dockingData._minFloatingPanelSize.cx)
- w = _nppGUI._dockingData._minFloatingPanelSize.cx; // invalid, reset
- }
- }
- if (floatElement->Attribute(L"height", &h))
- {
- if (h > maxMonitorSize.cy)
- {
- h = maxMonitorSize.cy; // invalid, reset
- }
- else
- {
- if (h < _nppGUI._dockingData._minFloatingPanelSize.cy)
- h = _nppGUI._dockingData._minFloatingPanelSize.cy; // invalid, reset
- }
+ // reset to adjusted factory defaults
+ // (and the panel will automatically be on the current primary monitor due to the x,y == 0,0)
+ x = 0;
+ y = 0;
+ w = _nppGUI._dockingData._minFloatingPanelSize.cx;
+ h = _nppGUI._dockingData._minFloatingPanelSize.cy + FWI_PANEL_WH_DEFAULT;
}
+
_nppGUI._dockingData._floatingWindowInfo.push_back(FloatingWindowInfo(cont, x, y, w, h));
}
}