TROMjaro Forum

How we theme TROMjaro

Update

We created packages for these fixes and improved them. You can find our package here. The bellow article is still somewhat relevant in terms of how we approach things, but not in terms of coding and final methodology.

Article:

Pretty much all distributions that I personally tested, and I tested a lot of them, fail to properly apply a system theme for most applications. Actually I know no one that does a great job. TROMjaro so far is the only one that does a great job at it. I will show you.

So, how do we do it?

First of all, you have to understand what we are facing with here. The ideal is to be able to select a theme of your choice, and the expectation to have it apply to at least the vast majority of the apps that you use. In Linux we have a few kinds of apps: QT, GTK (a few versions of), GTK + Libadwaita, Flatpaks, Snaps, Appimages, and a few other kinds. How to deal with them all?

Sync GTK with QT

We are using GTK (XFCE) so our system can already theme that (not Libadwaita tho…). On the left side you can see a QT app. Our default theme is dark. As you can see the QT app uses a light/default theme.

Believe it or not, that’s where most distros stop at. This broken kind of theming. The icons for the light QT theme are barely visible since we use an icon pack for our dark theme…so it is quite bad.

First let’s make the QT apps sync with the current GTK theme that we have. For that we need two packages: qt5ct and qt5-styleplugins. The second package is not updated since 2017. But it is this that does the magic. I’ve been using it for many years now and all works…Mint uses it too for the same purposes, and Mint is a trustful bunch of smartys. We had to package it for TROMjaro so it is in our repos. You can also find it in AUR. This is how the QT5CT looks like:

We have to select the style as GTK2. And we’ve also selected the default TROMjaro font in the Fonts. We did the same for the icon pack. What this does is to force all QT apps to use the current GTK theme that we have for our system.

Lastly go to your home folder and find the file .profile. Open it and add this line export QT_QPA_PLATFORMTHEME="qt5ct". You may need to reboot your computer.

This is how it looks now:

It is much better, but those icons are still not visible…to fix that you have to manually go to the QT5CT in the Icons tab and select a better icon theme…not user friendly. We can also do that via the file .config/qt5ct/qt5ct.conf:

[Appearance]
color_scheme_path=/usr/share/qt5ct/colors/airy.conf
custom_palette=false
icon_theme=zafiro-dark
standard_dialogs=default
style=gtk2

[Fonts]
fixed=@Variant(\0\0\0@\0\0\0 \0U\0\x62\0u\0n\0t\0u\0 \0\x43\0o\0n\0\x64\0\x65\0n\0s\0\x65\0\x64@(\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)
general=@Variant(\0\0\0@\0\0\0 \0U\0\x62\0u\0n\0t\0u\0 \0\x43\0o\0n\0\x64\0\x65\0n\0s\0\x65\0\x64@(\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)

[Interface]
activate_item_on_single_click=0
buttonbox_layout=0
cursor_flash_time=1000
dialog_buttons_have_icons=0
double_click_interval=400
gui_effects=@Invalid()
keyboard_scheme=2
menus_have_icons=true
show_shortcuts_in_context_menus=true
stylesheets=@Invalid()
toolbutton_style=4
underline_shortcut=0
wheel_scroll_lines=3

[SettingsWindow]
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\vH\0\0\0\xd8\0\0\xe*\0\0\x3\xcc\0\0\vJ\0\0\0\xf4\0\0\xe(\0\0\x3\xca\0\0\0\x1\0\0\0\0\a\x80\0\0\vJ\0\0\0\xf4\0\0\xe(\0\0\x3\xca)

[Troubleshooting]
force_raster_widgets=1
ignored_applications=@Invalid()

Notice the line icon_theme=zafiro-dark.

This is the trick number 1 that we will add to our final Theme Switcher code!

So we will fix this later in a proper way.

In XFCE we have one more hurdle: if you change a theme, it won’t apply to the top bar of certain apps…

Here I chose the adwaita theme in XFCE, but it won’t change the top bar for other apps. For that we have to open a Window Manager app in XFCE and choose the same theme…

Unfortunately there is no adwaita theme for the window management theme…such a headache. XFCE is adding a new option in the next stable release to select to sync the two…that’s a lot better. But in the meantime we have to kinda fix this in TROMjaro via an xfconf-query command…

This is the trick number 2 that we will add to our final Theme Switcher code!

With these two tricks, we can make our QT apps look identical to our GTK ones. As such:

See? Perfect! Of course to automate this we need a script to do that. Will reveal at the end.

Fix GTK + Libadwaita

More and more apps are using Libadwaita, the Gnome’s way of trying to “fix” theming by not allowing it. As you can see bellow in the right side, that’s how some GTK + Libadwaita look like on TROMjaro, after we selected a dark theme:

Not dark at all…Libadwaita does not care. We too use a handful of such apps as default in our TROMjaro because they are really great and useful.

How to fix this mess? Install the package libadwaita-without-adwaita-git - luckily someone decided to fix this. It is in the AUR and we also packaged it for TROMjaro. After installing it, voilla sanity:

We now got to control GTK, GTK + Libadwaita, and QT apps. We can stop here honestly because these are the absolute vast majority of apps out there…

But flatpaks???

Flatpaks are quite new and a bit weird. Contained packages. To theme them is not easy…I hope in the future they can implement an easier way. A way to do it is to install the same theme as flatpak, and some apps will respect that. But you need to install 2 themes for that…if you can find the same themes…

This is how Ungoogled Chromium (flatpak) looks like on TROMjaro:

It should go have a party with the Libadwaita ones! :slight_smile:

In order to force flatpaks to respect the system’s theme one has to go to /var/lib/flatpak/overrides/ - and if you do not have that folder, create it. Then create a file called global and add this to it:

[Context]
filesystems=~/.themes;

It tells flatpaks to look into the .themes folder for the system’s theme. It cannot be any other folder from my tests and knowledge…so you’ll have to copy your system’s theme that you are using, there…

UGLY.

We have a tutorial about how you can automate that, see Force some flatpaks to respect your theme

But yeah, that’s doable. After you do that you get this beauty:

It is the ugliest hack of them all, but that’s what it is…and many flatpaks won’t even accept these sort of things. They will look the way they want to…We always recommend to only use flatpaks in case you cannot find an app in Repos or AUR.

The rest?

We can’t do much about the rest, but they are a tiny minority. With the above, we master some 95-98% of all apps. It is a wild guess, but I tested thousands of apps so far so that’s from my own experience.

The downside

If you manually do the above changes you’ll still have a lesser experience. If I am to go now and install a new theme in TROMjaro and change it from the Apperance in XFCE, this is what I get:

Bad icons for QT apps…different window top bars…not that nice…

This is something we, at TROMjaro cannot improve honestly…XFCE must improve on that. The window top bar thing, as I said, will be able to sync with the system’s theme. But for the QT icons…this is on the user to be honest, since it is up to you what icon theme you will select. If you select a light icon theme with a light system theme, then you get light icons on a light theme…

But manually changing the icons from the Apperance into a dark set, won’t change it for the QT apps…remember it needs to be changes from the QT5CT…if you do it from there too, then all good.

In all, to change the theme, you must select the system’s theme from Appearance, then the same theme from the Window Manager, then a good icon pack from the same Appearance, then the same icon pack from QT5CT. Quite a lot of joggling for simply, changing the theme…

TROMjaro’s Theme Switcher

And this is why we decided to build our own theme switcher. The upside is that it makes everything so easy as I will explain. The downside is that it only works with our main system theme…tho we have 10 variations of colors and dark/light variants. So a lot of options. And who knows, maybe in the future, we can make it work for any theme.

This is it:

And underneath all that, this is the code:

#!/bin/bash
icons="$HOME"/.local/share/Theme-Switcher

set_theme() {
	# Check for Zafiro icon pack, icon packs won't be changed if Zafiro is not in use
	current_icon_theme=$(xfconf-query -c xsettings -p /Net/IconThemeName)
	[ "${current_icon_theme%-dark}" = 'zafiro' ] && Zafiro='True'

	if [ "${1##*-}" = 'Light' ]; then
		yad --image "dialog-question" --title '' --button='DARK':1 --button='LIGHT':0 --text 'Select the panels theme (dark panels may result in light icons over a light theme):'
		case $? in
			1)
				# Enable dark panels
				xfconf-query -c xfce4-panel -p /panels/dark-mode -n -t bool -s true
				# Use the dark icon pack
				[ "$Zafiro" = 'True' ] && { xfconf-query -c xsettings -p /Net/IconThemeName -n -t string -s zafiro-dark
				sed -i 's/^icon_theme=.*$/icon_theme=zafiro-dark/' "$HOME"/.config/qt5ct/qt5ct.conf; }
				;;
			0)
				# Disable dark panels
				xfconf-query -c xfce4-panel -p /panels/dark-mode -n -t bool -s false
				# Use the light icon pack
				[ "$Zafiro" = 'True' ] && { xfconf-query -c xsettings -p /Net/IconThemeName -n -t string -s zafiro
				sed -i 's/^icon_theme=.*$/icon_theme=zafiro/' "$HOME"/.config/qt5ct/qt5ct.conf; }
				;;
			*) exit ;;
		esac
	else
		# Use the dark icon pack
		[ "$Zafiro" = 'True' ] && { xfconf-query -c xsettings -p /Net/IconThemeName -n -t string -s zafiro-dark
		sed -i 's/^icon_theme=.*$/icon_theme=zafiro-dark/' "$HOME"/.config/qt5ct/qt5ct.conf; }
	fi
	# Change the main theme to the chosen one
	xfconf-query -c xsettings -p /Net/ThemeName -n -t string -s "Skeuos-$1"
	xfconf-query -c xfwm4 -p /general/theme -n -t string -s "Skeuos-$1-XFWM"
	gsettings set org.gnome.desktop.interface gtk-theme "Skeuos-$1"
	notify-send "Skeuos-$1 theme was enabled"
}
export -f set_theme

yad --no-buttons --center --keep-icon-size --use-interp --title 'Theme Switcher' --text-align=center --text "A Theme Switcher for TROMjaro's default theme-set (Skeuos)" --form --columns 5 \
--field=!"$icons/Blue-Dark.png"!'Blue-Dark':FBTN "set_theme 'Blue-Dark'" \
--field=!"$icons/Violet-Dark.png"!'Violet-Dark':FBTN "set_theme 'Violet-Dark'" \
--field=!"$icons/Blue-Light.png"!'Blue-Light':FBTN "set_theme 'Blue-Light'" \
--field=!"$icons/Violet-Light.png"!'Violet-Light':FBTN "set_theme 'Violet-Light'" \
--field=!"$icons/Teal-Dark.png"!'Teal-Dark':FBTN "set_theme 'Teal-Dark'" \
--field=!"$icons/Orange-Dark.png"!'Orange-Dark':FBTN "set_theme 'Orange-Dark'" \
--field=!"$icons/Teal-Light.png"!'Teal-Light':FBTN "set_theme 'Teal-Light'" \
--field=!"$icons/Orange-Light.png"!'Orange-Light':FBTN "set_theme 'Orange-Light'" \
--field=!"$icons/Green-Dark.png"!'Green-Dark (default)':FBTN "set_theme 'Green-Dark'" \
--field=!"$icons/Brown-Dark.png"!'Brown-Dark':FBTN "set_theme 'Brown-Dark'" \
--field=!"$icons/Green-Light.png"!'Green-Light':FBTN "set_theme 'Green-Light'" \
--field=!"$icons/Brown-Light.png"!'Brown-Light':FBTN "set_theme 'Brown-Light'" \
--field=!"$icons/Magenta-Dark.png"!'Magenta-Dark':FBTN "set_theme 'Magenta-Dark'" \
--field=!"$icons/Yellow-Dark.png"!'Yellow-Dark':FBTN "set_theme 'Yellow-Dark'" \
--field=!"$icons/Magenta-Light.png"!'Magenta-Light':FBTN "set_theme 'Magenta-Light'" \
--field=!"$icons/Yellow-Light.png"!'Yellow-Light':FBTN "set_theme 'Yellow-Light'" \
--field=!"$icons/Red-Dark.png"!'Red-Dark':FBTN "set_theme 'Red-Dark'" \
--field=!"$icons/Grey-Dark.png"!'Grey-Dark':FBTN "set_theme 'Grey-Dark'" \
--field=!"$icons/Red-Light.png"!'Red-Light':FBTN "set_theme 'Red-Light'" \
--field=!"$icons/Grey-Light.png"!'Grey-Light':FBTN "set_theme 'Grey-Light'"

When you click any of the themes in the list, it changes all of what we talked above automatically. Look how it uniformizes those non-uniform apps:

That will force our default system and icon theme, so be aware of that! You can adapt the above code for your own system’s theme.

Conclussions

All of this proves that we can sync the GTK and QT apps, and fix icon issues + the libadwaita unfriendliness. It is not that hard. But these should be done by Desktop Environments. Imagine if XFCE had all of this built into it, so whenever you use their Appearance app and click any theme, it applies for like 98% of all apps out there. How cool would this be!?

For now we have a solution for TROMjaro that works. For now… We do not know if Gnome will break theming even more and how, and if anyone can provide a fix for that. We do not know if QT6 (the next version of QT) will accept theming…but it is a shame that we have to fight over having a decent desktop on Linux. This is not only a visual subjectivity reason, it is also a usability one. If you work at night and want a dark theme, then let it be dark! And not dark with dark icons, mind you…that’s too dark! :smiley:

In the end, TROMjaro proves that yes, we can theme the Linux desktop in a way that is functional. And where there are glitches, we should fix them!

I also recommend this otehr article where I explain why Libadwaita is not needed No, we can theme pretty much all Linux apps! Gnome is wrong

UPDATE 2022.09.02

Fix QT6

Now the QT6 was another issue I had on my to-fix list. And we did. This is a QT6 app:

Looks out of place with our dark TROMjaro theme.

Let’s make it look like this:

We have to install 2 packages: qt6ct and qt6gtk2. Next you can also copy the settings for it.

Go to the .config folder and create another one called qt6ct and inside of it a file called qt6ct.conf. Inside of it add:

[Appearance]
color_scheme_path=/usr/share/qt5ct/colors/airy.conf
custom_palette=false
icon_theme=zafiro-dark
standard_dialogs=default
style=gtk2

[Fonts]
fixed=@Variant(\0\0\0@\0\0\0 \0U\0\x62\0u\0n\0t\0u\0 \0\x43\0o\0n\0\x64\0\x65\0n\0s\0\x65\0\x64@(\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)
general=@Variant(\0\0\0@\0\0\0 \0U\0\x62\0u\0n\0t\0u\0 \0\x43\0o\0n\0\x64\0\x65\0n\0s\0\x65\0\x64@(\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0\x32\x10)

[Interface]
activate_item_on_single_click=0
buttonbox_layout=0
cursor_flash_time=1000
dialog_buttons_have_icons=0
double_click_interval=400
gui_effects=@Invalid()
keyboard_scheme=2
menus_have_icons=true
show_shortcuts_in_context_menus=true
stylesheets=@Invalid()
toolbutton_style=4
underline_shortcut=0
wheel_scroll_lines=3

[SettingsWindow]
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\vH\0\0\0\xd8\0\0\xe*\0\0\x3\xcc\0\0\vJ\0\0\0\xf4\0\0\xe(\0\0\x3\xca\0\0\0\x1\0\0\0\0\a\x80\0\0\vJ\0\0\0\xf4\0\0\xe(\0\0\x3\xca)

[Troubleshooting]
force_raster_widgets=1
ignored_applications=@Invalid()

Now QT6 will dance the same way as the rest. Almost…

Flatpaks reloaded

I suggest you go the ugly way and create a script that will sync the themes for flatpaks too.

Got to /usr/bin (open as root). Create a file called fix-flatpaks-theming. In it add:

#!/bin/sh
while :; do
rm -r ~/.themes/* 2> /dev/null
rsync -av --progress /usr/share/themes/* ~/.themes/ --exclude Windowck
rsync -av --progress ~/.local/share/themes/* ~/.themes/ --exclude Windowck-dark
sleep 600
done

Save. Right click and Permissions then “Allow this file to run as a program.”. Now in the .profile file in your Home directory add this line fix-flatpaks-theming & maybe bellow fix-tweaked-desktop-files &. Reboot.

Fix the QT updates…

So…bloody hell if the QT gets an upgrade then it breaks the theming and some packages need to be reinstalled…sucks. So let’s try to fix it for good…

Let’s create a script in /usr/bin called reinstall-for-qt. Add this to it:

#!/bin/bash
rm /var/lib/pacman/db.lck  &
pacman --noconfirm -S qt5-styleplugins qt6gtk2

Save…right click, Permissions and make it run as a program. You know the drill by now.

This will reinstall the packages that need to be reinstalled. But when? Let’s tell it!

Create a “hook”. Go to usr/share/libalpm/hooks/ and create a file reinstall-for-qt.hook and put this into it:

[Trigger]
Operation = Upgrade
Type = Package
Target = qt5-base
Target = qt6-base


[Action]
Description = Reinstalling needed packages for theming QT applications...
When = PostTransaction
Exec = /usr/bin/reinstall-for-qt

Perfect! Now whenever there is an update to QT5 or QT6 the system will automatically update the right packages and theming will automatically work for QT…

Lastly, fix XFCE

All of the work we’ve done for theming works well when you use our Theme Switcher…but we want it to work in XFCE by default when using the main tool: Appearance. This is why we renamed that as TROMjaro Theme Switcher since it now forces a theme and icon set that are default to TROMjaro. But what if you want custom themes and icons?

For that we need to sync GTK with QT, in terms of themes and icons…

Make the last script. Again, /usr/bin and create fix-theming. Add this to it:

#!/bin/sh
sync_theme() {
	# Get the current system theme
	theme=$(xfconf-query -c xsettings -p /Net/ThemeName)
	# Find the best match for the xfwm4 theme that corresponds with the current system theme
	xfwm4_theme=$(find /usr/share/themes/ /usr/local/share/themes/ "$HOME"/.themes/ "$HOME"/.local/share/themes/ -mindepth 2 -maxdepth 2 -type d -name xfwm4 -printf '%h\n' 2>/dev/null | grep -o "/${theme}[^/]*$" | sort | head -n1)
	# If a match is not found then use the Default theme
	[ -z "$xfwm4_theme" ] && xfwm4_theme='Default'
	# Apply the xfwm4 theme
	xfconf-query -c xfwm4 -p /general/theme -n -t string -s "${xfwm4_theme#/}"
	# Apply the current theme with gsettings
	gsettings set org.gnome.desktop.interface gtk-theme "$theme"
}
sync_icon_theme() {
	# Get the current icon theme
	icon_theme=$(xfconf-query -c xsettings -p /Net/IconThemeName)
	# Apply the same theme in qt5ct and qt6ct configuration
	sed -i "s/^icon_theme=.*$/icon_theme=$icon_theme/" "$HOME"/.config/qt5ct/qt5ct.conf
	sed -i "s/^icon_theme=.*$/icon_theme=$icon_theme/" "$HOME"/.config/qt6ct/qt6ct.conf
}
while :; do
	# Get the current system theme
	theme_new=$(xfconf-query -c xsettings -p /Net/ThemeName)
	# Get the current icon theme
	icon_theme_new=$(xfconf-query -c xsettings -p /Net/IconThemeName)

	# Run sync_theme if the new system theme doesn't match the previous one
	[ "$theme_new" != "$theme_prev" ] && sync_theme
	# Run sync_icon_theme if the new icon theme doesn't match the previous one
	[ "$icon_theme_new" != "$icon_theme_prev" ] && sync_icon_theme

	# The new values become the previous values
	theme_prev=$theme_new
	icon_theme_prev=$icon_theme_new

	sleep 3
done

Save, do the drill again.

Now add it to start on boot. Edit the same .profile file from your Home, and add yet another line fix-theming &. Please reboot now.

My god…so many fixes for theming. But the result is harmony. And we managed to sync the icon theme too, across GTK and QT. Not the font yet…it is the last soldier to hold onto that territory…but we may overcome that too in the near future idk…


Conclusions and summary

Let’s keep this brief for all to understand. We managed with a few packages and a few scripts to make the following types of apps sync with each other in terms themes and icons: QT, QT5, QT6, GTK versions, GTK + Libadwaita, Flatpaks (some). This is by far the vast majority of all Linux apps out there. And all can be achieved now from XFCE’s default Appearance app. Great!

Summary:

To sync GTK with QT we need the following packages: qt5ct, qt5-styleplugins, qt6ct, qt6gtk2. In qt5ct and qt6ct we need to select the theme to follow a gtk2 style. Open them, select.

To make sure that they work even after qt5-base and qt6-base get updated, we need to create a hook and a script, that will reinstall qt5-styleplugins and qt6gtk2 after these get updated.

The script looks like this:

#!/bin/bash
rm /var/lib/pacman/db.lck  &
pacman --noconfirm -S qt5-styleplugins qt6gtk2

And you can name it anything you want. The hook looks like this:

[Trigger]
Operation = Upgrade
Type = Package
Target = qt5-base
Target = qt6-base


[Action]
Description = Reinstalling needed packages for theming QT applications...
When = PostTransaction
Exec = path-to-the-script

Add both to the proper locations. Then install the package libadwaita-without-adwaita-git to fix the Libadawaita apps.

Lastly we need a script to sync all of the changes, including the icon pack, across the entire XFCE:

#!/bin/sh
sync_theme() {
	# Get the current system theme
	theme=$(xfconf-query -c xsettings -p /Net/ThemeName)
	# Find the best match for the xfwm4 theme that corresponds with the current system theme
	xfwm4_theme=$(find /usr/share/themes/ /usr/local/share/themes/ "$HOME"/.themes/ "$HOME"/.local/share/themes/ -mindepth 2 -maxdepth 2 -type d -name xfwm4 -printf '%h\n' 2>/dev/null | grep -o "/${theme}[^/]*$" | sort | head -n1)
	# If a match is not found then use the Default theme
	[ -z "$xfwm4_theme" ] && xfwm4_theme='Default'
	# Apply the xfwm4 theme
	xfconf-query -c xfwm4 -p /general/theme -n -t string -s "${xfwm4_theme#/}"
	# Apply the current theme with gsettings
	gsettings set org.gnome.desktop.interface gtk-theme "$theme"
}
sync_icon_theme() {
	# Get the current icon theme
	icon_theme=$(xfconf-query -c xsettings -p /Net/IconThemeName)
	# Apply the same theme in qt5ct and qt6ct configuration
	sed -i "s/^icon_theme=.*$/icon_theme=$icon_theme/" "$HOME"/.config/qt5ct/qt5ct.conf
	sed -i "s/^icon_theme=.*$/icon_theme=$icon_theme/" "$HOME"/.config/qt6ct/qt6ct.conf
}
while :; do
	# Get the current system theme
	theme_new=$(xfconf-query -c xsettings -p /Net/ThemeName)
	# Get the current icon theme
	icon_theme_new=$(xfconf-query -c xsettings -p /Net/IconThemeName)

	# Run sync_theme if the new system theme doesn't match the previous one
	[ "$theme_new" != "$theme_prev" ] && sync_theme
	# Run sync_icon_theme if the new icon theme doesn't match the previous one
	[ "$icon_theme_new" != "$icon_theme_prev" ] && sync_icon_theme

	# The new values become the previous values
	theme_prev=$theme_new
	icon_theme_prev=$icon_theme_new

	sleep 3
done

And finally, to force flatpaks to sync too, we need to first enable permission for flatpaks to read the .themes folder with sudo flatpak override --filesystem=~/.themes/. Then we made this script that copies all of your system’s themes to that folder, regularly:

#!/bin/sh
while :; do
rm -r ~/.themes/* 2> /dev/null
rsync -av --progress /usr/share/themes/* ~/.themes/ --exclude Windowck
rsync -av --progress ~/.local/share/themes/* ~/.themes/ --exclude Windowck-dark
sleep 600
done

Sustainable?

The packages we use for this “fix” are in use for many years now, except maybe the qt6gtk2 and libadwaita-without-adwaita-git that are newer. Linux Mint and other distros use some of these methods too. I am confident they will be supported for a long time. The rest of the scripts are there to do some manually work in an automated fashion. That’s all. Not hacky really.

The best part is that TROMjaro comes with all of these packaged so you do not have to worry about theming. It is true, maybe at times you could find some inconsistencies, but overall everything looks great!

ENJOY!