Writing extensions for the new Gnome Shell
One of the features that includes the new Gnome Shell is the ability to create extensions. Those are plugins to add new functionalities to the Shell, or alter the default ones. It’s a natural evolution of the former panel applets, but far more powerful, since you can create almost anything you can imagine, not only these little apps for the panel.
The first thing you must know is that everything related to Shell is Javascript and CSS. Yeah, Javascript. Everybody knows Javascript, so it’s a great starting point. All we have to do to create a Shell extension is write down a JS file, create a CSS stylesheet, and it’s done. Easy, isn’t it?
Gnome Shell is a big thing, so explaining all you can do with the extensions isn’t the point of this post. For the moment, we’ll just play with the upper panel, but it’s possible to expand the Shell in many many ways. For example, you can add new sections in the Activities menu (by default only Windows and Applications are shown), add new search engines (besides the Google and Wikipedia ones), add new items in the user menu (A Shutdown menu entry, and not only the Suspend one!), and tons of other stuff. Just think about what would be great to have in the Shell, and go for it.
HOW TO CREATE AN EXTENSION?
Although it’s not mandatory to use it (you can write your extension completely from scratch), Gnome 3 includes a bash comand to help us to create new extensions: gnome-shell-extension-tool. We’ll use it to create the draft of our extension:
$ gnome-shell-extension-tool --create-extension
The command will ask us for some basic metadata:
- Name: A name for the extension.
- Description: A more detailed explanation for the extension functionality.
- Uuid: An unique identifier for the extension. It must be in a email address format, say foo@bar.com. By example, if your extension is named WorldDomination, and you work in DevilCorp Inc, a good Uuid should be world_domination@extensions.devilcorp.com.
Once you’ve filled that steps, the command will create some files in this path:
$HOME/.local/share/gnome-shell/extensions/world_domination@extensions.devilcorp.com/
Now we can edit that files to do what we want.
HOW TO LOAD THE EXTENSION?
When a user starts a Gnome session, the Shell will load all the extensions located in the following places:
~/.local/share/gnome-shell/extensions/usr/share/gnome-shell/extensions/usr/local/share/gnome-shell/extensions
But if we are developing an extension, it’s boring and time-wasting to log out and in every time we want to reload the shell. Instead of that, we can reload just the Shell, in a very easy way: Enter Alt+F2 and write “r” (reload).
OK, SHOW ME THE CODE!
If we’ve created the extension with gnome-shell-extension-tool, we can edit the extension.js file it has created:
$HOME/.local/share/gnome-shell/extensions/world.domination@extensions.devilcorp.com/extension.js
It contains a very simple extension that shows a “Hello world” message when clicking in the top bar:
// Sample extension code, makes clicking on the panel show a message
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
function _showHello() {
let text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
let monitor = global.get_primary_monitor();
global.stage.add_actor(text);
text.set_position(Math.floor (monitor.width / 2 - text.width / 2), Math.floor(monitor.height / 2 - text.height / 2));
Mainloop.timeout_add(3000, function () { text.destroy(); });
}
// Put your extension initialization code here
function main() {
Main.panel.actor.reactive = true;
Main.panel.actor.connect('button-release-event', _showHello);
}
When we reload the Shell and click the panel, we can see this:
When Gnome Shell loads the extension, it searches the main() function. In the above code, we make the panel to be responsive to events (Main.panel.actor.reactive = true;) and connect the panel’s event ‘button-release-event‘ to execute the funcion _showHello() when the user clicks the panel.
Let’s see step by step what _showHello does:
let text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
Here we create a label, with the text “Hello, world!”, and set it to use the CSS class ‘helloworld-label’. That class is defined in the ‘stylesheet.css’ file, and we can modify it if we want.
let monitor = global.get_primary_monitor();
global.stage.add_actor(text);
text.set_position(Math.floor (monitor.width / 2 - text.width / 2), Math.floor(monitor.height / 2 - text.height / 2));
Now we set the label position in the center of the main screen (we specify the main screen because we can have two or more monitors in our computer).
Mainloop.timeout_add(3000, function () { text.destroy(); });
Three seconds after the label is shown, we destroy it, so it will dissapear.
HOW CAN WE ADD ELEMENTS TO THE PANEL?
Let’s modify the extension to add a button to the panel. When the user clicks the button, the “Hello World” message will be shown.
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Lang = imports.lang;
const Main = imports.ui.main;
function PanelButton() {
this._init();
}
PanelButton.prototype = {
_init: function() {
this.actor = new St.Button();
this._label = new St.Label({ text: "HelloWorld Button" });
this.actor.set_child(this._label);
Main.panel._centerBox.add(this.actor, { y_fill: true });
this.actor.connect('clicked', Lang.bind(this, _showHello));
},
_onDestroy: function() {}
};
function _showHello() {
let text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
let monitor = global.get_primary_monitor();
global.stage.add_actor(text);
text.set_position(Math.floor (monitor.width / 2 - text.width / 2), Math.floor(monitor.height / 2 - text.height / 2));
Mainloop.timeout_add(3000, function () { text.destroy(); });
}
// Put your extension initialization code here
function main() {
let _panelButton = new PanelButton();
}
The button will be placed in the center of the panel, at the right side of the Calendar button. This is what will be shown when we load the extension and click the new button:
The _showHello() function remains the same. We’ve only changed the code to execute that function when we click on the button, instead of the panel.
HOW CAN I LEARN MORE?
It’s a really good question. Up to now, Gnome Shell has very few official documentation. But, as usual, you always can read some code, and search the Internet. In the Gnome’s GIT you can find a module called gnome-shell-extensions. These are some functional extensions, where you can learn how things work. It’s a good starting point. Read the README to get a description on what each extension does. But this lack of documentation isn’t going to be forever. I’m sure that soon there will be good documentation, as in every part of the Gnome desktop. Be aware of news in developer.gnome.org
The posibilities with Gnome Shell extensions are huge. Hurry up and create some of them!

