Dopo qualche settimana di smanettamenti (e smadonnamenti!) vari sono riuscito ad ottenere qualche prototipo funzionante di desklet per cinnamon.
La prima cosa che mi viene da dire è che è veramente difficile riuscire a raccapezzarsi tra tutte le librerie usabili, quali sono le funzioni e come si usano!
Questo perchè il linguaggio usato per l'implementazione dei desklet è il JavaScript, mentre la documentazione delle librerie richiamabili è generata dal codice C, con la possibilità di essere richiamate da codice python o altri linguaggi. Come si immagina la situazione è veramente complessa.
La storia è che sono state inventate delle interfacce per chiamare queste librerie scritte in C dal JavaScript (o da altri linguaggi), raccolte sotto il nome di GObject Introspection.
La documentazione di queste librerie segue lo standard C, per cui ad esempio la funzione
ClutterActor *gtk_clutter_embed_get_stage (GtkClutterEmbed *embed
);
va invocata in JavaScript come
const GtkClutter = imports.gi.GtkClutter;this._clutterEmbed = new GtkClutter.Embed();
this._gtkEmbedActor = this._clutterEmbed.get_stage();
per cui la prima parte del nome della funzione gtk_clutter rappresenta la libreria da importare: GtkClutter; mentre l'oggetto GtkClutterEmbed diventa GtkClutter.Embed; e l'ultima parte del nome della funzione rappresenta come va chiamata la funzione (get_stage); tra l'altro in C non ci sono gli oggetti mentre in JavaScript la funzione viene invocata sull'istanza (this._clutterEmbed).
Documentazione
Un ottimo post che spiega una desklet di tipo hello world è disponibile qui.
Una fonte preziosa di informazioni è quella ufficiale di linuxmint (i creatori di Cinnamon).
Un'altra ottima fonte di informazioni è il pacchetto devhelp, che contiene offline un sacco di reference utili; si installa con il comando
Andando al sodo, ecco un codice di esempio che stampa un'immagine:
il file comune metadata.json:
il file desklet.js:
Un'altra ottima fonte di informazioni è il pacchetto devhelp, che contiene offline un sacco di reference utili; si installa con il comando
sudo apt install devhelp cinnamon-doc
Un esempio
Andando al sodo, ecco un codice di esempio che stampa un'immagine:
il file comune metadata.json:
{ "uuid": "videoDesk@zac", "name": "Video Desklet", "description": "Show video streams on your desktop", "icon": "", "prevent-decorations": false, "max-instances": "100", "dangerous": false }
il file desklet.js:
const Desklet = imports.ui.desklet; const St = imports.gi.St; const Clutter = imports.gi.Clutter; function VideoDesk(metadata, desklet_id) { this._init(metadata, desklet_id); } VideoDesk.prototype = { __proto__: Desklet.Desklet.prototype, _init: function(metadata, desklet_id) { Desklet.Desklet.prototype._init.call(this, metadata, desklet_id); this.window = new St.Bin(); let imgFilename = '/home/zac/Progetti/videoDesk/image.png'; this._clutterTexture = new Clutter.Texture({keep_aspect_ratio: true}); this._clutterTexture.set_from_file(imgFilename) this._clutterBox = new Clutter.Box(); this._binLayout = new Clutter.BinLayout(); this._clutterBox.set_layout_manager(this._binLayout); this._clutterBox.set_width(this.metadata["width"]); this._clutterBox.add_actor(this._clutterTexture); this.window.add_actor(this._clutterBox); this.setContent(this.window); } } function main(metadata, desklet_id) { return new VideoDesk(metadata, desklet_id); }
Un trucco pratico
Durante l'implementaizone lancio spesso il desklet per verificare che la sintassi dei comandi che sto scrivendo sia corretta. Un'opzione è quella di aggiungere e rimuovere in continuazione il nostro desklet dal desktop. Ma ho trovato molto più comodo e veloce usare il compilatore di JavaScript di Cinnamon (il cjs). Tra l'altro ho impostato l'editor Scite a lanciarlo ogni volta che premo F5 per cui l'esecuzione e visualizzazione degli errori è ancora più veloce.
In scite la configurazione per la compilazione automatica si ottiene aggiungendo al file di configurazione la linea
command.go.*.js=cjs $(FileNameExt)
il codice del file di test (che mostra un filmato):
#!/usr/bin/cjs const Lang = imports.lang; const Gtk = imports.gi.Gtk; const Gst = imports.gi.Gst; const Clutter = imports.gi.Clutter; const ClutterGst = imports.gi.ClutterGst; const GtkClutter = imports.gi.GtkClutter; ClutterGst.init(null, null); const Application = new Lang.Class({ //A Class requires an explicit Name parameter. This is the Class Name. Name: 'Application', //create the application _init: function() { this.application = new Gtk.Application(); //connect to 'activate' and 'startup' signals to handlers. this.application.connect('activate', Lang.bind(this, this._onActivate)); this.application.connect('startup', Lang.bind(this, this._onStartup)); }, //create the UI _buildUI: function() { this._window = new Gtk.ApplicationWindow({ application: this.application, title: "Hello World!" }); this._window.set_default_size(200, 200); this.label = new Gtk.Label({ label: "Hello World" }); this.player = new ClutterGst.Playback(); this.player.set_filename("/home/zac/Scrivania/test.mov"); this._content = new ClutterGst.Aspectratio(); this._content.set_player(this.player); this._clutterBox = new Clutter.Box(); this._binLayout = new Clutter.BinLayout(); this._clutterBox.set_layout_manager(this._binLayout); this._clutterBox.set_width(300); this._clutterBox.set_height(100); this._clutterBox.set_content(this._content); this._clutterEmbed = new GtkClutter.Embed(); this._gtkEmbedActor = this._clutterEmbed.get_stage(); this._gtkEmbedActor.add_actor(this._clutterBox); this._window.add(this._clutterEmbed); this.player.set_playing(true); }, //handler for 'activate' signal _onActivate: function() { //show the window and all child widgetsq this._window.show_all(); }, //handler for 'startup' signal _onStartup: function() { this._buildUI(); }, }); //run the application let app = new Application(); app.application.run(ARGV);
Il prossimo passo è aprire un repository su GitHub dove piazzare il codice dei miei esperimenti, nel frattempo, buona programmazione!
Nessun commento:
Posta un commento