WM_DPICHANGED suggested size is not scaled - windows

The RECT I get from WM_DPICHANGED is not scaled when I move a window between two monitors with different scaling, I get the same dimensions in pixels whichever monitor I move it to (which results in the window being too large for the monitor or too small for its contents). From using Spy++ it looks like this is the case for other applications too. The documentation
suggests that it should be scaled linearly with DPI by default.
My application is using Qt Quick, which sets PROCESS_PER_MONITOR_DPI_AWARE by default. I've also tried SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE) in my own code, which works as I want in terms of window sizing, but the contents are blurry on the secondary monitor (as you'd expect), and SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) which works like the Qt default but scales the window decorations correctly too. In all 3 cases the window contents are scaled correctly.
I'm wondering if there is an issue with Windows itself, or if an update has changed this behaviour, as no application currently resizes correctly for me, and I'm pretty sure some applications, e.g. Explorer and Edge used to at least. I'm currently using Windows 10 17134.

Related

How to set DPI scale to less than 100% on Windows 10 - With multiple displays

So I have a big 32 inch display with a resolution of 1440p, and I want to set the DPI scaling to 75% instead of 100%. But I can't find any way to do so on multiple monitors.
I currently have:
Display 1 [2560 x 1440] (Main display I want to change)
Display 2 [2560 x 1440] (This one is 27 inches so it's fine as is)
Display 3 [3840 x 2160] (Set to 100%, fine as it is)
This trick (click me) changes DPI scaling via some registry keys (LogPixels & Win8DpiScaling), but when I use that trick it downscales display 3 instead of display 1.
Is there a way to get this to work? I see no reason for Microsoft to limit the scaling in displays.
Note: I have a 2070 super, all the displays are plugged into the GPU via displayport directly, with the latest avalible firmware at the time of writing (september 2021)
The tl;dr:
Technical limitations aside, there are very solid user experience reasons why this probably isn't allowed.
No, Windows will not let you set UI scaling below 100%.
(even if a stable workaround were to be discovered, most users would probably be quite unhappy with the results)
While I would love¹ to be proven incorrect, the implications of scaling at less than 100% are so fraught that this limitation is unlikely to change in the near future.
Background:
This has been the case for ages, likely since Windows first introduced the feature.
Compatibility with current software
The only ~purely technical~ reason I can think of:
The 100% scaling size likely uses the smallest base image (e.g. Explorer and Taskbar icons, mouse and text cursors) resources included in various existing Microsoft and 3rd-party applications.
User experience
Going below the 100% point may cause small UI text and icons, especially in application toolbars and the Taskbar to be blurred to the point of ambiguity.
Those fine lines in the taskbar 'Windows' menu icon? Blurred or gone.
Taken to the extreme, the UI ~might~ become so unreadable that the user is effectively prevented from being able to read the text even in the 'Settings' window and therefore is 'stuck': i.e. not able to navigate through 'Settings' to restore the original '100%' scaling mode.
(Luckily, Windows is never used to run any SCADA software where confusing two icons could theoretically cost money or lives.)
Performance:
Since those carefully-designed graphic assets don't exist, if sub-100% scaling were allowed, it would also likely cause extra CPU/GPU workload - that is why only certain fixed sizes of up-sampling are shown on the normal Display settings screen and why the Advanced scaling settings screen warns that custom scaling between 100-500% is "not recommended".
That might also apply to any fixed scaling option offered below 100%, and absolutely would for custom scaling sizes.
Some people enjoy reading:
Vector-based TrueType/OpenType fonts usually contain a ~lot~ of manual tweaking / hints to enable readable display of very small point sizes.
The marketing department & friends of the C-suite
Could they implement this at a limited range of options? 90%? 75%?
Perhaps - but it's extra testing for a horrible-looking edge case.
The existence of the option, even if only available as a registry hack, might cause some people to actually use it in kiosks and other public-facing displays; this risks the same sort of bad PR as when a BSOD is seen on the 'arrivals' screen at a train station or airport monitor.
Combined with the first example below, even a 90% option could cause trouble in some environments.
Example and tutorial:
Imagine how Windows might look displayed on one of those cheapo '1080p-supported' projectors that actually only contains an imager with a native pixel resolution of, say, 1024x576 (or even 480x234).
Windows thinks it can send 1080p, since that what the HDMI connection advertises, so it does: any text / vector content looks atrocious.
(At least in this case the user could normally² unplug the projector and reconnect to a normal monitor to restore functionality.)
See for yourself... while connected to any monitor (at that monitor's native resolution), with Windows set to 100% scaling:
Open Windows Notepad
Type or paste in any block of text
Now, use the Zoom Out command from the View menu³ five or more times in a row
While not an exact analogue, you may still see how hard it could be to read down-sampled text, even when very high-contrast (the best-case scenario).
   ¹: As someone currently typing this very answer on a 1080p connection to a 55" 4K television as a second monitor, I came across the question very much hoping this was possible. Sadly, logic intervened and killed my potential joy.
   ²: Unless the computer is actually stored somewhere locked or inaccessible, such as a NUC-style PC hidden above the false ceiling in a conference room.
   ³: Alternatively, press <CTRL>-<Minus> five or more times.

AccessibleObjectFromPoint and per-monitor DPI

I'm using accessibility with the AccessibleObjectFromPoint function, and I'd like it to work correctly on a per-monitor DPI environment. Unfortunately, I can't get it to work. I tried many things, and the situation for now is:
My app is marked as per-monitor-DPI-aware in the manifest. (True/PM)
I use GetCursorPos and then AccessibleObjectFromPoint.
How can the problem be reproduced:
Have two monitors, one with 100% DPI, the other with 125%.
Run Chrome on the 125% monitor.
Use AccessibleObjectFromPoint on one of the tab names, it won't work.
It works with some apps (DPI-aware, it seems, like explorer), but doesn't work with others. I tried several relevant functions, such as GetPhysicalCursorPos and PhysicalToLogicalPointForPerMonitorDPI, but nothing works.
It's worth noting that Microsoft's inspect.exe works as expected.
I’ve been struggling with this exact same problem for several weeks and can now tell you my findings. Unfortunately I can’t give you more than a hint of code, because the project I am working on, is proprietary.
The issue started at Windows 8.1. The problem did not exist on Windows 7 or Vista, because AccessibleObjectFromPoint always used raw physical coordinates, as documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317984(v=vs.85).aspx .
“Microsoft Active Accessibility does not use logical coordinates. The following methods and functions either return physical coordinates or take them as parameters.” This has not been true since Windows 8.1.
AccessibleObjectFromPoint now uses a flawed calculation that cannot always find the correct window for reasons similar to my question here: High DPI scaling, mouse hooks and WindowFromPoint .
My findings lead me to one conclusion: The API is broken. This does not mean it is not possible though.
Possible solutions I have partially tested that seem to work follow.
Prerequisites are that you
1/. Make your process per monitor DPI aware, NOT USING THE MANIFEST (more on that later).
2/. Determine the hWnd of the window you want to query (WindowFromPoint() variants)
3/. Determine the monitor DPI of the queried hWnd
4/. Determine the DPI of your process
5/. Determine the DPI of the queried hWnd
6/. Determine the monitor origin and offset for the queried hWnd (MonitorFromWindow() and GetMonitorInfo() )
Next, depends on your platform
Windows 10.0.14393+
Write a function that finds the IAccessible (AccessibleObjectFromWindow() ) from the top level window, and then recursively call IAccessible::accHitTest until you reach the bottom-most IAccessible and perhaps ChildID data. Return that as if you would call AccessibleObjectFromPoint.
To call it successfully, you will need to scale the (x,y) co-ordinates into the scale system of the queried hWnd, using the DPIs and co-ordinates fetched in the list above. Watch out for systems where monitors are not the same size or if monitors are partially offset, or above and below.
And now for the important part for 10.0.14393 – Set your thread to the same DPI_AWARENESS_CONTEXT of the hWnd you are querying. Now call your new function. Now revert your thread to monitor DPI aware, and voila, it works, even if the window is not maximised. This is why you must not use the manifest.
If you are on Windows 8.1 to 10.0.10586 you have a tougher task.
Instead of calling accHitTest, as above, you have to recursively call AccessibleChildren and iterate the call IAccessible::accLocation to determine if your test point is within each child. This is tricky and starts to get really messy when you get to e.g. combo boxes in products like Office, which is only system DPI aware.
That’s all I can give you for now.
To do it successfully on multi-platform (mine has to work from Vista to Windows-Current) the only really safe bet is to write a wrapper DLL in C++ that can determine at runtime which OS it is on and change code path accordingly. The reason you want to do it in C++ is to avoid passing IAccessible objects across the .Net/unmanaged marshalling boundary. You can call IUnknown::Release on objects you don’t need to return n the unmanaged side. You can do it all in .Net, but it will be slow.
P.S. also watch out for Chrome returning infinite trees where parents are children of their parents, some snity checks are required. Also, Chrome does not return accRole correctly, and will give you HTML tags instead of VT_I4.
Good luck
A fairly workable solution is as follows, in your IAccessible recursive function:
Use getwindowrect to capture the physical right on main window
Use accChild.accLocation in loop to capture left and Width on each Object
Add this simple test
If l > rct2r.Right And l > arrIACC.x2 Then
arrIACC.x2 = l + w
End If
if dpi = 100 then no Object is furter out than physical right
if dpi > 100 then closebutton is...x pix offset
Use the difference to rescale all values you are in use of Width
arrIACC.w1 = CInt(((-rct2r.Left + arrIACC.w1) / arrIACC.x2) * rct2r.Right)
This solution is from an Excel plugin I have developed, I was testing the Width of the quick access toolbar qat and my result was +- 5 pixels regardless of any DPI.

How to change the Icon of a MFC-Application without changing each sub-image?

when I open the application icon of a MFC-project with Visual Studio 2008 there are 13 images (different sizes, different color palette). How would you change the icon of your MFC-application without changing each image?
Thanks!
I like to use the Icons file type extension with Paint.NET. When you open a .ICO file it will prompt you for which image to open - select only the largest / highest-bit image. Make your changes, and then save. You will be prompted for which sizes and bitness to save - select the same list that was present in the original icon.
Using this method, you will get automatically scaled and dithered icons at the smaller sizes. A designer would actually tweak the icons at each size to get the best look, but for most applications this technique produces something that is usable.
An icon resource typically contains many different versions of an icon. For an application icon you would expect 16x16, 32x32, 48x48 and 256x256. You'd also expect to see the 3 smaller ones at 32 bit colour, 8 bit colour 4 bit colour. Or some variant on that. Microsoft publishes guidelines.
Why so many different versions of the same icon?
Well, the icon will be drawn in different settings. On a window caption bar, the 16px version will typically be shown. On the Windows 7 taskbar the 48px version will be shown. When usint ALT+TAB in XP the 32px will be shown. In Vista/7 explorer with ultra large icon view, the 256px will be shown.
To obtain the best visual appearance you must have different versions of the image for different sizes because small raster images aren't easy to scale. What's more, you may present a slightly different version of the icon at different resolutions. For example you may use 3D effects only on larger resolution, partial transparency versions.
When using remote desktop, lower colour depths may be used if the connection is bandwidth challenged.
The MS guidelines go into these issues in detail.
The normal practice of for the graphic designer to design the icon and once you are happy with it the designer will produce rasterised versions for all the required sizes and colour depths, typically in a single .ico file.

Director/Lingo, making an application toggle between fullscreen and windowed?

I recently had a client contact me asking for an update to his project that I used to maintain/develop years ago.
It was done using Macromedia Director (now Adobe Director) and Lingo. Since I haven't developed anything using these technology in such a long time I need some assistance.
The majority of the changes are simple, but what has got me stumped is making the application be able to toggle between full-screen projector and windowed-mode.
This is how it is organised:
I have a stub projector, which is lightweight and ensures a quick start-time.
The stub projector loads the main movie. ("#::Content:Main")
This stub projector is published with in full-screen mode.
Now, I can create a projector that is windowed and one that is full-screen mode by publishing separate executables. However what the client wants is the ability to switch this at runtime - is this even possible?
I have found a few workarounds that kinda work (setting the display-rect and stage-rect to the desktop size) but introduce numerous compatibility issues.
Any advice? Solutions?
I am tempted to say that it isn't possible to switch at runtime and recommend that he publishes either a full-screen or a windowed version.
For future reference: http://www.directorforum.com/showthread.php?p=38795#post38795
Well there are different ways to
define "full screen", but all can be
done at runtime:
1) The projector automatically adjusts
the computer's display resolution to
match the dimensions of the movie and
hides the taskbar/dock. This is
generally what "full screen" means in
modern parlance. You can check out
various Xtras for switching the
resolution on the fly.
2) In Director terms, publishing a
projector 'full screen' just means
that the projector window has no
titlebar, takes up the full dimensions
of the display, hides the
taskbar/dock, and has the movie
content centered on screen framed by a
solid background color. This is a
pretty lame implementation of full
screen since it doesn't make the movie
appear any bigger onscreen. This can
be set at runtime by manipulating the
rects that you mention and using an
Xtra to hide the taskbar. Not sure
what "compatibility issues" you ran
into.
3) Graphically stretch the movie so
that its actual content takes up the
entire screen. The easiest way to do
this is by altering the drawRect. But
this can result in distorted graphics
depending on how much stretching is
occurring, since no antialiasing is
used to smooth the stretched pixels.

