Writing a simple task Applet for Cinnamon Desktop

Pressing Ctrl+F11 will call the script, which will switch the audio device and send a nice little notification.

Taking it Up a NotchI was actually using the above script in my workflow for a while, but it felt like something was missing.

I wanted to have an indicator of which device was currently selected, as well as the ability to switch devices with a mouse click.

The system tray seemed to be the best fit for this.

For a while I tried searching for tutorials on writing applications that sit in the system tray on Cinnamon, with surprisingly little results.

Eventually I realized why: system tray applications on Cinnamon have a name: Applets.

Writing Our First AppletAs a user, I’ve been really happy with Cinnamon so far.

It’s simple, beautiful, and customizable.

As a developer, on the other hand, I’ve been extremely frustrated with it.

Cinnamon is a fork of Gnome.

Because of this, it inherits a lot of functionality from it.

This is a good thing: Gnome is very well documented (with some notable exceptions) and popular, which makes it relatively welcoming to newcomers like myself.

The problem is that Cinnamon’s diversions from Gnome are not well documented and were, at least for me, very hard to track down, or in some cases non-existent.

They do provide a quick tutorial on how to write a simple Applet.

I used this as a jumping off point to start tinkering.

Even more helpful was this blog post by Eli Billauer.

With these resources I was able to make an Applet that, when clicked in the system tray, would run the same commands as our script above.

The two necessary files are metadata.

json and applet.

js.

Here is what my first applet.

js looked like:When the Applet is clicked, the on_applet_clicked() function is called.

From there I call the helper functions switchDevices() and updateIcon().

Where Cinnamon’s basic Applet tutorial started to break down for me was when I needed to capture the output of a system command, namely pactl, to get the current output device.

Cinnamon’s util library doesn’t provide such a thing, so I had to look at the underlying implementation and use GLib commands directly.

Note: using GLib’s spawn_command_line_sync() is one of a few functions that will cause a warning to appear when you try to install your applet, claiming that it could cause issues with Cinnamon.

I found this to be accurate when some commands I was running went longer than expected, causing the entire desktop to hang.

You can also see that I’m setting the icon based on the current output device.

As mentioned in Cinnamon’s tutorial, the icon name references installed icons in /usr/share/icons.

I found the icons audio-headphones and multimedia-volume-controlto be good analogs for headphones and speakers respectively.

Note that I’m using symbolic icons because system tray icons should be simple and monochrome.

The Applet can be installed from the Applets menu, after which it will appear in the system tray.

All in all, the above code is not too different from Cinnamon’s example Applet.

It’s an IconApplet that performs an action when clicked.

We’re done, right?Applets and SignalsAt this point I was pretty happy with my first Applet.

It did a thing when clicked, it was snappy, it had pretty icons that updated properly.

There were just two problems:The Applet itself isn’t triggered by a keyboard shortcut.

If I leave the old script hooked up to the keyboard shortcut, the Applet icon will get out of sync.

Now, I won’t tell you how much time I spent trying to figure out how to get Applets to respond to global keyboard shortcuts.

Suffice it to say I tried a lot of different ways and was extremely frustrated by the time I finally came up with a solution.

The Eureka!.moment happened when I was scouring the code of the built-in Sound Applet.

I was looking there because the volume icon changes according to the current volume setting; it must have a connection to the system, keyboard or otherwise!.I came across these lines of code:this.

_sound_settings = new Gio.

Settings({ schema_id: CINNAMON_DESKTOP_SOUNDS });this.

_sound_settings.

connect("changed::" + MAXIMUM_VOLUME_KEY, Lang.

bind(this, this.

_on_sound_settings_change));Let’s break this down.

Arguably the most important part of these lines is the connect function call.

Gnome and GTK use Signals to allow any object to trigger events on any other object, without the emitter needing to know anything about the receiver.

I’ve done some work with Qt so this concept was familiar to me.

You’ll notice in Gnome and Cinnamon documentation that many objects have a list of Signals just like they have a list of Properties and Functions.

That’s what we’re going to take advantage of.

What is the Sound Applet connecting to?.GSettings.

Gio.

Settings allows me to connect my Applet to the changed signal of a GSettings key.

This is the connection I needed!This was my new plan: Connect the Applet to a GSettings key of my own creation and update the device and icon when the setting changes.

Let’s do it!Creating A GSettings SchemaIn order to compile my GSettings schema, I needed to create a .

gschema.

xml file in /usr/share/glib-2.

0/schemas.

Here’s what mine looks like:The id and path properties of the schema should be unique.

The convention for id is to use your reversed domain name followed by a unique identifier for your schema.

The same content can be used for path, except using slashes as separators.

Note that path must end in a trailing slash.

I’ve specified the setting called device of type string (hence the "s").

Once that was in place, I needed to tell GLib to re-compile the schemas:glib-compile-schemas /usr/share/glib-2.

0/schemasOnce that was done I could use the setting in my Applet.

Refactoring the Applet to Use GSettingsNow that I had set up GSettings, I could refactor my Applet.

I connected it to a Gio.

Settings object pointing to my newly created schema.

When the Applet is clicked, instead of running the commands explicitly, it will simply flip the settings value and let the event flow pick it up.

That will ensure that, no matter where the change is made, it will always be picked up by the Applet.

Now the Applet does the same thing it did before, except now it does it by receiving a signal from our GSettings object.

So, what’s left?Activating the Applet by Keyboard ShortcutAll I had left to do was to use a keyboard shortcut to trigger the settings change.

Since I already had Ctrl+F11 wired to a bash script, I simply modified the script to use the gsettings CLI to make the change.

That’s it!.Now I can switch my audio output device by either clicking the icon in the system tray or using the key combination.

In both cases an icon will be updated and a notification will be shown.

Mission accomplished!The complete code can be found on GitHub.

.

. More details

Leave a Reply