Egy korábbi bejegyzésben már írtam a GNOME Shellről általánosságban, most egy saját kiegészítő elkészítésével fogok foglalkozni. Ezek, bár a jól ismert JavaScript íródnak, elég nehezen kezelhetőek, ugyanis a shellben elérhető függvényekhez és erőforrásokhoz szinte semmilyen dokumentáció nem készült.
Ennek telepítése:
Egyedi azonosító birtokában a GNOME Shell egy segédparancsa létrehozza az alkalmazást:
Name: Az alkalmazás ember által olvasható neve (Hello Világ)
Description: Egymondatos leírás (Első Shell kiegészítőm)
Uuid: A korábbiakban tárgyalt egyedi azonosító (helloworld@webgyerek.net)
A válaszok megadása után A GNOME Shell Extension Tool egy Helló Világ programot készít az összes szükséges fájllal együtt. Az új kiegészítő kipróbálásához engedélyezni kell azt, majd a újratölteni a GNOME Shellt:
extension.js
Ebben található a kiegészítő JavaScript kódja. A tartalmazott kód kerül programkódként felhasználásra ha a kiegészítőt bekapcsolják.
metadata.json
Ebben a fájlban találhatóak a kiegészítő adatai, például (a létrehozáskor parancssorban megadottak), valamint néhány más beállítás és tulajdonság, mint például a GNOME Shell verziószáma amivel a kiegészítő működik.
stylesheet.css
Ha a kiegészítő használ valamilyen egyedi elemet, akkor ebben a fájlban tárolható a hozzá tartozó megjelenés és formázás. Ha nincs ilyen, ez a fájl nem kötelező.
Az extensions.js programfájlnak 3 függvényt kötelező tartalmaznia ahhoz hogy a kiegészítő üzemképes legyen.
Az init() függvény akkor fut le amikor a kiegészítő először betöltődik a shellbe. Ebben kell elhelyezni azokat a műveleteket amik előkészítik a kiegészítőnek szükséges dolgokat, de nem változtatnak sem a megjelenésen, sem a működésen.
Az enable() függvény akkor fut le, amikor a kiegészítőt bekapcsolják. Ez mindig később történik mint az init() lefutása. Ebben kell elhelyezni azokat a kódokat amik módosítják a megjelenést vagy a működést.
A disable() függvény pedig akkor kerül futtatásra, amikor kikapcsoljásra kerül a kiegészítő. Minden változtatást el kell tüntetnie amit az enable() végzett.
A Shell a felület megrajzolásához mindenhol egy Clutter nevű alprogramot használ, ennek segítségével egy 2.5D térben helyezhetőek el elemek. Minden elem egy ún. actor, olyasmi mint a weben egy div blokk. Ezeknek vannak fajtái, és egyeseknek lehet további tartalma (szöveg, ikon, vagy újabb actor) valamint vannak tulajdonságaik (méret, kattinthatóság, ...).
A legfontosabb hogy minden aktornak van egy connect metódusa, amivel különböző eseményekhez rendelhetőek saját JavaScript függvények futtatásai.
Sajnos (a cikk írásakor) a Clutterhez semmilyen a JavaScript felületet bemutató leírás nincs. Elvileg a működés és a metódusok ugyan azok mint C nyelven, úgyhogy az eredeti Clutter dokumentáció használható, több kevesebb sikerrel. A feladatot bonyolítja hogy a kiegészítők valójában nem a Clutterrel dolgoznak.
A GNOME csapat készített egy újabb virtuális réteget, ami a kiegészítő JavaScript kódokon kívül automatikusan alkalmazza a CSS tulajdonságokat is az actorokon. Erre a rétegre St-ként hivatkoznak a kódokban. A több dokumentálatlan közvetítőt rétegnek köszönhetően, végeredményben legegyszerűbb a kész kódokból kitapasztalni az actorok működését. Ehhez viszont van segítség, ugyanis a Shell felülete ugyanazon a nyelven íródott mint a kiegészítők. A kódok áttekintéséhez a /usr/share/gnome-shell/js/ui mappát lehet érdemes tanulmányozni.
A "Helló Világ!" kiegészítő forráskódja, amit az érthetőség kedvéért megjegyzésekkel egészítettem ki:
Kompatibilitás
A GNOME csapat a Shell fejlesztése közben több visszafelé nem kompatibilis változtatást vezetett be. A 3.1 és a 3.4-es verzió között alapvető változások történtek a kiegészítők által használt kódokban. Ebben a leírásban végig a GNOME Shell 3.4.1-es, az Ubuntu 12.04 LTS által szállított változatát fogom használni.Ennek telepítése:
sudo apt-get install gnome-shell gnome-shell-common gnome-tweak-tool
Első lépések
A felhasználók saját GNOME Shell kiegészítői a saját mappájukban, a ~/.local/share/gnome-shell/extensions helyen találhatóak. Minden kiegészítőnek szüksége van egy egyedi névre úgynevezett UUID-re. Ennek a formája e-mail cím szerű: alkalmazásneve@a_fejlesztő_saját_egyedi_kódja. Én a helloworld@webgyerek.net azonosítót használom.Egyedi azonosító birtokában a GNOME Shell egy segédparancsa létrehozza az alkalmazást:
gnome-shell-extension-tool --createA következő kérdéseket teszi fel:
Name: Az alkalmazás ember által olvasható neve (Hello Világ)
Description: Egymondatos leírás (Első Shell kiegészítőm)
Uuid: A korábbiakban tárgyalt egyedi azonosító (helloworld@webgyerek.net)
A válaszok megadása után A GNOME Shell Extension Tool egy Helló Világ programot készít az összes szükséges fájllal együtt. Az új kiegészítő kipróbálásához engedélyezni kell azt, majd a újratölteni a GNOME Shellt:
gnome-shell-extension-tool -e helloworld@webgyerek.netA shell legegyszerűbben az <ALT>+F2 futtatás ablakba r betűt írva és entert ütve indítható újra. Az alkalmazásaink nem fognak bezáródni, csak a Shell tölt be ismét. A GNOME Shellben a jobb felső sarokban (a hang ikontól balra) megjelenik két fogaskerék, rájuk kattintva pedig a Hello, world! szöveg villan fel szürke dobozban a képernyő közepén. Ha ki akarnánk kapcsolni a kiegészíőnket akkor a következő paranccsal megtehetjük. Utána szintén újratöltés lehet szükséges.
gnome-shell-extension-tool -d helloworld@webgyerek.net
Kiegészítők felépítése
Az új kiegészítő a felhasználói kiegészítők között található: ~/.local/share/gnome-shell/extensions/helloworld@webgyerek.net (Az UUID a létrehozáskor megadott!) A mappa teljes tartalmával együtt maga a kiegészítő. A következő fájlok találhatóak benne:extension.js
Ebben található a kiegészítő JavaScript kódja. A tartalmazott kód kerül programkódként felhasználásra ha a kiegészítőt bekapcsolják.
metadata.json
Ebben a fájlban találhatóak a kiegészítő adatai, például (a létrehozáskor parancssorban megadottak), valamint néhány más beállítás és tulajdonság, mint például a GNOME Shell verziószáma amivel a kiegészítő működik.
stylesheet.css
Ha a kiegészítő használ valamilyen egyedi elemet, akkor ebben a fájlban tárolható a hozzá tartozó megjelenés és formázás. Ha nincs ilyen, ez a fájl nem kötelező.
Az extensions.js programfájlnak 3 függvényt kötelező tartalmaznia ahhoz hogy a kiegészítő üzemképes legyen.
Az init() függvény akkor fut le amikor a kiegészítő először betöltődik a shellbe. Ebben kell elhelyezni azokat a műveleteket amik előkészítik a kiegészítőnek szükséges dolgokat, de nem változtatnak sem a megjelenésen, sem a működésen.
Az enable() függvény akkor fut le, amikor a kiegészítőt bekapcsolják. Ez mindig később történik mint az init() lefutása. Ebben kell elhelyezni azokat a kódokat amik módosítják a megjelenést vagy a működést.
A disable() függvény pedig akkor kerül futtatásra, amikor kikapcsoljásra kerül a kiegészítő. Minden változtatást el kell tüntetnie amit az enable() végzett.
A forráskód
A kiegészítő forrásának elkészítéséhez természetesen tudni kell, hogyan működik a GNOME Shell felülete. Sajnos ez meglehetősen aluldokumentált:A Shell a felület megrajzolásához mindenhol egy Clutter nevű alprogramot használ, ennek segítségével egy 2.5D térben helyezhetőek el elemek. Minden elem egy ún. actor, olyasmi mint a weben egy div blokk. Ezeknek vannak fajtái, és egyeseknek lehet további tartalma (szöveg, ikon, vagy újabb actor) valamint vannak tulajdonságaik (méret, kattinthatóság, ...).
A legfontosabb hogy minden aktornak van egy connect metódusa, amivel különböző eseményekhez rendelhetőek saját JavaScript függvények futtatásai.
Sajnos (a cikk írásakor) a Clutterhez semmilyen a JavaScript felületet bemutató leírás nincs. Elvileg a működés és a metódusok ugyan azok mint C nyelven, úgyhogy az eredeti Clutter dokumentáció használható, több kevesebb sikerrel. A feladatot bonyolítja hogy a kiegészítők valójában nem a Clutterrel dolgoznak.
A GNOME csapat készített egy újabb virtuális réteget, ami a kiegészítő JavaScript kódokon kívül automatikusan alkalmazza a CSS tulajdonságokat is az actorokon. Erre a rétegre St-ként hivatkoznak a kódokban. A több dokumentálatlan közvetítőt rétegnek köszönhetően, végeredményben legegyszerűbb a kész kódokból kitapasztalni az actorok működését. Ehhez viszont van segítség, ugyanis a Shell felülete ugyanazon a nyelven íródott mint a kiegészítők. A kódok áttekintéséhez a /usr/share/gnome-shell/js/ui mappát lehet érdemes tanulmányozni.
A "Helló Világ!" kiegészítő forráskódja, amit az érthetőség kedvéért megjegyzésekkel egészítettem ki:
//Az összes szükgéses lib betöltéseA kód JavaScript, de a webhez képest felmerül egy szembetűnő újdonság: A kiegészítőkben nem a var kulcsszóval lehet definiálni változókat, az ilyenek ugyanis az egész Shellben elérhetőek lesznek. Helyette a let szóval definiálhatóak, ami csak az éppen aktuális blokkban és annak alblokkjaiban teszi őket elérhetővé. A JavaScript nyelvhez a GNOME csapat ezt a Mozillás leírást javasolja.
const St = imports.gi.St; //Ez az aktorok fölé húzott, CSS-t alkalmazó réteg
const Main = imports.ui.main; //Ebben vannak a Shell alapelemei (felső panel, monitorok, dash, stb)
const Tweener = imports.ui.tweener; //Ezzel a segéddel lehet animációkat készíteni
let text, button; // A text és a button az egész kiegészítőben elérhető közös változók
function _hideHello() { //Ez a függvény fogja letörölni a "Hello, world!" felirat actorát
Main.uiGroup.remove_actor(text); //Letöröli a címkét a monitorról
text = null; //És megszünteti a létezést (hogy új kattintásnál újragyártsa majd)
}
function _showHello() { //Ez a függvény rajzolja ki a "Hello, world!" felirat actorát
//Ezek a részek új Helló feliratot csinálnak. Ha éppen még látszik, nem futnak le
if (!text) {
//Ha épp nincs felirat, készít egyet
//Ez egy címke típusú actor lesz
text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
Main.uiGroup.add_actor(text); //Hozzáadja a címkét a monitorhoz
}
//Ezek a részek az animációt állítják, minden kattintáskor lefutnak, hogy újra kezdődjön.
text.opacity = 255; //Actor kezdeti átlátszósága
let monitor = Main.layoutManager.primaryMonitor; //Elsődleges monitor beszerzése
//Elhelyezzi a címkét a monitor közepére
text.set_position(Math.floor(monitor.width / 2 - text.width / 2),
Math.floor(monitor.height / 2 - text.height / 2));
//Lefuttatja az animációt, az animáció végén meghívja a _hideHello-t
Tweener.addTween(text,
{ opacity: 0,
time: 2,
transition: 'easeOutQuad',
onComplete: _hideHello });
}
function init() { //Kötelező függvény, lásd a leírásban
//Készít egy új gombot két aktorból (ez lesz a két fogaskerék gombja)
//A külső aktor (St.Bin) lesz a gomb, készít egy másik actort, amiben az ikon van
button = new St.Bin({ style_class: 'panel-button',
reactive: true,
can_focus: true,
x_fill: true,
y_fill: false,
track_hover: true });
let icon = new St.Icon({ icon_name: 'system-run',
icon_type: St.IconType.SYMBOLIC,
style_class: 'system-status-icon' });
button.set_child(icon); //Beletesszi az ikont a gombba
button.connect('button-press-event', _showHello); //Kattintásra történjem meg a _showHello
}
function enable() { //Kötelező függvény, lásd a leírásban
//Beszúrja a gombot a jobb oldali doboz 0. helyére (itt van a fogaskerék ikonos gomb)
Main.panel._rightBox.insert_child_at_index(button, 0);
}
function disable() { //Kötelező függvény, lásd a leírásban
//Kitöröli a gombot a helyéről
Main.panel._rightBox.remove_child(button);
}