The Basics

Creating and Enabling your extension

To create an extension, type in a terminal

gnome-shell-extension-tool --create-extension

Name your application. For this extension, "Hello world" and press enter.

Give it a description. Something like "Show a hello world label pressing an icon in the system tray" should do.

Then you will be asked about an uuid. This is a globally-unique identifier for your extension as well as the name of your extension's folder.

UUID Guidelines

A good uuid contains something related to your email. For example, if your email is first.second1925@server.com, I recommend something like theNameOfYourExtension@first.second1925-server.com. The UUID must contain only alphanumerical characters, the period (.), the at symbol (@), the underscore (_), and the dash (-). Unicode characters are not allowed. Your extension must not end with gnome.org. Extensions are not affiliated with GNOME and must not appear to be.

In this case "helloWorld@email.com" and press enter.

A "Hello World" example should appear in your IDE, gedit or your Browser if all else fails.

Open the gnome-tweak-tool and enable your extension in the extensions tab.

Debugging your Extension

The main debugging tool is, in a terminal :

gnome-shell --replace

" Be careful to not close this terminal or you will crash your desktop "

LookingGlass

The LookingGlass can give you some well needed informations too. To open it, Alt+F2 and type lg. It is divided into the following tabs:

  • Evaluator : here you can evaluate random javascript code, accesing gnome shell objects and libraries. For example, write this in the evaluator and press enter:

Main.notify("Hello world")
  • Also, in the Evaluator tab, you have a "picker" in the left corner. Click on it, Then "pick" random object of the interface of the gnome shell to know its name. This is useful if you are trying to know "where" the object you are seeing is in the class hierarchy of the gnome shell and what kind of object it is.
  • Windows : where you can see wich windows are currently active. Pay attention to wmclass. This name let you identify an application inside gnome.
  • Extensions : will tell you wich extensions are installed and some other information about each extension as well as opening their source code.

Restarting your shell and Applying changes

  • To apply changes made to your extension, save your file, press Alt-F2 and type r (or restart).
  • " If you crash your shell "

Chill. Press Ctrl+Alt+F2. Get a command line. Go to your extension's directory,

cd  ~/.local/share/gnome-shell/extensions/<yourExtension>

and modify your code accordingly.

sudo nano extension.js

Than restart your shell :

DISPLAY=:0 gnome-shell

and CTRL+ALT+F7 or CTRL+ALT+F8.

Anatomy of an Extension

Your extension's folder

~/.local/share/gnome-shell/extensions/helloWorld@email.com

There are 3 files in this folder :

  • extension.js : the javascript code for your extension, the focus of this tutorial.
  • metadata.js : {name, description, uuid, gnome-version } and store the data you need across sessions in JSON format.
  • stylesheet.css : CSS to style your UI components.

Organizing extension.js

  • Imports and Constants :

const St = imports.gi.St;

const IMPORTANT_VARIABLE = 1;
  • Your actual extension. In this case Class Inheritance :

const Lang = imports.lang

const New_Class = new Lang.Class({
        Name: 'new class',
        Extends: Old_class,

                _init: function() {do something};
});
  • Your extension HAS to have the following three function to work :

function init(){};   // Don't do anything major here, initialize settings for example.
function enable(){}; // Activate your extension.
function disable(){}; // You have to disable everything you have done.

Hello World Code Sample

