-
Notifications
You must be signed in to change notification settings - Fork 927
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
High-DPI and dynamic DPI changing support for Windows #224
High-DPI and dynamic DPI changing support for Windows #224
Conversation
Embedding a manifest isn't too hard. Currently in my apps I use the embed-resource crate, which allows embeding a manifest by using a simple The problems with this approach would be:
|
Reimplement platform_window on win32
When is winit ever built as a separate dynamic library? 99% of the time all rust crates are statically linked together.
If Rust would finally let us specify arbitrary linker arguments, then you could use |
Rust may be used to build a dynamic library to be loaded by foreign code. First-class support for this use case is one of rust's big selling points. If DPI awareness needs to be set in the manifest, and cargo won't yet let us just hardware it to "aware," it seems like the only behaviorally predictable solution is a documentation one. |
I agree that this would be the best solution for building This idea of loading function pointers and then calling the functions to set DPI awareness is used by GLFW. Of course, GLFW is more often than not loaded as a DLL, but as @Ralith said, someone could build a
That could work, but we can't guarantee users of the library will do that. And since high-DPI screens aren't that common, the users of the If As I said before, high-DPI support also involves some work done by users of the library, but by providing a cross-platform API of getting DPI and being informed of DPI changes, maybe users will also read up on high-DPI support and include it in their apps. |
I don't know the APIs in question, but it's probably not appropriate for winit-in-a-cdylib to automatically set the entire process to high DPI, if for example rust code is being used as a plugin that needs to play well with other existing code that has its own opinions. |
Even for winit-as-a-regular-library it's probably not a great thing to set a process-global option. |
These option can only be changed once, anyway. If the user wants to override it, the user only has to call these functions before The method @retep998 recommends, using manifests, would mean the user wouldn't be able to make the app DPI unaware later. |
I don't think winit should automatically set the DPI awareness. Although I do think it should provide the ability to change the DPI awareness when the user explicitly asks for it. |
…inite/winit into fix-hidpi-windows
I've refactored the code. High-DPI awareness is now opt-in. The user has to call |
src/platform/windows/window.rs
Outdated
@@ -44,7 +44,7 @@ impl Window { | |||
{ | |||
let mut w_attr = Some(w_attr.clone()); | |||
let mut pl_attr = Some(pl_attr.clone()); | |||
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ew trailing whitespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was in the original window.rs
. I've removed it now.
[skip ci]
This is the right function to use according to the documentation.
There is already the Documentation for the Also, if you report this value as DPI then it is necessary to say in the documentation what is the default, non-scaled value is. |
I see that there is a deprecated SetProcessDPIAware function which can be used on Vista to set DPI awareness and is used in this PR if newer APIs are not available. But I don't see any way to actually get the DPI on Vista. WM_DPICHANGED is only sent on Windows 8.1. I checked all functions in the High DPI Reference and all functions for getting DPI are available only on 8.1 or newer. |
winit
currently cannot be used to create cross-platform high-DPI aware applications (see issue #105). This commit adds support for creating high-DPI aware applications for Windows.The 2 main changes of this pull request:
DPIChanged
, that informs the users of thewinit
library that they should handle the new DPI.I've also added a new
high-dpi.rs
example to showcase what this pull request does.Visual example
This is the same window, but after a DPI change. Notice how the text is blurry - Windows does not know the app is aware of high DPI displays, and therefore scales the rendered bitmap.
After the code changes, the text looks fine, even at higher DPI.
However, high-DPI support means that the user code also has to adapt to higher DPI. The example uses the same font and layout at all DPIs - this is bad, it should be calculating a new layout and choosing a new font based on DPI, but that is not the concern of the
winit
library.The reason why the text is unreadable below is because I didn't account for high-DPI when writing the rendering code.
DPI changed event
While on Windows 7 DPI can only be changed by logging out, therefore closing all programs, and logging in again, starting with Windows 8 DPI can be dynamically changed, or differ from monitor to monitor.
Therefore I added a new
WindowEvent
, theDPIChanged
event, which is sent when the window receives theWM_DPICHANGED
message.Implementation
The code I added uses the already existing
shared_library
dependency. It tries to load, in order, the functions for setting DPI awareness for Windows 10, Windows 8, and Windows Vista.If those DLLs are missing or lack the functions, or if the process is already high-DPI aware (through a manifest), no harm is done.
Further changes
It would be great to add a
MonitorId::get_monitor_dpi()
function, which returns the DPI of the monitor on Windows 8 or newer, and the same system DPI for all monitors on Windows 7 or older.