Qt Apps and GTK Themes, an investigation with partial success


#1

I’ve been spending a couple of days on an investigation about how to integrate Qt apps better in GTK based environments. So far I had partial success and maybe this thread could help someone else or be a starting point for the further discussion and investigation on achieving the best possible theme integration available at this time, and in the future with snapcraft improvements…

Partial success:

  • Ugly mouse cursor (fallback theme) can be fixed on some DEs
  • GTK theme integration can be achieved on some systems via the QGtkStyle (gtk2) plugin (with drawbacks though)

Failures:

  • Not all distros/DEs expose the right gtk2 settings file and/or provide appropriate GTK2 theme versions

Future work:

  • QGnomePlatform is a very promising project to solve this for GTK3 themes, looks like the proper way to go, but at this time it appears to be not working on Ubuntu, upstream issue filled here.

How to Fix Ugly Fallback Mouse Cursor Theme for Qt Apps

EDIT: there’s now a better way to do this, see next posts below…

The snap needs the correct plugs to access the icon theme and a specific package needs to be staged additionally.

plugs: # additional plug to fix mouse cursor theme
  icon-themes:
    interface: content
    target: $SNAP/data-dir/icons
    default-provider: gtk-common-themes

and stage package:

stage-packages:
      - qt5-style-plugins # for mouse cursor theme fix

For a complete example, please look at the following snapcraft.yaml

Before:

After:

Issues: currently this works only on distros and DEs that also pick up the gtk2 theme, when not supported the fallback cursor is still used. Distros I tested that pick the GTK2 theme up are Ubuntu and elementaryOS for example, no success on Manjaro, Mint, Kubuntu. I think it is safe to integrate this feature since it has no drawbacks and only advantages when supported.


How to Integrate a Qt App with the System’s GTK default Theme

Like above, this works only on a few distros and DEs that export GTK2 themes properly (similar to Ubuntu). The big drawback of this method is that if a distro/DE is not supported it will show an ugly GTK fallback theme instead of the default fusion style, see images below

Default fusion style (Qt apps right now):

QGTKStyle integration on Ubuntu 16.04, works also with Yaru, Adwaita, and more themes:

QGTKStyle on elementaryOS:

Fallback GTK theme when not working (Mint, Zorin, Kubuntu, Manjaro):

Add the following code to your snapcraft.yaml:

plugs: # additional plugs to pick up the GTK theme and icons from the system
  icon-themes:
    interface: content
    target: $SNAP/data-dir/icons
    default-provider: gtk-common-themes
  sound-themes:
    interface: content
    target: $SNAP/data-dir/sounds
    default-provider: gtk-common-themes
  gtk-2-engines:
    interface: content
    target: $SNAP/lib/gtk-2.0
    default-provider: gtk2-common-themes:gtk-2-engines
  gtk-2-themes:
    interface: content
    target: $SNAP/share/themes
    default-provider: gtk2-common-themes:gtk-2-themes

environment:
  GTK_PATH: $SNAP/lib/gtk-2.0
  GTK_DATA_PREFIX: $SNAP
  XDG_DATA_DIRS: $SNAP/share:$XDG_DATA_DIRS
  QT_QPA_PLATFORMTHEME: gtk2 # set default theme to gtk to integrate with system theme (GTK2)

In the app section append the -style gtk2 override to your command like this:

apps:
  symphytum:
    command: desktop-launch symphytum -style gtk2

This is required because somehow the QT_QPA_PLATFORMTHEME env variable is not picked up, so we can force a specific Qt style with that switch. For a complete example, see this snapcraft.yaml file.

I think this is not safe to add unconditionally to your snap at this stage because it will fallback to the ugly GTK fallback theme on unsupported setups (quite a few). Maybe you could ship a different snap with enabled GTK integration for the users who wish to use it on supported systems like Ubuntu and elementaryOS. Some systems like Mint also support this when changing to a compatible theme which includes the GTK2 theme like Adwaita on Mint.

As an end user of such snap you can always force the default Qt fusion style by passing the override switch like symphytum -style fusion this will launch the app with fusion style, regardless of what the snap packager set.


I hope with this thread we can investigate this further maybe even fix the theming for currently unsupported systems. The best solution would be to get the QGnomePlatform plugin to work on a core18 base (work in progress snapcraft.yaml), I think that would also work on most systems because GTK3 is much more similarly configured across different distros.

Cheers
joshirio


#2

Nice topic.

