Tuesday 13 June 2017

Gnome Desktop -- Terminal icon wars

I have recently switched my default desktop environment to Ubuntu Gnome as part of our ongoing dogfooding program.  First impressions are good.  As always different is confusing and I keep hitting buttons that used to do one thing and get another; 5 years with one desktop will do that to a man.

As a consummate command-line junkie I really use my desktop environment to hold my terminal windows, lots of them.  It is really important my desktop environment will sensibly collate them; sensibly to me.  I use a lot of command line tools for email, IRC etc.  Those are necessarily hosted in terminal windows but not semantically terminal windows.  I want them to be grouped together away from actual terminals and preferably they should have my preferred icons.

I am pleased to say I have been able to persuade Gnome of my predilections.  It has been a long and frustrating journey.  I have to thank Laney for his support in this endeavour, for answering interminable IRC questions and stopping me from sticking a fist through my screen.

Gnome Terminal

The default terminal application in Gnome is Terminal (gnome-terminal to me).  This has lots of nice sounding options which ought to let me have the control I want.  It supports the --class option to set the window manager class.  In the X11 world this is meant to tell the window manager the type of window this is and it is common to use that to group windows.  Great:
gnome-terminal --class weechat -- weechat
Of course nothing is ever simple.  gnome-terminal is now smart, starting a server which spawns new windows for you thus defeating the window manager class option.  After some playing and a lot of whining at people further down the road they pointed me to the --app-id option allowing me to separate instances by use case with a server for each.  After some work (and getting a bug fixed in the Ubuntu gnome-terminal wrapper) I was able to use those two in combination:
gnome-terminal --app-id com.example.Terminal.weechat \
    --class weechat -- weechat
Now my windows are separated and grouped in the alt-TAB popup.  Sadly they are all called gnome-terminal.

Gnome Dash

In order to distinguish the various otherwise visually identical Terminal icons with their associated terminal windows I wish to have specific icons for each group.  Icons are determined by the .desktop file for the application.  So first we have to create one for each class:
[Desktop Entry]
Encoding=UTF-8
Name=my-weechat
Comment=Chat with other people using Internet Relay Chat
Exec=gnome-terminal --app-id org.shadowen.Terminal.my-weechat --class my-weechat --hide-menubar --title Weechat
Icon=weechat
Terminal=false
Type=Application
Note that you want the Name= attribute to be unique in space and time otherwise it will associate your windows with another application (likely with the same icon) but not with your command and generally make your head hurt.  This had me going for an hour as one of my groups was fine (the name happened to be unique) and the other not.

This file tells the launcher which icon to associate with this application.  You need to drop that into your personal applications directory ($HOME/.local/share/applications) for Gnome to know about it.  Now you can start this new application from the overview search box.  You can also drag that icon from the searcher to the Gnome Dash to have it clickable.  Nice.  Now I have my windows grouped on alt-TAB with the specified name underneath and the appropriate icon.  Win!

This seemed to work for a while, until it stopped working and they all went back to being named gnome-terminal and using the original Terminal icon in alt-TAB.  Arrgggh.

Startup Notification Protocol

After much reading around the subject it seems I was hitting a race so that the Gnome Launcher was having to guess which window was associated with the applications it knew.  As these are all Terminal windows Gnome felt at liberty to associate them with that application even though it did correctly group them by class.  This happens as launching an application is a fire-and-forget process and finding the windows which were spawned by the started application rather than something that happened to start around that time is hard.  To sort this out there is a protocol which allows the newly started application to communicate with the window-manager to tell it that this window is that application.  In Gnome these are defined using the StartupNotify= and StartupWMClass= attributes:
StartupNotify=true
StartupWMClass=my-weechat
With these set to match the class used by gnome-terminal the Gnome Launcher was able to reliably associate the new windows with the appropriate icon but in the Gnome Dash and in the alt-TAB window.

Complete Example

Here is the final complete desktop entry:
[Desktop Entry]
Encoding=UTF-8
Name=my-weechat
Comment=Chat with other people using Internet Relay Chat
Exec=gnome-terminal --app-id org.shadowen.Terminal.my-weechat --class my-weechat --hide-menubar --title Weechat
Icon=weechat
Terminal=false
Type=Application
StartupNotify=true
StartupWMClass=my-weechat

Result 

Finally I have windows grouped under the appropriate icons every time.  Nice.