Eclipse IDE: Scharf auf allen Monitoren mit HiDPI-Darstellung
Monitor-spezifisches UI-Scaling für Eclipse unter Windows ist ein Problem, aber lösbar – ein Blick hinter die Kulissen der Entwicklung.
(Bild: Erstellt mit KI (Midjourney) von iX-Redaktion)
- Amartya Parijat
Wer an hochauflösenden Monitoren oder mit Multi-Monitor-Set-ups arbeitet, hatte in der Eclipse IDE bisher ein Problem: Die Bedienoberfläche skaliert nicht dynamisch, wenn man das Fenster zwischen Monitoren mit unterschiedlichen DPI-Einstellungen verschiebt. Ein unscharfes UI beeinträchtigt nicht nur die Optik, sondern auch die Developer-Produktivität.
(Bild:Â Screenshots (Amartya Parijat))
Statische Skalierung im Standard Widget Toolkit
Eclipse nutzt das SWT (Standard Widget Toolkit) als UI-Framework, das auf die nativen Widgets des jeweiligen Betriebssystems zurückgreift. Unter Windows übersetzt SWT Java-UI-Komponenten also in native Windows-Komponenten. Das führt normalerweise zu besserer Performance und einem plattformtypischen Look & Feel. Allerdings erfasst SWT die DPI-Informationen nur beim Start der Anwendung und stellt alle Widgets dementsprechend ein. Wenn sich die DPI-Einstellungen ändern, ein Monitor wechselt oder jemand das Fenster auf einen anderen Monitor verschiebt, passt sich Eclipse nicht automatisch an. Daher erscheinen die Widgets entweder verpixelt oder überdimensioniert.
Wenn jemand beispielsweise einen Button, der ursprünglich auf einem Monitor mit 100 % Zoom dargestellt wurde, auf einen Monitor mit 200 % Zoom verschiebt, behält der Button seine ursprüngliche Größe bei und erscheint damit verschwommen oder unstimmig dargestellt.
Um diese Unstimmigkeit zu beseitigen, haben wir ein Projekt fĂĽr die HiDPI-Skalierung fĂĽr Eclipse unter Windows gestartet.
Die interne Struktur von SWT
Ein Blick auf den Aufbau des SWT zeigt, wie komplex die Herausforderung der dynamischen Skalierung ist. Das Toolkit besteht aus drei Implementierungen, je eine für Windows, Unix und macOS sowie gemeinsamem Code für bestimmte Bereiche. Die Implementierungen teilen sich eine öffentliche API, die sicherstellt, dass die Komponenten über alle drei Plattformen hinweg einheitlich funktionieren. SWT-Anwendungen basieren auf drei Kernkomponenten:
- Widgets– die Basisklasse aller UI-Elemente.
- Controls – eine Unterklasse von Widgets beispielsweise für Schaltflächen oder Textfelder.
- Resources – Grafiken und Schriftarten für die Anwendung.
Wenn eine Anwendung in SWT einen Button erzeugt, setzt es diesen über OS-Level-Bindings als nativen Windows-Button um, der aber nachträgliche DPI-Änderungen nicht registriert. Da die Implementierung von SWT je nach Plattform variiert, stellt sich die Frage, wie man DPI-Änderungen bei Windows-spezifischen Komponenten grundsätzlich ermöglicht, ohne das zugrundeliegende plattformübergreifende Verhalten zu beeinträchtigen. Außerdem muss es möglich sein, künftig plattformunabhängigen Code zu aktualisieren, ohne dessen Implementierung zu verändern.
Videos by heise
Erster Ansatz
Wir begannen mit der Recherche zu Ideen in der Community. Jemand hatte bereits einen passenden Pull Request in Eclipse, der einen ersten Ansatz für DPI-Änderungen unter Windows lieferte, der jedoch insbesondere bei Multi-Monitor-Szenarien nicht ausreichte. Wir starteten daher mit einem Proof of Concept (PoC) und gliederten das Problem in folgende Teilbereiche auf:
- DPI-Kontext für Windows-Komponenten bereitstellen: SWT-Komponenten sollten zur Laufzeit die DPI-Einstellungen erfassen können.
- Plattformübergreifende Stabilität sicherstellen: Bei der DPI-Anpassung unter Windows durfte es keine negativen Auswirkungen auf die anderen Betriebssysteme geben.
- Dynamische Skalierung fĂĽr mehrere Monitore: Komponenten sollten sich korrekt verhalten, wenn sie zwischen Monitoren mit unterschiedlichen DPI-Werten bewegt werden.
Ziel war es, bei jedem Verschieben eines Fensters auf einen Monitor mit anderen DPI-Werten die Änderungen konsequent an die Anwendung weiterzugeben. Bei der Implementierung sind wir folgendermaßen vorgegangen:
Zunächst erfasst die Umsetzung die DPI-Änderungen auf Shell-Ebene. In SWT repräsentiert die Klasse Shell das Hauptfenster einer Anwendung. Sie registriert das Windows-Event DPI_CHANGED, wenn beispielsweise das Fenster zwischen Monitoren verschoben wird. Tritt dieses Event auf, versieht SWT sämtliche Kind-Elemente mit dem korrekten Zoom-Level.
Die Implementierung muss anschließend DPI-Änderungen an alle Widgets weitergeben. Sobald die Shell die neuen DPI-Einstellungen empfängt, löst sie eine Neukalibrierung aller untergeordneten Widgets aus. Da SWT-Widgets hierarchisch organisiert sind, musste sichergestellt werden, dass die DPI-Änderungen in einer Top-Down-Reihenfolge von der Shell an jedes Kind-Widget weitergegeben werden. Wir integrierten dazu DPI-Handler in den relevanten Win32-Klassen. Eine neue API hätte das plattformübergreifende Design potenziell gestört. Stattdessen verwendeten wir statische private Methoden, um die Änderungen der DPI intern zu steuern. So konnten wir die Widgets dynamisch skalieren, ohne die öffentliche API zu verändern oder Regressionen auf anderen Plattformen zu verursachen.
Ein besonderer Knackpunkt waren Ressourcen wie Bilder. Dasselbe Bild kann auf Monitoren mit unterschiedlichen DPI-Einstellungen angezeigt werden. Daher war es notwendig, für jede Ressource mehrere Handles anzulegen – jeweils in der passenden Größe. Beispielsweise 16 px bei 100 % Zoom, 24 px bei 150 % und 32 px bei 200 % Zoom. Wir führten dazu Methoden in den Resource-Klassen ein, die die Handles für die Zoom-Level verwalten. Diese Vorgehensweise erlaubt dem System, Ressourcen auf unterschiedlichen Monitoren in jeweils optimaler Qualität darzustellen.