Continue writing the GNOME Shell extension article

This commit is contained in:
Gergely Polonkai 2015-09-28 23:55:11 +02:00
parent 2b14481253
commit 8eeb6f6351

View File

@ -3,9 +3,11 @@ layout: post
title: "Writing a GNOME Shell extension" title: "Writing a GNOME Shell extension"
--- ---
I could not find a tutorial on how to write a GNOME Shell extension, I could not find a good tutorial on how to write a GNOME Shell
but I wanted to create one for my SWE GLib library to show the current extension. There is a so called step by step instruction list on how
positions of the planets. So I dug into existing (and working) to do it, but it has its flaws, including grammar and clearance. As I
wanted to create an extension for my SWE GLib library to show the
current position of some planets, I dug into existing (and working)
extensions source code and made up something. Comments welcome! extensions source code and made up something. Comments welcome!
--- ---
@ -23,10 +25,11 @@ top-right “Activities” button) are actors on this stage. You can add
practically anything to the Shell panel that you can add to a Clutter practically anything to the Shell panel that you can add to a Clutter
stage. stage.
The other thing to remember is the lifecycle of a Shell extension. There The other thing to remember is the lifecycle of a Shell
are two methods here: either you use an extension controller, or plain extension. After calling `init()`, there are two ways forward: you
old Javascript functions `enable()` and `disable()`; I will go on with either use a so called extension controller, or plain old JavaScript
the former method. functions `enable()` and `disable()`; I will go on with the former
method for reasons discussed later.
## Anatomy of an extension ## Anatomy of an extension
@ -35,6 +38,8 @@ The only thing you actually need is an `init()` function:
function init(extensionMeta) { function init(extensionMeta) {
// Do whatever it takes to initialize your extension, // Do whatever it takes to initialize your extension,
// like initializing the translations. // like initializing the translations.
// Then return the controller object
return new ExtensionController(extensionMeta); return new ExtensionController(extensionMeta);
} }
@ -53,7 +58,9 @@ extension is unloaded, the `disable()` method gets called.
enable: function() { enable: function() {
this.extension = new PlanetsExtension(this.extensionMeta); this.extension = new PlanetsExtension(this.extensionMeta);
Main.panel.addToStatusArea("planets", this.extension, 0, "right"); Main.panel.addToStatusArea("planets",
this.extension,
0, "right");
}, },
disable: function() { disable: function() {
@ -66,12 +73,11 @@ extension is unloaded, the `disable()` method gets called.
} }
This controller will create a new instance of the `PlanetsExtension` This controller will create a new instance of the `PlanetsExtension`
class and add it to the panels right side when loaded. Upon unloading, class and add it to the panels right side when loaded. Upon
the extensions actor gets destroyed, together with the extension unloading, the extensions actor gets destroyed (which, as you will
itself. Also, for safety measures, the extension is set to `null`. see later, gets created behind the scenes, not directly by us),
together with the extension itself. Also, for safety measures, the
As you will see soon, `extension.actor` is not created by us, but behind extension is set to `null`.
the scenes by the Shell.
## The extension ## The extension
@ -95,28 +101,34 @@ PlanetsExtension.prototype = {
this.actor.add_actor(this.panelContainer); this.actor.add_actor(this.panelContainer);
this.actor.add_style_class_name('panel-status-button'); this.actor.add_style_class_name('panel-status-button');
this.panelLabel = new St.Label({text: 'Loading', y_align: Clutter.ActorAlign.CENTER}); this.panelLabel = new St.Label({
text: 'Loading',
y_align: Clutter.ActorAlign.CENTER
});
this.panelContainer.add(this.panelLabel); this.panelContainer.add(this.panelLabel);
} }
}; };
``` ```
The only parameter passed to the parents `_init` function is Here we extend the Button class of panelMenu, so we will be able to do
some action upon activate.
The only parameter passed to the parents `_init()` function is
`menuAlignment`, with the value `0.0`, which is used to position the `menuAlignment`, with the value `0.0`, which is used to position the
menu arrow. (_Note: I cannot find any documentation on this, but it menu arrow. (_Note: I cannot find any documentation on this, but it
seems that with the value `0.0`, a menu arrow is not added._) seems that with the value `0.0`, a menu arrow is not added._)
## Loading up the extension ## Loading up the extension
Now with the correct import lines added: Now with all the necessary import lines added:
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const St = imports.gi.St; const St = imports.gi.St;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
The only thing to create now is the `metadata.json` file. It contains The only thing to create now is the `metadata.json` file, which
compatibility information and, well, some meta data. contains compatibility information and, well, some meta data.
{ {
"shell-version": ["3.18"], "shell-version": ["3.18"],
@ -125,8 +137,8 @@ compatibility information and, well, some meta data.
"description": "Display current planet positions" "description": "Display current planet positions"
} }
As soon as this file is ready, you can restart your Shell (Alt-F2, enter As soon as this file is ready, you can restart your Shell (press
the command `r`), and load the extension with e.g. the GNOME Tweak Tool. Alt-F2 and enter the command `r`), and load the extension with
e.g. the GNOME Tweak Tool. You will see the Planets button on the
This little label showing the static text “Planets” is pretty boring, so right. This little label showing the static text “Planets”, however,
lets add some content. is pretty boring, so lets add some action.