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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <shlwapi.h>
|
||||
@ -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<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 doesDirectoryExist(const wchar_t* dirPath, 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 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 ((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)
|
||||
RECT rect{ x,y,w,h };
|
||||
bInputDataOk = isWindowVisibleOnAnyMonitor(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bInputDataOk)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user