Here is the annotated hello world example your should get everytime you create an extension:

   1 /*
   2 In this example we will click on a button in the top bar,
   3 causing an event that create a text label (hello world), which with some
   4 animation, will be decreasing its opacity from 100% to 0%
   5 */
   6 
   7 
   8 /*Import St, this is the library that allows you to create UI elements */
   9 const St = imports.gi.St;
  10 
  11 /*Import Main, the instance of the class that have all the UI elements loaded
  12 as we have to add to the Main instance our UI elements */
  13 const Main = imports.ui.main;
  14 
  15 /*Import tweener for the animations of the UI elements */
  16 const Tweener = imports.ui.tweener;
  17 
  18 /* Initialising global variables to use as button to click and a text label.*/
  19 let text, button;
  20 
  21 /* Function to call when the label is opacity 0%. As the label remains an
  22 UI element, but not visible, we have to delete it explicitily. When
  23 the label reaches 0% opacity, we remove it from the Main instance.*/
  24 function _hideHello() {
  25     Main.uiGroup.remove_actor(text);
  26     text = null;
  27 }
  28 
  29 function _showHello() {
  30     /* If the text is not already present, we create a new UI element using the St library.
  31     REFERENCE: http://developer.gnome.org/st/stable/ */
  32     if (!text) {
  33         text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
  34         Main.uiGroup.add_actor(text);
  35 }
  36 
  37 text.opacity = 255;
  38 
  39 /* We have to choose the monitor we want to display the hello world label.
  40 Here we use the primary monitor*/
  41 let monitor = Main.layoutManager.primaryMonitor;
  42 
  43 /*we change the position of the text to the center of the monitor.*/
  44 text.set_position(Math.floor(monitor.width / 2 - text.width / 2),
  45                   Math.floor(monitor.height / 2 - text.height / 2));
  46 
  47 /* Using tweener for the animations, we set the opacity at 0% after 2 seconds,
  48 with the type of transition easeOutQuad. When this animation is completed,
  49 we execute our function _hideHello.
  50 REFERENCE: http://hosted.zeh.com.br/tweener/docs/en-us/ */
  51 Tweener.addTween(text, { opacity: 0,
  52                    time: 2,
  53                    transition: 'easeOutQuad',
  54                    onComplete: _hideHello });
  55 }
  56 
  57 /*This where we initialize our extension.
  58 we have to be careful with init(), enable() and disable() and do the right things here.
  59 REFERENCE: http://blog.mecheye.net/2012/02/requirements-and-tips-for-getting-your-gnome-shell-extension-approved/ */
  60 function init() {
  61     /*We create a button for the top panel. We pass to the constructor a map of properties, properties from St.bin and its
  62 parent classes, stWidget. A style class (from the css theming of gnome shell), we make it reactive to mouse clicks, we mark the button as being able to receive keyboard focus via keyboard navigation. The button will fill the x space, and we don't want to fill the y space, so we set the values true and false respectively.We want the button to be reactive on the hover of a mouse, so we set the value of the track_hover property to true. */
  63     button = new St.Bin({ style_class: 'panel-button',
  64                           reactive: true,
  65                           can_focus: true,
  66                           x_fill: true,
  67                           y_fill: false,
  68                           track_hover: true });
  69     /* We create an icon with the "system-status-icon" icon and give it the name "system-run" */
  70     let icon = new St.Icon({ icon_name: 'system-run',
  71                              style_class: 'system-status-icon' });
  72     /*we set the icon as a child of the button. In the structure of actors we have the icon inside the button that is a
  73     container. */
  74     button.set_child(icon);
  75     /*we connect the actor signal "button-press-event" of the button to the funcion _showHello. In this manner,
  76     when we press the button, this signal is emitted, we capture it and execute the _showHello function. */
  77     button.connect('button-press-event', _showHello);
  78 }
  79 
  80     /* We have to write here our main extension code and the things that actually make the extension (Add ui elements, signals, etc). */
  81 function enable() {
  82     /* We add the button we created before to the rigth panel of the top panel (where the sound and wifi settings are) */
  83     Main.panel._rightBox.insert_child_at_index(button, 0);
  84 }
  85 
  86 /*We have to delete all conections and things from our extensions, to let the system how it was before our extension. So
  87 we have to unconnect the signals we connect, we have to delete all UI elements we created, etc. */
  88 function disable() {
  89     /* we remove the button from the right panel */
  90     Main.panel._rightBox.remove_child(button);
  91 }

Projects/GnomeShell/Extensions/EcoDoc/FirstExtension (last edited 2017-05-06 05:11:51 by Fulleco)