Mirroring a portion of the screen to an external display (in OSX)

I would like to write a program that can mirror a portion of the main display into a new window. Ideally this new window could then be displayed on an external monitor. I have seen this uiltity for a flightsim that does this on a pc (a multifunction display extractor).
CLick here for a screenshot of the program (MFD Extractor)
This would be a live window ie. constantaly updated video display not just a static graphic.
I have looked at screen magnifiers or vnc clients for ideas but I think I need to write something from scratch. I have tried to do some reading on osx programing but where do I start in terms of gaining access to the display? I somehow need to extract the graphics from a particular program. Is it best to go near the final output stage (the individual pixels sent to the display) or somewhere nearer the window management stage.
Any ideas or pointers would be much appreciated. I just need somewhere to start from.
Regards,
There are a few ways to do this:
Quartz Display Services will let you get access to the video memory for a screen.
Quartz Window Services (a.k.a. CGWindow) will let you create an image of everything that lies below a window. If you create a borderless, transparent, empty, high-level window whose frame occupies an entire screen, everything below it will be everything on that screen. (Of course, you could create a smaller window in order to copy a section of the screen.)
There's also a way to do it using OpenGL that I never fully understood. That technique is demonstrated by a couple of code samples, OpenGLScreenSnapshot and OpenGLCaptureToMovie. It's more or less obsoleted by CGWindow, though.
Each of those will get you an image that you can then show or write to a file or something.
To show an image, use NSImageView or IKImageView. If you want to magnify it, IKImageView has a zoomFactor property, but if you want nearest-neighbor scaling (like Pixie, DigitalColor Meter, or xScope), I think you'll need to write a custom view for that (but even that isn't all that hard).

Resources