I know the cause of this: The desktop-launch launcher overwrites the variable to appmenu-qt5 (for appindicator support, which is no longer needed in the Qt5 version shipped in core18.

You have to override the environment variable after the desktop-launch launcher is executed, here’s the patch that I’ve just made to enable gtk-common-themes support in SimpleScreenRecorder.


#3

Interesting, never heard of the qt5-gtk-platformtheme package, difficult to find information about it, maybe it’s part of Qt, looks like this could be an alternative to the QGnomePlatform, will have to run some tests.

Thanks for the pointer on the env variable!


#4

I did a reverse package search for the libqgtk3.so file mentioned in the following topic:


#5

The icon problem might be fixed (partially) after the breeze icon theme is supported in gtk-common-themes:
Ship the Breeze theme (#6) · Issues · Community / Ubuntu / gtk-common-themes · GitLab


#6

I believe (part of?) your problem with QGnomePlatform is that it is meant to pair with adwaita-qt, which as the name suggests will only help with Adwaita, not other GTK 3 themes. (FWIW, adwaita-qt is in Ubuntu.)


#7

Yes that was also the respone from the upstream issue report. I initially thought QGnomePlatform was the same just for GTK3 as QGtkStyle was for GTK2.


#8

I’ve submitted a patch to fix this:


#9

Based on the work of @Lin-Buo-Ren (big thank you :slight_smile: ), there’s now a better way to fix the cursor theme, which now also work correctly on distros like Mint, of course except less common cursor themes that are not in the gtk common themes snap. Another advantages of using the qt5-gtk-platformtheme package is the native GTK3 file dialogs and native font settings. The default Qt fusion theme still gets used, so the only thing remaining to fix is the GTK3 theming, hopefully we will get there.

Native file dialog using GTK3 by a Qt app:

Mint cursor theme now correctly picked up:

Before implementing this change (notice font size and style):

After this change (notice font size and style):


How to Fix Mouse Cursor Theme, Use Native GTK3 File Dialogs and Font Settings

First we have to add the right plugs to allow the snap accessing the icon and general theme settings (for GTK3)

plugs: # plugs for theming, font settings, cursor and to use gtk3 file chooser
  gtk-3-themes:
    interface: content
    target: $SNAP/data-dir/themes
    default-provider: gtk-common-themes:gtk-3-themes
  icon-themes:
    interface: content
    target: $SNAP/data-dir/icons
    default-provider: gtk-common-themes:icon-themes
  sound-themes:
    interface: content
    target: $SNAP/data-dir/sounds
    default-provider: gtk-common-themes:sounds-themes

Modify the original app section to something like this:

apps:
  symphytum:
    adapter: full
    command: bin/symphytum
    command-chain:
      - bin/desktop-launch
      - bin/gtk3-env-launch
    desktop: usr/share/applications/symphytum.desktop
    environment:
      DISABLE_WAYLAND: 1 # disable wayland (not ready yet), comment out this line to enable full wayland support
      #QT_QPA_PLATFORMTHEME: gtk3 # gtk-common-themes support, currently overrided by desktop-launch(`appmenu-qt5`), implement in snap launcher instead
    plugs:
      - home
      - network
      - opengl
      - removable-media
      - unity7
      - x11
      - wayland
      - gsettings # allow wayland apps access system theme settings
      - desktop
      - desktop-legacy

This is needed because as noted in the previous post by @Lin-Buo-Ren, the environment variable for the Qt platform theme is set by the desktop-launch script, this will probably be fixed by upstream, in the meantime we use a custom launcher that sets the platform theme env variable after the desktop launch script.

To do this we create an executable (use chmod +x) file inside the local/launchers directory (or snap/local/launchers depending on your repo structure):

edit local/launchers/gtk3-env-launch file as follows:

#!/usr/bin/env bash
# This is the maintainence launcher for the snap, make necessary runtime environment changes to make the snap work here.  You may also insert security confinement/deprecation/obsoletion notice of the snap here.

set \
	-o errexit \
	-o errtrace \
	-o nounset \
	-o pipefail

# gtk-common-themes support
export QT_QPA_PLATFORMTHEME=gtk3

# Finally run the next part of the command chain
exec "${@}"

To deploy this script, we have to add it to the parts section:

parts:
  launchers: # custom launcher to set QT_QPA_PLATFORMTHEME=gtk3 correctly
    source: local/launchers
    plugin: dump
    organize:
      '*': bin/
    stage:
      - -bin/README.*

Finally, add the qt5 gtk package to the staging packages in the main parts section:

stage-packages:
      # for theming, font settings, cursor and to use gtk3 file chooser
      - qt5-gtk-platformtheme 

A complete example, which includes the yaml file and all required scripts, is available here.

Note, this has no downsides because the default Qt fusion widget style is still used, so the end user is not at risk to see the ugly GTK fallback theme. Tested and working on Ubuntu, Kubuntu, Linux Mint, Zorin, Solus, Manjaro. Strangely only elementaryOS falls back to the default x11 cursor theme yet the native gtk file chooser is still used.


#10

without DISABLE_WAYLAND=1 apps run but look awful (at least for me). Is it known what’s specifically missing here?


#11

can you post a screenshot? Is it the CSD (window theme) if so, it’s because Qt draws it own CSD and not the window manager.


#12

Wayland

XWayland

The CSD is the obvious difference, but also the font size & proportions look off.


#13

Looks like the Qt app under wayland is using a custom DPI setting. I’m not sure this is snap specific though. AFAIK Qt apps look like this under wayland, so that would be out of scope here. Please correct me if this happens only when run from snapd.

BTW I think wayland apps require the gsettings plug to access theme info from the DE.


#14

Indeed, it isn’t specific to snaps.

Older Qt versions seem to have a broken theme on wayland.


#15

Not sure what changed but after some core18 or snapcraft/snapd update, themes appear to be broken again, if you build with snapcraft right now. Previously built snaps still work fine.

More info https://github.com/keepassxreboot/keepassxc/issues/2966

EDIT: temp workaround is to specify the default Qt fusion theme by using the style flag, for example:

apps:
  symphytum:
    command: desktop-launch symphytum -style fusion