AppImageKit
AppImageKit copied to clipboard
Qt applications ignore system font size preferences
It seems that the version of Qt 5.5 currently available for CentOS 6 via EPEL (and therefore used for packaging all Qt AppImages made in CentOS 6) is not using the system font size on any distribution using GNOME or a related desktop environment, which makes text unreadable for users with large, high-resolution monitors. Setting the environment variable QT_STYLE_OVERRIDE=GTK+
seems to correct this behaviour. This line should be added to the AppRun launcher script for any Qt-based AppImages:
export QT_STYLE_OVERRIDE=GTK+ # use system font size
Doing this has either corrected the problem, or at least not made it worse, on every distro/desktop tested so far. Should it become apparent that a different solution is needed on certain desktops then they can be filtered by reading the XDG_CURRENT_DESKTOP environment variable.
What were the distros/desktops tested? I'm mostly worried about forcing GTK+ on KDE
Is this limited to the version of Qt 5.5 currently available for CentOS 6 via EPEL? Is the behavior different e.g., in Qt 5.6?
@probonopd Seems to be limited to Qt 5.5 via EPEL. Ubuntu's Qt 5.4, and Qt 5.5 direct from http://www.qt.io/ don't have the problem.
@RazZziel From my tests, and thanks to those who report at https://musescore.org/en/node/104106
OS/Desktop | Font behaviour without QT_STYLE_OVERRIDE=GTK+ | Font behaviour with QT_STYLE_OVERRIDE=GTK+ |
---|---|---|
Ubuntu/Unity | Incorrect (didn't obey system settings) | Correct (obeys system settings) |
Ubuntu/XFCE | Incorrect | Correct |
Debian/GNOME | Partially correct | Correct |
ArchLinux/MATE | Incorrect | Correct |
ArchLinux/LXDE | Incorrect | Incorrect |
openSUSE/KDE | Correct | Correct |
So setting QT_STYLE_OVERRIDE=GTK+ never made it worse, and in most cases completely fixed it.
If setting it on KDE still worries you, you could do:
if [ "${XDG_CURRENT_DESKTOP}" != "KDE" ]; then
export QT_STYLE_OVERRIDE=GTK+
fi
Wouldn't it be better to just use a different Qt then?
Krita seems to be going down that path. Might also solve https://github.com/probonopd/AppImages/issues/27 while we are at it.
Unfortunately I don't have the time right now to try it out, and I fear that re-building Qt from source each time will easily exceed the Travis build time limit... so we need to build/find a better Qt for CentOS 6?
http://koji.fedoraproject.org/koji/buildinfo?buildID=746785 it seems like Qt 5.6 is coming to EPEL6
Unfortunately I don't have the time right now to try it out, and I fear that re-building Qt from source each time will easily exceed the Travis build time limit... so we need to build/find a better Qt for CentOS 6?
In any case IMHO rebuilding Qt should be the applications responsibility, not the container's; AppImageKit itself doesn't use Qt at all. Each application should pack the version of Qt that better suits its needs, there's no reason for the container to select Qt5.6 i.e. for an app that has only been tested and validated in Qt5.2.
I think it makes sense to put this here because it will get seen by projects using Qt in AppImages. I'm not blaming AppImageKit for problems in Qt via EPEL ;)
Upgrading to Qt 5.6 from EPEL might not fix this problem if it is caused by the EPEL packaging. It might be necessary to get it somewhere else instead of EPEL, we'll have to wait and see. In the meantime, setting that environment variable really isn't very hard to do.
The fact that Qt can normally pick up KDE's font settings is because the KDE platform theme plugin (KDEPlatformTheme.so
) is used, isn't it? So to get an AppImage that bundles Qt to respect the KDE font settings, you would also need to bundle that plugin (including a truckload of KF5 dependencies).
I did a quick test, running my AppImage on a Kubuntu Xenial desktop. It does not respect KDE's font settings, which is to be expected (printing QFontDatabase::systemFont(QFontDatabase::GeneralFont)
gives QFont( "Sans Serif,9,-1,5,50,0,0,0,0,0" )
).
But if I do this hacky maneuver:
mkdir ~/foo/platformthemes
cp /usr/lib/x86_64-linux-gnu/qt5/plugins/platformthemes/KDEPlatformTheme.so ~/foo/platformthemes
QT_PLUGIN_PATH=~/foo ./myapp.AppImage
Then it'll respect the KDE settings (QFontDatabase::systemFont(QFontDatabase::GeneralFont)
now reports QFont( "Noto Sans,10,-1,0,50,0,0,0,0,0" )
instead, which is correct). The above is not a proper solution of course.
I think in general (but I'm not sure), for Qt to pick up font settings from KDE/GNOME, it needs the proper platform theme plugin.
(To clarify: The above is not a proper solution, even if you'd bake some logic into your AppRun
to make it load the host system's KDEPlatformTheme.so
when in a KDE session, since that plugin was built against the system's Qt, while your AppImage could conceivably bundle a Qt that is too new to be ABI compatible. My hack above only worked because the Kubuntu Qt 5.5.1 is ABI compatible with the 5.6.1 I was bundling.)
A solution, if all you're interested in is respecting the KDE/GNOME font settings, might be to make a really lightweight Qt platform theme plugin which only supports reporting font settings and changes to font settings, and bundle that. I might experiment with that actually (though only KDE since I don't have GNOME available).
Finally, I think the fact that it seems to "work" in some cases might just be that "Sans Serif" happen to map to whatever was the font settings on the platform. Try printing QFontDatabase::systemFont(QFontDatabase::GeneralFont)
to see if it really picked up the font settings.
@estan
A solution, if all you're interested in is respecting the KDE/GNOME font settings, might be to make a really lightweight Qt platform theme plugin which only supports reporting font settings and changes to font settings, and bundle that.
Wow. I think this should go into Qt upstream. It's not only affecting AppImages but all sorts of applications that bundle their private copy of Qt (as many do).
Wow. I think this should go into Qt upstream. It's not only affecting AppImages but all sorts of applications that bundle their private copy of Qt (as many do).
Well, looking at the code for the KDE platform theme plugin, such a minimal plugin would (for the KDE case) need to link at least KF5::ConfigCore
, and I guess the Qt devs wouldn't want to do that. I also don't think they'll want to write their own code to parse KDE/GNOME settings, as the format of those might change.
I think the design is that, if no platform theme plugin suited for the current desktop session is found, Qt uses its own, which obviously doesn't know about KDE/GNOME settings, and the idea is that if you want proper integration, you install the platform theme plugin for the respective platform.
But I'm no Qt dev, so what do I know :)
It should be possible to bundle the KDE platform plugin in your AppImage, but it brings in quite a bit of KF5 dependencies [1], which is a bit heavy if all you're after is the font settings (which would only bring in KF5::ConfigCore
AFAICS).
In my image I'm actually bundling the Breeze Qt style plugin + its KF5 dependencies, because my primary target machines are running Plasma, and I wanted the correct look there. It grew my image by about 7 MB, which is quite a bit, but OK in my case.
I'll see if I can create a minimal KDE platform theme plugin that just has the font settings integration though. For GNOME, someone else will have to do it, as I don't have GNOME at hand (and not very good with its APIs).
[1] KF5::ConfigWidgets, KF5::ConfigCore, KF5::IconThemes, KF5::KIOFileWidgets, KF5::KIOWidgets, KF5::XmlGui, KF5::I18n, KF5::Notifications from the looks of it.
Thanks for the detailed explanation @estan. I am also not a Qt developer but I think they should do native GTK and KDE platform plugins, so that applications behave truly natively. In the meantime, I am looking forward to your solution.
Hm yes, thinking about it a bit more, I think you're right. It fits with the purpose of Qt. They do respect Windows' font settings after all.
I'll see if there's maybe a bug report at Qt about this.
In the meantime, I might make a fork of https://github.com/KDE/plasma-integration and brutally hack it to only include the font integration.
I guess the problem might be that on Linux, there are many desktop environments (even if KDE and GNOME are the biggest), and how they store the font settings is different. On Windows and MacOS, it's monolithic, and they can use the system libraries to read font settings. On Linux, they'd need to link KDE libraries, GNOME libraries, et.c. to read the settings properly (or do the parsing themselves and risk it breaking), and I don't think they want Qt to depend on those libraries.
For what it's worth, I forked plasma-integration
and ripped out some things to cut down on the number of KF5 dependencies (notably the KDE native file dialog, which would have brought in KIO and a lot of other stuff). The branch is here: https://github.com/estan/plasma-integration/tree/mini
With this platform theme plugin bundled, my AppImage will respect KDE font and color scheme settings, as well as some other small settings. (I'm actually also bundling the Breeze theme plugin, since Plasma is a major target platform for me).
This platform theme plugin is highly unofficial of course, so if you want something supported, you should bundle the full thing.
@probonopd: Regarding your question "Is this limited to the version of Qt 5.5 currently available for CentOS 6 via EPEL? Is the behavior different e.g., in Qt 5.6?". I saw the problem with Qt 5.6.1 (from EPEL).
And also, I think you're right, this should be reported as a bug in Qt, because it does in fact have some general platform theme plugins for GNOME / KDE built in, which its XCB platform plugin falls back to if no platform theme plugin is chosen (see http://code.qt.io/cgit/qt/qtbase.git/tree/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp). It just seems the one for KDE isn't doing a good job when it comes to fonts.
In any case, I don't think this is a bug with AppImageKit, so this issue should probably be closed.
Thanks @estan this is a highly relevant contribution. Any chance that you will offer a deb or repo (ppa) for it?
@probonopd: Well, I consider it mostly a hack, so I don't really want to turn it into something official looking. The proper thing to do if you want full KDE integration is to bundle the full KDEPlasmaPlatformTheme.so
installed by the official plasma-integration
as it is. For me, I didn't feel like I needed the KDE native file dialog or the systray integration, so those were the things I stripped out (and Wayland support, since my app is X11 only), in order to reduce dependencies.
And Qt should fix/improve its internal KdeTheme
in qgenericunixtheme.cpp
that it falls back to in the absense of a platform theme, since the KDE font settings integration seems broken (perhaps it's getting some settings paths wrong?). It actually tries to manually parse the KDE settings, something I didn't think it did.
And aren't most people building their AppImages on CentOS? Then a .deb
/ PPA wouldn't be too useful I think.
Here are some parts from the Dockerfile
for the CentOS 6.7 image in which I build my AppImage showing how I build Breeze + dependencies and my hacked plasma-integration
+ dependencies.
# Version of Plasma dependencies
ENV PLASMA_VERSION 5.9.3
# Version of KF5 dependencies
ENV KF5_VERSION 5.32.0
# Build and install Extra CMake Modules
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/extra-cmake-modules-${KF5_VERSION}.tar.xz && \
tar xvf extra-cmake-modules-${KF5_VERSION}.tar.xz && \
mkdir /tmp/extra-cmake-modules-${KF5_VERSION}/build
WORKDIR /tmp/extra-cmake-modules-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KWindowSystem
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kwindowsystem-${KF5_VERSION}.tar.xz && \
tar xvf kwindowsystem-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kwindowsystem-${KF5_VERSION}/build
WORKDIR /tmp/kwindowsystem-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KConfig
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kconfig-${KF5_VERSION}.tar.xz && \
tar xvf kconfig-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kconfig-${KF5_VERSION}/build
WORKDIR /tmp/kconfig-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KGuiAddons
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kguiaddons-${KF5_VERSION}.tar.xz && \
tar xvf kguiaddons-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kguiaddons-${KF5_VERSION}/build
WORKDIR /tmp/kguiaddons-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KCodecs
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kcodecs-${KF5_VERSION}.tar.xz && \
tar xvf kcodecs-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kcodecs-${KF5_VERSION}/build
WORKDIR /tmp/kcodecs-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KWidgetsAddons
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kwidgetsaddons-${KF5_VERSION}.tar.xz && \
tar xvf kwidgetsaddons-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kwidgetsaddons-${KF5_VERSION}/build
WORKDIR /tmp/kwidgetsaddons-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KCoreAddons
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kcoreaddons-${KF5_VERSION}.tar.xz && \
tar xvf kcoreaddons-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kcoreaddons-${KF5_VERSION}/build
WORKDIR /tmp/kcoreaddons-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KItemViews
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kitemviews-${KF5_VERSION}.tar.xz && \
tar xvf kitemviews-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kitemviews-${KF5_VERSION}/build
WORKDIR /tmp/kitemviews-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KAuth
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kauth-${KF5_VERSION}.tar.xz && \
tar xvf kauth-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kauth-${KF5_VERSION}/build
WORKDIR /tmp/kauth-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KI18n
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/ki18n-${KF5_VERSION}.tar.xz && \
tar xvf ki18n-${KF5_VERSION}.tar.xz && \
mkdir /tmp/ki18n-${KF5_VERSION}/build
WORKDIR /tmp/ki18n-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_WITH_QTSCRIPT=NO -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KConfigWidgets
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kconfigwidgets-${KF5_VERSION}.tar.xz && \
tar xvf kconfigwidgets-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kconfigwidgets-${KF5_VERSION}/build
WORKDIR /tmp/kconfigwidgets-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KArchive
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/karchive-${KF5_VERSION}.tar.xz && \
tar xvf karchive-${KF5_VERSION}.tar.xz && \
mkdir /tmp/karchive-${KF5_VERSION}/build
WORKDIR /tmp/karchive-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KPackage
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kpackage-${KF5_VERSION}.tar.xz && \
tar xvf kpackage-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kpackage-${KF5_VERSION}/build
WORKDIR /tmp/kpackage-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install Breeze
WORKDIR /tmp
RUN wget https://download.kde.org/stable/plasma/${PLASMA_VERSION}/breeze-${PLASMA_VERSION}.tar.xz && \
tar xvf breeze-${PLASMA_VERSION}.tar.xz && \
mkdir /tmp/breeze-${PLASMA_VERSION}/build
WORKDIR /tmp/breeze-${PLASMA_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DWITH_DECORATIONS=OFF -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install KIconThemes
WORKDIR /tmp
RUN wget https://download.kde.org/stable/frameworks/5.32/kiconthemes-${KF5_VERSION}.tar.xz && \
tar xvf kiconthemes-${KF5_VERSION}.tar.xz && \
mkdir /tmp/kiconthemes-${KF5_VERSION}/build
WORKDIR /tmp/kiconthemes-${KF5_VERSION}/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=NO .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install && \
ldconfig
# Build and install unofficial mini version of KDE Plasma platform theme plugin
WORKDIR /tmp
RUN wget https://github.com/estan/plasma-integration/archive/v${PLASMA_VERSION}-mini.tar.gz && \
tar xvf v${PLASMA_VERSION}-mini.tar.gz && \
mkdir /tmp/plasma-integration-${PLASMA_VERSION}-mini/build
WORKDIR /tmp/plasma-integration-${PLASMA_VERSION}-mini/build
RUN cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr .. && \
cmake3 --build . -- -j6 && \
cmake3 --build . --target install
EDIT: Oops, realized just now that I'm not using the KF5_VERSION
variable I added in the directory part of the KF5 URLs above. I should fix that.
Cool stuff @estan - is your AppImage available for download?
@probonopd: It's a closed source application for work unfortunately :(
But the above is the gist of it. I then install the platform theme plugin and Breeze theme plugin with
# Install Breeze Qt style plugin
cp /usr/lib64/plugins/styles/breeze.so $APPDIR/usr/lib/qt5/plugins/styles/
# Install mini version of KDE Plasma platform theme plugin
cp /usr/lib64/plugins/platformthemes/KDEPlasmaPlatformThemeMini.so $APPDIR/usr/lib/qt5/plugins/platformthemes/
in my AppImage building script (and their deps to $APPDIR/usr/lib
of course).
@estan thanks. Even if it's closed source, feel free to add it to the list at https://github.com/probonopd/AppImageKit/wiki/AppImages if you like.
@probonopd Ah yes, I might do that in the future. It's not a general purpose application though. It's a tool for looking at the results coming from an analysis machine we're developing, so the tool will only be delivered together with the machine. And it's not released yet. It's under development and only tested internally and by a few prospective customers. We're deploying it through our own APT repository at the moment, so I'm only experimenting with AppImage so far (great job BTW, I love the simplicity!).
And since people may be interested: Adding Breeze + dependencies and my custom Plasma platform theme plugin + dependencies increases my AppImage size by ~8 MB compared to when I had no KF5 dependencies in it. Adding just the platform theme + dependencies would be a bit less than that, but not much less.
I am sure we can do better than this for a Qt 5.9 application on Ubuntu 17.10:
But what, exactly, do we need to do?
export QT_STYLE_OVERRIDE=GTK+
prior to running the AppImage doesn't seem to make a visual difference.
Interesting: The AppImages from https://download.opensuse.org/repositories/home:/rncbc/AppImage/ look correctly themed on XFCE:
Despite no platformthemes
bundled:
me@host:~$ strace -f squashfs-root/AppRun 2>&1 | grep -e platformtheme
[pid 31050] stat("/home/me/squashfs-root/usr/plugins/platformthemes/.", 0x7ffd7d15fdd0) = -1 ENOENT (No such file or directory)
[pid 31050] stat("/home/me/squashfs-root/usr/bin/platformthemes/.", 0x7ffd7d15fdd0) = -1 ENOENT (No such file or directory)
But it has Gtk+ related stuff baked in:
me@host:~$ strings squashfs-root/usr/lib/libQt5Widgets.so.5 | grep gtk_ | wc -l
89
Whereas the one bundled with Subsurface doesn't have that:
me@host:~$ strings squashfs-root/usr/lib/libQt5Widgets.so.5 | grep gtk_ | wc -l
0
It's a shame! The newer Qt got worse?
Please move to the linuxdeploy-plugin-qt repository.
Can't move there because it's in a different organization.
Closing as it was moved to linuxdeploy-plugin-qt