Un recap sui progetti a cui sto lavorando al momento.
<h4>Clutter</h4>
Nei commenti al <a href="http://www.emmanuelebassi.net/archives/2007/01/the-body-says-no/">blog precendente</a> mi si chiedeva di Clutter. Per chi non seguisse Planet GNOME (o per chi lo seguisse ma non avesse comunque la più pallida idea di cosa si tratti), <a href="http://www.clutter-project.org">Clutter</a> è un toolkit che ho contribuito a realizzare più o meno da quando sono stato assunto alla OpenedHand (settimana più, settimana meno).
Clutter è un toolkit basato sulle stesse librerie usate per le GTK+ (GLib, GObject, Pango) ideato per scrivere applicazioni con un’interfaccia grafica mono-finestra – ad esempio: media box, personal video recorder, etc. – in ambienti (<em>embedded</em> e non) dotati di grafica accelerata (tramite <a href="http://en.wikipedia.org/wiki/OpenGL">OpenGL</a> oppure <a href="http://en.wikipedia.org/wiki/OpenGL_ES">OpenGL ES</a>). Clutter fornisce un <em>canvas</em>, rappresentato dal <em>singleton</em> <code>ClutterStage</code>, e alcuni <em>widget</em>, chiamati <code>ClutterActor</code>. I widget forniti sono (volutamente, al momento) pochi: non solo perché siamo alla release 0.2.0, ma soprattutto perché vogliamo vedere di cosa necessitano gli sviluppatori prima di implementare <code>ClutterActor</code> nel modo sbagliato o del tutto inutili.
<strong>Hello, World</strong> – Come funziona Clutter? Ecco un semplice <a href="http://devel.emmanuelebassi.net/software/hello-clutter.py">"hello, world"</a> che sfrutta buona parte delle nuove API. à scritto in Python – avrei preferito scriverlo in Perl, ma conoscendo la quantità di pythonisti in "ascolto" ho scelto altrimenti; la versione in Perl è disponibile a richiesta. Se volete, potete scaricarla e farci quello che volete – è nel <em>public domain</em>, come dovrebbero essere tutti gli "hello world" di questo mondo. Se cliccate dopo il link, smonto il codice in blocchi per spiegare come funziona.
<!–more–>
<pre>
<span style="color:purple">import</span> sys
<span style="color:purple">import</span> clutter
</pre>
Si parte importando i moduli, ovviamente. Il modulo <code>clutter</code> è fornito da <a href="http://www.clutter-project.org/sources/pyclutter/0.2/">pyclutter</a> e supporta tutta la <em>core library</em>; non appena riuscirò ad avere un po’ di tempo, e a domare le interazioni tra Python, GObject e GStreamer, pyclutter fornirà anche i binding per le estensioni multimediali disponibili (al momento) in C.
<pre>
<span style="color:orange">class</span> <span style="color:blue">HelloClutter</span>:
<span style="color:orange">def</span> <span style="color:blue">__init__</span> (self, message):
self.stage = clutter.stage_get_default()
self.stage.set_color(clutter.color_parse(<span style="color:red">’DarkSlateGrey’</span>))
self.stage.set_size(800, 600)
self.stage.connect(<span style="color:red">’key-press-event’</span>, clutter.main_quit)
self.stage.connect(<span style="color:red">’button-press-event’</span>,
self.on_button_press_event)
</pre>
Semplice classe per la nostra applicazione; inizializziamo tutto quando e cominciamo a creare lo <em>stage</em> principale su cui aggiungeremo i vari attori. Diamo una mano di "DarkSlateGrey" al palco, lo allarghiamo a 800 pixel per 600 e colleghiamo i due eventi che ci interessano: pressione di un tasto (a cui associamo l’uscita dal programma) e pressione di un pulsante del mouse (a cui associamo il metodo <code>on_button_press_event</code>).
<pre>
color = clutter.Color(0xff, 0xcc, 0xcc, 0xdd)
</pre>
Creiamo un colore, dandogli i valori dei quattro canali (rosso, verde, blu e alpha per l’opacità ). Questo è uno dei vari modi che Clutter mette a disposizione per creare un colore. In alternativa, si può usare una stringa di testo (come sopra) che, però, non cambierà il valore dell’opacità di default; si può usare un intero senza segno da 32 bit (packed) come <code>0xffccccdd</code>; si può usare una conversione di <em>colorspace</em> da <acronym title="Hue Luminance Saturation">HLS</acronym> a <acronym title="Red, Green, Blue">RGB</acronym>.
<pre>
self.label = clutter.Label()
self.label.set_font_name(<span style="color:red">’Mono 32′</span>)
self.label.set_text(message)
self.label.set_color(color)
(label_width, label_height) = self.label.get_size()
label_x = self.stage.get_width() – label_width – 50
label_y = self.stage.get_height() – label_height
self.label.set_position(label_x, label_y)
self.stage.add(self.label)
</pre>
Dopo il palco, creiamo il primo attore: una semplice etichetta di testo. Decidiamo il font e il contenuto e posizioniamo l’attore a cinquanta pixel dall’estremo in basso a destra dello <em>stage</em>. Le dimensioni dell’etichetta vengono ricalcolate quando impostiamo il font e il testo, così da garantirci sempre dei valori aggiornati. Usando Pango, abbiamo gratis il supporto per l’internazionalizzazione delle stringhe, dei glifi, dei paragrafi, dell’ellissi dei testi, degli spazi e delle legature.
<pre>
self.cursor = clutter.Rectangle()
self.cursor.set_color(color)
self.cursor.set_size(20, label_height)
cursor_x = self.stage.get_width() – 50
cursor_y = self.stage.get_height() – label_height
self.cursor.set_position(cursor_x, cursor_y)
self.stage.add(self.cursor)
</pre>
Altro attore: il "cursore" alto quanto l’etichetta di testo, largo venti pixel e posto nell’estremo in basso a destra del nostro <em>stage</em>. Ora non ci resta che animarlo, facendolo lampeggiare.
<pre>
self.timeline = clutter.Timeline(30, 25)
self.timeline.set_loop(True)
alpha = clutter.Alpha(self.timeline, clutter.ramp_func)
self.behaviour = clutter.BehaviourOpacity(alpha, 0xdd, 0)
self.behaviour.apply(self.cursor)
</pre>
Per le animazioni ricorro ai "behaviour", i comportamenti che accennavo all’inizio del post. Per prima cosa, creo una timeline, ovvero una linea che dia il computo del tempo; la voglio di trenta frame, con 25 frame al secondo, e la voglio in <em>loop</em>.
Come seconda cosa, creo un <em>alpha</em>. Un <code>ClutterAlpha</code> è un oggetto che lega una timeline a una funzione; ad ogni "tic" della timeline, invoca la funzione e ottiene un intero senza segno che è dipendente solo dal tempo. In pratica, ingegneristicamente parlando, è un generatore di <a href="http://en.wikipedia.org/wiki/Waveform">forme d’onda</a> (mi rendo conto solo ora, cercandolo, che Wikipedia italiana non ha una pagina sui generatori di forme d’onda; gli ingeneri sono peggio degli idraulici: quando servono non ci sono mai).
Infine, creo un <em>behaviour</em>, ovvero un oggetto che controlla una o più proprietà di un set di attori usando l’oggetto alpha; in questo caso, un <code>ClutterBehaviourOpacity</code> che controlla l’opacità degli attori.
<pre>
<span style="color:orange">def</span> <span style="color:blue">on_button_press_event</span> (self, stage, event):
print <span style="color:red">"mouse button %d pressed at (%d, %d)"</span> % <span style="color:purple">\\</span>
(event.button, event.x, event.y)
</pre>
Questo è il callback del nostro evento, giusto per mostrare come ottenere i vari dettagli dall’oggetto <code>event</code>.
<pre>
<span style="color:orange">def</span> <span style="color:blue">run</span> (self):
self.stage.show_all()
self.timeline.start()
clutter.main()
</pre>
Il metodo <code>run</code> serve a:
<ul>
<li>mostrare tutti gli attori sullo <em>stage</em>;</li>
<li>avviare la timeline;</li>
<li>avviare il main loop;</li>
</ul>
In questo senso, Clutter funziona esattamente come le GTK+: il main loop gira ed esegue il dispatch degli eventi da X all’applicazione.
<pre>
<span style="color:orange">def</span> <span style="color:blue">main</span> (args):
<span style="color:orange">if</span> args:
message = args[0]
<span style="color:orange">else</span>:
message = <span style="color:red">’Hello, Clutter!’</span>
app = HelloClutter(message)
app.run()
return 0
<span style="color:orange">if</span> __name__ == <span style="color:red">’__main__’</span>:
sys.exit(main(sys.argv[1:]))
</pre>
Qui c’è la solita ferramenta necessaria per i programmi Python. Per avviare, basta eseguire:
<pre>
$ python hello-clutter.py "Ciao, mondo"
</pre>
<strong>Where do we go from here?</strong> – La versione 0.1 di Clutter, rilasciata l’anno passato, ha gettato le fondamenta per gli attori di base, ed è stata sufficiente per realizzare <acronym title="OpenedHand Presentation Tool">OPT</acronym>, un programma di presentazione usato da Ross Burton, da Jeff Waugh e dal sottoscritto al GUADEC di Vilanova. Per la version 0.2 abbiamo migliorato l’API, creato un renderer GL per Pango (riducendo l’utilizzo della memoria e aumentando la velocità e il supporto per l’internazionalizzazione) e aggiunto il supporto per i "comportamenti" (<code>ClutterBehaviour</code>) degli attori – ovvero un modo per animare i widget sul canvas. Purtroppo, a parte <a href="http://svn.o-hand.com/view/clutter/trunk/toys/opt/">OPT</a> non abbiamo notizia (al momento) di applicazioni che usino Clutter. Per questo ci farebbe piacere l’input della comunità , anche per sapere quali sono non solo i bug, ma anche le feature e le richieste che gli sviluppatori di applicazioni hanno; se voleste delle modifiche alle API per realizzare il prossimo rivale di MythTV (la cui interfaccia, diciamocela tutta, va bene a duemila <em>geek</em>, ma se la vedono gli utenti che hanno difficoltà a cambiare l’ora del videoregistratore abbiamo diecimila utenti che si buttano dalla finestra dall’orrore), oppure se avete dei bug da segnalare, basta aprire un ticket su <a href="http://bugzilla.o-hand.com/enter_bug.cgi?product=Clutter">Bugzilla</a>.
<em style="font-size:80%">continua…</em>
Comments are disabled for this post