JetBrainsRuntime icon indicating copy to clipboard operation
JetBrainsRuntime copied to clipboard

HiDPI scaling on Xwayland outside Gnome broken (for some multi-monitor geometries)

Open oxan opened this issue 1 year ago • 3 comments

Environment: PHPStorm 2024.1.4 on JBR 17.0.11+1-b1207.24, amd64, Ubuntu 24.04, KDE 5.27.11.

Situation:

  • Running JBR as an X11 application within Xwayland (i.e. not using the native Wayland support).
  • One external regular display (2560x1440) and one internal hi-DPI display (3840x2400). The (Wayland) scale factor for the internal display is set to 2x, while the external display is unscaled.
  • Xwayland is set to Hi-DPI, e.g. using KDE's "Legacy Applications (X11)" > "Apply scaling themselves" option in Display Configuration. This gives an Xft.dpi of 192. The Xwayland (Xinerama) screen for the external display will have double the native resolution (5120x2880), and will be downscaled by the Wayland compositor.
  • Consider the situation where the external screen is configured to be above the internal screen, with the internal screen centered below it. The geometry in Wayland will be the external screen of 2560x1440 at (0,0) with scale = 1, and the internal screen of 1920x1200 at (320,1440) with scale = 2. In Xwayland, the geometry will be the external screen of 5120x2800 at (0, 0) and the internal screen of 3840x2400 at (640, 2880).

Symptoms:

  • JBR applications will show fine on the internal screen, but be tiny on the external screen.
  • Show HiDPI info on the internal screen will show:
Per-monitor DPI-aware : enabled
Monitor resolution : 1920x1200
Monitor scale : 2.0
User (IDE) scale : 1.0
Xft.DPI : 192
GSettings scale factor : 2.0
GDK_SCALE : undefined
GDK_DPI_SCALE : undefined
  • Show HiDPI info on the external screen will show:
Per-monitor DPI-aware : enabled
Monitor resolution : 5120x2880
Monitor scale : 1.0
User (IDE) scale : 1.0
Xft.DPI : 192
GSettings scale factor : 1.0
GDK_SCALE : undefined
GDK_DPI_SCALE : undefined

Root cause:

  • The "Monitor scale" for the external screen is incorrectly set to 1.0. In this situation, because the compositor downsamples, JBR should render at 2.0 scale. This is also what all other X11 applications do, JBR is the only application I've encountered showing this behaviour.
  • The "Monitor scale" comes from X11GraphicsDevice.getNativeScaleFactor(). This method first checks the waylandMonitorScales array, and uses the value from there if it's not empty. This array is initialized on startup from X11GraphicsEnvironment.updateWaylandMonitorScaling(). It queries both the X server (XWayland) and the Wayland compositor for display information, matches them based on geometry on the Wayland and X side and, if they match, uses the scale factor from Wayland.
  • Bonus: because in this situation the Wayland and X displays have a different geometry, that matching is completely broken, but that actually saves us in certain scenarios where it can't find a match. For example, if the internal screen is put on top of the external screens, the screen positions on the Wayland side are now (0, 1200) and (320, 0) for respectively the external and internal screen, while on the Xwayland side they'll be (0, 2400) and (640, 0). In this case there'll be no match between the geometries for any screens, the Wayland scale factor will be ignored, and everything will work fine.

Solution:

  • To be honest I don't see any reason why JBR would need to take the scale factor of the displays in Wayland into account when running as an X application. Just use the settings from the X environment (i.e. Xft.dpi) and everything should work fine.
  • If that's not possible for whatever reason, the isMonitorFramebufferScalingEnabled() check should be updated to be generic instead of GNOME-specific.

Workaround:

  • Don't let JBR talk to the Wayland compositor, for example by putting a fake libwayland-client.so.0 on the library path:
touch empty.c
gcc -shared -fpic -o libwayland-client.so.0 empty.c
export LD_LIBRARY_PATH=$(pwd)
phpstorm
  • Alternatively, set the Mutter GSettings key that JBR checks for. This only works as long as the Mutter GSettings schema is installed (mutter-common package on Debian/Ubuntu):
gsettings set 'org.gnome.mutter' 'experimental-features' "['scale-monitor-framebuffer']"

oxan avatar Jun 28 '24 11:06 oxan

https://youtrack.jetbrains.com/issue/JBR-5316

nadia-tarashkevich avatar Jun 28 '24 21:06 nadia-tarashkevich

The workaround in the OPs post worked for me, but the UI is then kind of blurry.

maciex avatar Jul 01 '24 14:07 maciex

The reason for reading Wayland scales in XWayland mode was to enable per-monitor scaling, while stll running on X toolkit, before the Wayland toolkit was ready. Now we got the Wayland toolkit working, so we're going to revert these problematic changes soon.

YaaZ avatar Jul 22 '24 09:07 YaaZ