Make Electron applications use the native Wayland renderer

By on

Plenty of applications are built using Electron. To name some of them:

  • Discord
  • VS-Code
  • Slack
  • Obsidian
  • Spotify

And they all look terrible by default when running under Wayland + fractional scaling. Let's see how we can fix that.

A short lexicon

Let's get some simplified definitions out of the way:

  • Chromium is an open-source web browser. It is maintained primarily by Google.
  • Chrome is the popular browser made by Google built on top of Chromium with added proprietary (closed-source) features.
  • Node.js is an open-source, cross-platform JavaScript runtime environment that allows developers to execute JavaScript code outside of a web browser.
  • Electron is an open-source framework that allows developers to build desktop applications using web technologies, by combining Chromium and Node.js.
  • Wayland is a display server architecture designed to replace the old X11 server (it's from september 1987, so it's 1 month older than me!), providing a simpler way to render graphical content. Each operating system has something like this. On MacOS/iOS it is called "Quartz", on Android it is called "SurfaceFlinger", ...
  • XWayland is a compatibility layer that allows X11 applications to run on Wayland compositors by translating X11 protocol requests into Wayland protocol requests
  • ~/ is a commonly used alias on Linux to refer to the current user's home folder. In my case ~/ would be the same as /home/skerit/

That's a lot of things to explain, but it should make the following easier to understand 😅

What's the problem?

While Chromium has the capability to run natively under Wayland, it does not do so by default. Instead, it insists on acting like an X11 application. So this forces it to use XWayland.

What is the problem with that? Well, besides it being an extra layer sometimes causing some minor issues here and there, the real problem is when you use fractional scaling.

Say you're using a 4K monitor with no scaling: all graphical elements will look very tiny. This makes text and interface components difficult to read and interact with. Scaling adjusts the size of these elements to improve readability and usability.

While integer scaling (e.g., scaling everything by 2x or 3x) increases the size of graphical elements, they often become too large, taking up excessive screen space. Consequently, fractional scaling (e.g., 1.25x) is preferred for a more balanced display size.

Since integer scaling (say scaling everything up by 2x or 3x) makes everything too big, I want to use a fractional multiplier, more specifically 1.25x

And there XWayland has problems: it renders the window at its original size (1x) and then scales it up to the desired fraction (e.g., 1.25x). This approach leads to blurry visuals since the scaling is applied post-render rather than adjusting the render size itself.

Screenshot of Obsidian using the blurry XWayland renderer vs the crisp native Wayland renderer This is a screenshot of Obsidian: The top uses the blurry XWayland renderer, while the bottom uses the crisp & native Wayland renderer.

How to solve this?

The solution is very easy: force Chromium to use the Wayland renderer. You can do it like this:

chromium --enable-features=UseOzonePlatform --ozone-platform=wayland

Of course, you don't want to start the application from the terminal each time. So you can either add it to the .desktop links, or more easier: you can add these as default flags, which is a feature Chromium supports.

Chromium checks a file in your home folder, for me it is: ~/.config/chromium-flags.conf

In that I can put flags that should be used each time Chromium starts:

--enable-features=UseOzonePlatform
--ozone-platform=wayland

Electron will actually ignore this file. It has its own file instead: electron-flags.conf. Simply put the same flags in there. Or symlink them, whatever you like.

And from then on out, they'll always start using Wayland.

Oh, if you sometimes for some reason switch environments that aren't Wayland based, you can tell it to automatically detect which renderer to use too, just use this flag instead:

--ozone-platform-hint=auto

What about Discord? And VS-Code? And Spotify?

Hey, what about Discord or VS-Code? I thought they were Electron apps too, yet they still look blurry!

VS-Code uses yet another file to load flags: ~/.config/code-flags.conf. So you just need to put the same flags into that file.

Spotify also uses a different file: ~/.config/spotify-flags.conf

Discord on the other hand removed this functionality. It does not support the usage of a flags file. You'll be better of editing the .desktop file.

Let's take a look at that next.

Discord

So we've established that discord does not use any "flags" file.

It does have a ~/.config/discord/settings.json file that has a section called chromiumSwitches! You might be tempted to waste a lot of time on that, so don't! Only a limited amount of switches are supported in that section, namely these:

 const validSwitches = {
    disable_accelerated_h264_decode: 1,
    disable_accelerated_h264_encode: 1,
    disable_accelerated_hevc_decode: 1,
    disable_d3d11: 1,
    disable_d3d11_video_decoder: 1,
    disable_decode_swap_chain: 1,
    disable_dxgi_zero_copy_video: 1,
    disable_dynamic_video_encode_framerate_update: 1,
    disable_media_foundation_clear_playback: 1,
    disable_media_foundation_frame_size_change: 1,
    disable_metal: 1,
    disable_nv12_dxgi_video: 1,
    force_high_performance_gpu: 1,
    force_low_power_gpu: 1
  };

So that's a dead end.

Info
Before we continue though: The settings.json file can have a property called SKIP_HOST_UPDATE, which you can set to true in order to make it skip the update check. This is really useful on any non-Debian based distro since otherwise the application will ask you to download a .deb file to upgrade and refuse to start whenever a new version is available.

Modifying the .desktop file

So .desktop files contain information on installed applications, what their name is, how they should be started, etc...

The discord one can be found here: /usr/share/applications/discord.desktop It looks like this:

[Desktop Entry]
Name=Discord
StartupWMClass=discord
Comment=All-in-one voice and text chat for gamers
GenericName=Internet Messenger
Exec=/usr/bin/discord
Icon=discord
Type=Application
Categories=Network;InstantMessaging;
Path=/usr/bin
Path=/usr/bin
Warning
It is not a good idea to edit this file directly, since it is probably handled by your package manager. The contents would be removed whenever you update the package.

What you should do is copy it to your local folder using the same name & edit that. So to copy the file first:

cp /usr/share/applications/discord.desktop ~/.local/share/applications/

And then you can edit the file using your favourite editor, like:

nano ~/.local/share/applications/discord.desktop

Just modify the Exec= line to look like this:

Exec=/usr/bin/discord --enable-features=UseOzonePlatform --ozone-platform=wayland

And voila, Discord works natively under Wayland now too.

Comments

Name
Email
Website
Body
submit error done Busy
Jelle De Loecker