mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-27 07:44:24 +02:00
Fix floating panels position resetting in multimon extended mode
This fixes a regression caused by PR #15236 (Fix for the "lost" panels problem). As the Virtual Screen in the extended multi-monitor mode can start not a the point 0,0 (as the primary monitor does) but also at some negative coordinates, we have to deal with it. The MS Virtual Screen concept ref: https://learn.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen Fix #15498 , fix #16077, close #16079
This commit is contained in:
parent
6dfbc1f7e8
commit
b09b89799b
@ -13,6 +13,7 @@
|
|||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
#include <windows.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
@ -1903,3 +1904,56 @@ bool doesPathExist(const wchar_t* path, DWORD milliSec2wait, bool* isTimeoutReac
|
|||||||
getFileAttributesExWithTimeout(path, &attributes, milliSec2wait, isTimeoutReached);
|
getFileAttributesExWithTimeout(path, &attributes, milliSec2wait, isTimeoutReached);
|
||||||
return (attributes.dwFileAttributes != INVALID_FILE_ATTRIBUTES);
|
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<Param4InOut*>(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<LPARAM>(¶m4InOut));
|
||||||
|
return param4InOut.isWndVisibleOut;
|
||||||
|
}
|
||||||
|
@ -288,3 +288,7 @@ BOOL getFileAttributesExWithTimeout(const wchar_t* filePath, WIN32_FILE_ATTRIBUT
|
|||||||
bool doesFileExist(const wchar_t* filePath, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
|
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 doesDirectoryExist(const wchar_t* dirPath, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
|
||||||
bool doesPathExist(const wchar_t* path, DWORD milliSec2wait = 0, bool* isTimeoutReached = nullptr);
|
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);
|
||||||
|
@ -6910,40 +6910,32 @@ void NppParameters::feedDockingManager(TiXmlNode *node)
|
|||||||
int w = FWI_PANEL_WH_DEFAULT;
|
int w = FWI_PANEL_WH_DEFAULT;
|
||||||
int h = FWI_PANEL_WH_DEFAULT;
|
int h = FWI_PANEL_WH_DEFAULT;
|
||||||
|
|
||||||
|
bool bInputDataOk = false;
|
||||||
if (floatElement->Attribute(L"x", &x))
|
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"y", &y))
|
||||||
{
|
{
|
||||||
if ((y > (maxMonitorSize.cy - 1)) || (y < 0))
|
|
||||||
y = 0; // invalid, reset
|
|
||||||
}
|
|
||||||
if (floatElement->Attribute(L"width", &w))
|
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 (floatElement->Attribute(L"height", &h))
|
||||||
{
|
{
|
||||||
if (h > maxMonitorSize.cy)
|
RECT rect{ x,y,w,h };
|
||||||
|
bInputDataOk = isWindowVisibleOnAnyMonitor(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bInputDataOk)
|
||||||
{
|
{
|
||||||
h = maxMonitorSize.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)
|
||||||
else
|
x = 0;
|
||||||
{
|
y = 0;
|
||||||
if (h < _nppGUI._dockingData._minFloatingPanelSize.cy)
|
w = _nppGUI._dockingData._minFloatingPanelSize.cx;
|
||||||
h = _nppGUI._dockingData._minFloatingPanelSize.cy; // invalid, reset
|
h = _nppGUI._dockingData._minFloatingPanelSize.cy + FWI_PANEL_WH_DEFAULT;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_nppGUI._dockingData._floatingWindowInfo.push_back(FloatingWindowInfo(cont, x, y, w, h));
|
_nppGUI._dockingData._floatingWindowInfo.push_back(FloatingWindowInfo(cont, x, y, w, h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user