Eclipse IDE: Sharp on all monitors with HiDPI display
Monitor-specific UI scaling for Eclipse under Windows is a problem, but solvable – A look behind the scenes of development.
(Image: Erstellt mit KI (Midjourney) von iX-Redaktion)
- Amartya Parijat
Until now, anyone working on high-resolution monitors or with multi-monitor setups had a problem in the Eclipse IDE: the user interface does not scale dynamically when the window is moved between monitors with different DPI settings. A blurred UI not only impairs the visual appearance, but also developer productivity.
(Image:Â Screenshots (Amartya Parijat))
Static scaling in the Standard Widget Toolkit
Eclipse uses the SWT (Standard Widget Toolkit) as a UI framework, which uses the native widgets of the respective operating system. Under Windows, SWT translates Java UI components into native Windows components. This usually results in better performance and a platform-specific look & feel. However, SWT only records the DPI information when the application is started and sets all widgets accordingly. If the DPI settings change, a monitor changes or someone moves the window to another monitor, Eclipse does not adjust automatically. As a result, the widgets appear either pixelated or oversized.
For example, if someone moves a button that was originally displayed on a monitor with 100% zoom to a monitor with 200% zoom, the button retains its original size and thus appears blurred or inconsistent.
To eliminate this inconsistency, we have started a project for HiDPI scaling for Eclipse under Windows.
The internal structure of SWT
A look at the structure of SWT shows how complex the challenge of dynamic scaling is. The toolkit consists of three implementations, one each for Windows, Unix and macOS, as well as shared code for certain areas. The implementations share a public API, which ensures that the components work consistently across all three platforms. SWT applications are based on three core components:
- Widgets – the base class of all UI elements.
- Controls – a subclass of widgets, for example for buttons or text fields.
- Resources – Graphics and fonts for the application.
When an application creates a button in SWT, it converts it into a native Windows button via OS level bindings, but does not register subsequent DPI changes. Since the implementation of SWT varies depending on the platform, the question arises as to how to enable DPI changes for Windows-specific components without affecting the underlying cross-platform behavior. It must also be possible to update platform-independent code in the future without changing its implementation.
Videos by heise
First approach
We started by researching ideas in the community. Someone already had a suitable pull request in Eclipse that provided an initial approach for DPI changes on Windows, but it was not sufficient, especially for multi-monitor scenarios. We therefore started with a proof of concept (PoC) and divided the problem into the following sub-areas:
- Provide DPI context for Windows components: SWT components should be able to detect DPI settings at runtime.
- Ensure cross-platform stability: There should be no negative impact on the other operating systems when adjusting DPI on Windows.
- Dynamic scaling for multiple monitors: Components should behave correctly when they are moved between monitors with different DPI values.
The aim was to consistently pass on the changes to the application each time a window is moved to a monitor with different DPI values. We proceeded as follows during implementation:
First, the implementation captures the DPI changes at shell level. In SWT, the Shell class represents the main window of an application. It registers the Windows event DPI_CHANGED if, for example, the window is moved between monitors. If this event occurs, SWT provides all child elements with the correct zoom level.
The implementation must then pass on DPI changes to all widgets. As soon as the shell receives the new DPI settings, it triggers a recalibration of all subordinate widgets. Since SWT widgets are organized hierarchically, we had to ensure that the DPI changes are passed from the Shell to each child widget in a top-down order. We integrated DPI handlers in the relevant Win32 classes for this purpose. A new API would have potentially disrupted the cross-platform design. Instead, we used static private methods to control the DPI changes internally. This allowed us to dynamically scale the widgets without changing the public API or causing regressions on other platforms.
A particular sticking point was resources such as images. The same image can be displayed on monitors with different DPI settings. It was therefore necessary to create several handles for each resource –, each in the appropriate size. For example, 16 px at 100 % zoom, 24 px at 150 % and 32 px at 200 % zoom. To do this, we introduced methods in the Resource classes that manage the handles for the zoom levels. This procedure allows the system to display resources on different monitors in optimum quality.