Pinning Emacs in the KDE Launcher
KDE Top Bar and Emacs
Here's an annoying problem I ran into. I have a few apps pinned to my KDE taskbar: Firefox, Emacs, Teams, and others. The order matters because I switch between them with keyboard shortcuts: Meta+1, Meta+2, etc.
The problem: KDE couldn't figure out whether to launch emacs or emacsclient. Sometimes clicking Meta+2 would:
- Start a new Emacs instance in the pinned spot
- Start emacsclient at the end of the taskbar
- Keep spawning new instances instead of focusing the existing one
Basically, (I think) KDE got confused about whether the daemon and client were the same app. Every time I wanted to reset things, I'd have to quit Emacs entirely and start over.
To reset things back I'd have to quit my Emacs instance and restart things.
Solution
I ended up writing this .desktop file
[Desktop Entry]
Name=Emacs
Comment=GNU Emacs
Exec=emacsclient -c -a ""
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=Emacs
StartupNotify=true
I saved this to ~/.local/share/applications/emacs-custom.desktop, then pinned that to my taskbar instead of the default Emacs launcher.
The key parts:
Exec=emacsclient -c -a ""- Always use the client, start daemon if neededStartupWMClass=Emacs- Tells KDE these windows belong to the same app
Now Meta+2 behaves consistently: it either focuses the existing Emacs or starts a new one in the right spot.
Maybe I caused the issue myself and fixed it in a roundabout way. Who knows.
Plasma 6
June 2025 I was just setting up KDE (with Plasma 6) on another PC (NixOS this time around). I followed the steps above and found that... it doesn't work.
I did get it working by adapting the above slightly: instead of putting emacsclient -c -a "" in the Exec part I call out to a custom script:
# Check if the Emacs daemon is running
# Use 'emacsclient -e "(daemonp)"' to check.
# The '>/dev/null 2>&1' suppresses output and errors.
if emacsclient -e '(daemonp)' >/dev/null 2>&1; then
# Daemon is running, launch Emacs client
# -c: Create a new frame
# "$@": Pass all arguments (like filenames) to emacsclient
exec emacsclient -c "$@"
else
# Daemon is not running, launch full Emacs GUI
# "$@": Pass all arguments (like filenames) to emacs
exec emacs "$@"
fi
Important note: make sure to put %F at the end of the Exec and chmod +x the script:
[...]
Exec=/path/to/script.sh %F
[...]
- ← Previous
The Los Alamos Primer - Next →
How to mount a WSL2 disk on Linux