-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DPI Awareness Support #1386
Comments
I just checked |
I fixed this case by using GetShellWindow() with GetDpiForWindow().
We can use GetShellWindow()+GetDpiForWindow or GetScaleFactorForMonitor (with or without GetShellWindow) GetScaleFactorForMonitor returns the correct DPI for the monitor but not sure if it should use GetShellWindow or just NULL?
|
From here:
System Informer now is under DPI_AWARENESS_PER_MONITOR_AWARE. |
It works for me and GetScaleFactorForMonitor changes at runtime when changing the display properties. He might be right about the UWP aspect.... The IDisplayPropertiesStatics_get_ResolutionScale method returns the correct scaling at 150% and so does the DPI. Can you compile this and compare the output?
|
100 dpi:
125 dpi:
Looks like it returns correct results, but Again, |
Here is working binary with PerMonitorv2 enabled. On start waiting 2 seconds. Just move cursor to monitor to display it's DPI. |
The documentation says it's not V2 aware?
|
This comment was marked as off-topic.
This comment was marked as off-topic.
It exactly says And how Where is here "not PerMonitor aware": As you can see, official documentation is contradicts itself. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Are we able to eliminate DPI from application settings? PhLoadWindowPlacementFromSetting/PhSaveWindowPlacementToSetting for example are both saving the DPI but this should be redundant. Application settings should be changed to logical units which don't require persisting DPI and then we convert to physical units at runtime so those settings are portable across all machines? For example:
|
Already! PhGetSizeDpiValue is used to avoid saving dpi value in configuration, how it works you can see in layout manager, saving the packed size value and on resizing unpack it's size to current dpi value and doing the job. It can be implemented in But, i think some changes is required for |
We're still saving the DPI and scaling on startup? There's some weird issue where hidden treelist window columns are incorrectly scaled when their window is hidden and starting/closing/restarting the application with different DPI values: systeminformer/phlib/settings.c Lines 381 to 389 in 16f717c
And here: systeminformer/phlib/settings.c Lines 1102 to 1103 in 16f717c
Although it's probably caused by GetDpiForSystem returning the wrong DPI until the application is restarted?
The enums/values returned by winrt can be used with muldiv by casting those values to float. I'm looking for alternatives to GetDpiForSystem since it has a major problem when you change the scaling at runtime from the display properties. If the current display properties are using 100% then GetDpiForSystem returns 96 but continues returning 96 even after changing the scaling and doesn't update unless you restart the application. GetDpiForWindow will instantly return the newer scaling but parts of the application (i.e settings) using GetDpiForSystem end up saving the 96 DPI but the application is using 120 DPI and with RECTs from 120 - When you restart the application it sees 96 != 120 and scales those values but they were already scaled for 120.
You can call this in a loop and see GetDpiForSystem return the wrong values: VOID PrintDPI(VOID)
{
static PH_INITONCE initOnce = PH_INITONCE_INIT;
static HRESULT (WINAPI *GetDpiForMonitor_I)(
_In_ HMONITOR hmonitor,
_In_ MONITOR_DPI_TYPE dpiType,
_Out_ PUINT dpiX,
_Out_ PUINT dpiY
) = NULL; // win81+
static UINT (WINAPI *GetDpiForWindow_I)(
_In_ HWND hwnd
) = NULL; // win10rs1+
static UINT (WINAPI *GetDpiForSystem_I)(
VOID
) = NULL; // win10rs1+
static UINT (WINAPI *GetDpiForSession_I)(
VOID
) = NULL; // ordinal 2713
if (PhBeginInitOnce(&initOnce))
{
PVOID baseAddress;
if (!(baseAddress = PhGetLoaderEntryDllBase(L"shcore.dll")))
baseAddress = PhLoadLibrary(L"shcore.dll");
if (baseAddress)
{
GetDpiForMonitor_I = PhGetProcedureAddress(baseAddress, "GetDpiForMonitor", 0);
}
if (!(baseAddress = PhGetLoaderEntryDllBase(L"user32.dll")))
baseAddress = PhLoadLibrary(L"user32.dll");
if (baseAddress)
{
GetDpiForWindow_I = PhGetProcedureAddress(baseAddress, "GetDpiForWindow", 0);
GetDpiForSystem_I = PhGetProcedureAddress(baseAddress, "GetDpiForSystem", 0);
}
PhEndInitOnce(&initOnce);
}
UINT systemDpi = 0;
UINT shellWindowDpi = 0;
UINT monitorWindowDpi = 0;
UINT monitorRectWindowDpi = 0;
UINT deviceCapsDpi = 0;
{
systemDpi = GetDpiForSystem_I();
shellWindowDpi = GetDpiForWindow_I(GetShellWindow());
}
{
UINT dpi_x;
UINT dpi_y;
GetDpiForMonitor_I(MonitorFromWindow(GetShellWindow(), MONITOR_DEFAULTTONEAREST), MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
monitorWindowDpi = dpi_x;
}
{
UINT dpi_x;
UINT dpi_y;
GetDpiForMonitor_I(MonitorFromRect(&(RECT){ 1, 1, 1, 1 }, MONITOR_DEFAULTTONEAREST), MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
monitorRectWindowDpi = dpi_x;
}
{
HDC screenHdc;
if (screenHdc = GetDC(NULL))
{
deviceCapsDpi = GetDeviceCaps(screenHdc, LOGPIXELSX);
ReleaseDC(NULL, screenHdc);
}
}
dprintf("System: %lu, Window: %lu, Monitor: %lu, Monitor2: %lu, DeviceCaps: %lu\n", systemDpi, shellWindowDpi, monitorWindowDpi, monitorRectWindowDpi, deviceCapsDpi);
} BTW the above code with IDisplayInformationStatics wasn't working because the runtime wasn't initialized. IDisplayProperties is deprecated and probably doesn't return the correct values. This code should work:
|
All the remaining DPI issues have been fixed and support now includes the application and plugins. Are you able to try out the latest nightly and let me know if there's any remaining DPI issues? On a separate topic I've also found a major Windows 11 bug with the CreateDialog API and PerMonitorV2... If the user minimizes windows/dialogs that were created using the CreateDialog API and then changes the DPI settings for the display while the window is minimized the internal state of the window becomes deadlocked/corrupted. The message loop immediately stops processing messages, various window functions return incorrect data and if you attempt to active the window it'll trip the message loop then resize to 0,0 and become unusable. I'm not sure if we can workaround the issue with CreateDialog by just changing some window styles? |
I have and they marked it "needs more details" 🤦 |
What about scaling columns sizes depending on DPI? On 100% display the sizes can be larger compared to displays with for example 125%. When moving the Main Window between such 2 displays I have to change the sizes each time. |
@MagicAndre1981 in my project haved listview resize on dpi change, do not know how it realized here. |
nice, maybe create a PR to add it here, too? |
ok, there is no scaling on DPI change. When you start SI on 100% and move it to 125% display it still uses 100% scaling |
This works really well, but there are a couple of per-monitor-DPI corner cases not listed, affecting window size:
(this is Win10, not sure if Win11 is affected) |
My issue #2251 is also related to DPI scaling. |
The recent addition of V2 DPI awareness introduced a few issues:
The text was updated successfully, but these errors were encountered: