User Tools

Site Tools


sway:dark-mode

This is an old revision of the document!


On themes, sway, emacs and kitty - the dark-mode script

Unlike Desktop Environments like Gnome and KDE, Window Managers like sway do not come with all the tools you might need or want. It's up to the user to perceive a need, do the research and then install, configure and use the appropriate tools for the job. Notwithstanding the earnest attempts by the DE's to bury the implementation details in obscure code and non-existent documentation, this approach gives me a lean and mean working environment albeit not as pretty. Plus the satisfaction of knowing what's going on.

In my own history through fvwm, fluxbox, i3wm and now sway I've never really wanted to bother with themes. I just made terminals and emacs have a black background and other programs could do what ever they liked. Such a heathen!

Recently I felt that need and did some research into the topic. It was rather more complex and harder to discover than I had thought.

I wanted to have a simple switch I could flick, perhaps a script, that would turn night into day. Let's have black text on a bright, white background in the daytime and reverse it in the evening. I wanted to have the changes applied to running programs without restarting them.

Sounds simple? Here are some notes on what I discovered for customising and a script that I use to do the flick.

All of this is on Fedora-31.

Apologies if this is all obvious and well documented elsewhere. It was a journey for me and non-trivial.

GTK2 programs

GTK2 programs start up referring to ~/.gtkrc-2.0 for their theme hints. Simple really, just lob in a new value:

gtk-theme-name=“Adwaita”

or

gtk-theme-name=“Adwaita-dark”

The hard part was understanding how to get running programs to notice the change. lxappearance(1) is a program from the LXDE desktop environment that does both jobs. Unfortunately, it lacks a CLI interface so it can only be used in the pointy-clicky mode and not in a script.

By using strace(1) on the different components, I was able to track this down to a new (for me) system call eventfd(2) which GTK2 uses as a signalling mechanism. With a bit more research I found this script fragment at https://crunchbang.org/forums/viewtopic.php?id=39646 which invokes the correct event in the GTK2 world and makes those programs re-read ~/.gtkrc-2.0:

#!/usr/bin/python2
import sys, gtk
events=gtk.gdk.Event(gtk.gdk.CLIENT_EVENT)
data=gtk.gdk.atom_intern("_GTK_READ_RCFILES", False)
events.data_format=8
events.send_event=True
events.message_type=data
events.send_clientmessage_toall()''

GTK3 programs

GTK3 programs start up referring to ~/.config/gtk-3.0/settings.ini but the format is slightly different (of course!)

gtk-theme-name=Adwaita-dark

Note the cunning change in the use of quotation marks.

Again, getting programs that are already running to notice the change is lightly documented, if at all. But I found that by installing gnome-settings-daemon (a bit of an overkill for my lightweight purposes) there is a daemon that can do the job. So I added this to my sway config:

exec /usr/libexec/gsd-xsettings

I just wonder if this could be replaced by a simple script like the GK2 one?

But that appears to be not the entire story.

dconf

Some programs do not respond to gsd-xsettings and dconf is needed:

dconf write /org/gnome/desktop/interface/gtk-theme "'Adwaita-dark'"

Again, note the amusing change in quotation - single quotes are essential. The dconf approach also appears to work for live GTK2 programs and overrides the value in ~/.gtkrc-2.0 and ~/.config/gtk-3.0/settings.ini

gsettings

More comedy arises from yet another path to the same outcome. This invocation appears to be completely equivalent with it's own permutation on the quotation merry-go-around:

gsettings set org.gnome.desktop.interface gtk-theme Adwaita-dark

emacs

emacs. Hmmm. I've grown up with that program and am unlikely to wean myself off it. There are 'PureGTK' versions floating around as experiments but they are yet to hit the Fedora repositories outside COPR so I haven't tried them to see how they respond to the standard GTK signals.

In any case, for emacs I need to also modify the internal text areas and emacs has its own themes spelled out in elisp. I decided on a couple of good themes and added some code to my script to flip from one theme to another. The script should be self explanatory. The themes I chose were a modified dichromacy (for the colourblind) and a derived dichromacy-dark which I created by 'inverting' the original using a script at https://explog.in/notes/poet.html#monochrome

kitty

Now for my favorite wayland terminal emulator, Kitty. It has it's own unique configuration language and can have its colour changed on the fly like this:

kitty @ set_colors --all foreground=white background=black

bash

My bash prompt contains colours and I have a separate script (actually a function in ~/.bashrc) that responds appropriately to the setting of TERM_BACKGROUND in {dark,light} so my script outputs that setting and invokes setup_prompt.

eval $( dark-mode on )

… 'dark-mode on' outputs TERM_BACKGROUND=dark; setup-prompt and that's what gets eval'd.

These final 2 steps are the reason I don't put dark-mode into a cron job - it needs to run in my stack of kitty terminal tabs.

KDE

KDE/Qt5/Plasma/whatcha-ma-call-it

Here be dragons. I have NO IDEA how to script this. If you know how to script a theme change, please let me know!

dark-mode

Here is the result of all this rambling:

#!/usr/bin/env bash

# dark-mode [on|off]
# sets dark mode on or off

# best to run as:
# eval $( dark-mode on )

# for emacs, these themes can be chosen from the standard ones (in
# custom-theme-load-path) or they can be installed in
# custom-theme-directory (usually ~/.emacs.d)
# They must have a filename of $THEMENAME-theme.el

light_emacs_theme="dichromacy-bh"
light_emacs_modeline_theme="smart-mode-line-light"
#dark_emacs_theme="manoj-dark-bh"
dark_emacs_theme="dichromacy-dark-bh"
dark_emacs_modeline_theme="smart-mode-line-dark"
case "$1" in
    off|stop|reset|end|light)
        # light mode
        new_emacs_theme="$light_emacs_theme"
        prev_emacs_theme="$dark_emacs_theme"
        new_emacs_modeline_theme="$light_emacs_modeline_theme"
        prev_emacs_modeline_theme="$dark_emacs_modeline_theme"

        new_gtk_theme='Adwaita'
        new_fg='black'
        new_bg='white'
        BRIGHTNESS=100
        TERM_BACKGROUND=light
        ;;
    *)
        # dark mode
        new_emacs_theme="$dark_emacs_theme"
        prev_emacs_theme="$light_emacs_theme"
        new_emacs_modeline_theme="$dark_emacs_modeline_theme"
        prev_emacs_modeline_theme="$light_emacs_modeline_theme"

        new_gtk_theme='Adwaita-dark'
        new_fg='white'
        new_bg='black'
        BRIGHTNESS=0
        TERM_BACKGROUND=dark
        ;;
esac

(
    # look for an emacs running as this user:
    emacs_pid=$(pgrep -u $USER emacs | head -n 1)
    [[ "$emacs_pid" ]] &&
        emacsclient --eval "
          (progn
            (disable-theme '$prev_emacs_theme)
            (disable-theme '$prev_emacs_modeline_theme)
            (load-theme '$new_emacs_theme)
            (load-theme '$new_emacs_modeline_theme))"

    f=~/.gtkrc-2.0
    [[ -w $f ]] &&
        sed -i "s/^gtk-theme-name=.*/gtk-theme-name=\"$new_gtk_theme\"/" $f
    gtkreload # gtk2 only!

    f=~/.config/gtk-3.0/settings.ini
    [[ -w $f ]] &&
        sed -i "s/^gtk-theme-name=.*/gtk-theme-name=$new_gtk_theme/" $f
    # /usr/libexec/gsd-xsettings notifies gtk3 clients - start it in sway

    # these two appear to be comletely equivalent:
    dconf write /org/gnome/desktop/interface/gtk-theme "'$new_gtk_theme'"
    #gsettings set org.gnome.desktop.interface gtk-theme $new_gtk_theme

    [[ "$KITTY_WINDOW_ID" ]] &&
        kitty @ set_colors --all foreground=$new_fg background=$new_bg

    brightness $BRIGHTNESS
) >/dev/null

echo "TERM_BACKGROUND=$TERM_BACKGROUND; setup_prompt"
sway/dark-mode.1602552630.txt.gz · Last modified: 2020/10/12 19:30 by admin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki