On the other side of the screen, it all looks so easy

Overdrive/1

Un recap sui progetti a cui sto lavorando al momento.

Clutter

Nei commenti al blog precendente 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), Clutter è 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 (embedded e non) dotati di grafica accelerata (tramite OpenGL oppure OpenGL ES). Clutter fornisce un canvas, rappresentato dal singleton ClutterStage, e alcuni widget, chiamati ClutterActor. 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 ClutterActor nel modo sbagliato o del tutto inutili.

Hello, World - Come funziona Clutter? Ecco un semplice “hello, world” 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 public domain, come dovrebbero essere tutti gli “hello world” di questo mondo. Se cliccate dopo il link, smonto il codice in blocchi per spiegare come funziona.

import sys
import clutter

Si parte importando i moduli, ovviamente. Il modulo clutter è fornito da pyclutter e supporta tutta la core library; 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.

class HelloClutter:
    def __init__ (self, message):
        self.stage = clutter.stage_get_default()
        self.stage.set_color(clutter.color_parse(‘DarkSlateGrey’))
        self.stage.set_size(800, 600)
        self.stage.connect(‘key-press-event’, clutter.main_quit)
        self.stage.connect(‘button-press-event’,
                           self.on_button_press_event)

Semplice classe per la nostra applicazione; inizializziamo tutto quando e cominciamo a creare lo stage 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 on_button_press_event).

        color = clutter.Color(0xff, 0xcc, 0xcc, 0xdd)

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 0xffccccdd; si può usare una conversione di colorspace da HLS a RGB.

        self.label = clutter.Label()
        self.label.set_font_name(‘Mono 32′)
        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)

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 stage. 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.

        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)

Altro attore: il “cursore” alto quanto l’etichetta di testo, largo venti pixel e posto nell’estremo in basso a destra del nostro stage. Ora non ci resta che animarlo, facendolo lampeggiare.

        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)

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 loop.

Come seconda cosa, creo un alpha. Un ClutterAlpha è 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 forme d’onda (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 behaviour, ovvero un oggetto che controlla una o più proprietà di un set di attori usando l’oggetto alpha; in questo caso, un ClutterBehaviourOpacity che controlla l’opacità degli attori.

    def on_button_press_event (self, stage, event):
        print “mouse button %d pressed at (%d, %d)” % \
              (event.button, event.x, event.y)

Questo è il callback del nostro evento, giusto per mostrare come ottenere i vari dettagli dall’oggetto event.

    def run (self):
        self.stage.show_all()
        self.timeline.start()
        clutter.main()

Il metodo run serve a:

  • mostrare tutti gli attori sullo stage;
  • avviare la timeline;
  • avviare il main loop;

In questo senso, Clutter funziona esattamente come le GTK+: il main loop gira ed esegue il dispatch degli eventi da X all’applicazione.

def main (args):
    if args:
        message = args[0]
    else:
        message = ‘Hello, Clutter!’

    app = HelloClutter(message)
    app.run()
    return 0

if __name__ == ‘__main__’:
    sys.exit(main(sys.argv[1:]))

Qui c’è la solita ferramenta necessaria per i programmi Python. Per avviare, basta eseguire:

$ python hello-clutter.py "Ciao, mondo"

Where do we go from here? - La versione 0.1 di Clutter, rilasciata l’anno passato, ha gettato le fondamenta per gli attori di base, ed è stata sufficiente per realizzare OPT, 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” (ClutterBehaviour) degli attori - ovvero un modo per animare i widget sul canvas. Purtroppo, a parte OPT 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 geek, 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 Bugzilla.

continua…

16 Comments »

  1. Mae* said,

    January 30, 2007 @ 00:12

    “nei commenti al blog precendente” per un attimo ho pensato avessi cambiato blog ;).

  2. Lawrence Oluyede said,

    January 30, 2007 @ 00:33

    Sembra fico Emmanuele! Lo linko su it.comp.lang.python. Appena ho tempo lo provo, ora latito un po’ troppo su OSX :-P

  3. EnricoTuxMind said,

    January 31, 2007 @ 11:02

    Complimenti Emmanuele!

    “la cui interfaccia, diciamocela tutta, va bene a duemila geek, 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”

    eh eh :)

  4. André said,

    April 26, 2007 @ 18:49

    Hello,

    I’m very impressed with Clutter. It’s a great project!

    Where I can find more examples with pyclutter?

    Thanks.

  5. zefram said,

    May 2, 2007 @ 11:01

    @andré:

    thank you!

    there aren’t many examples with pyclutter, unfortunately; the tarball comes with some API usage examples, but it’s mostly dependent on what you want to achieve. we are planning a “clutter-demo” and a more extensive “clutter-tutorial” that should be bundled with the core clutter, and ported over to the bindings.

  6. Francesco said,

    June 29, 2007 @ 14:41

    Ciao, molto interessante questo progetto. Devo dire però che mi sembra molto instabile, ad esempio quando ridimensiono la finestra di qualsiasi progetto creato con Clutter compreso questo Hello World e i due esempi presenti in pyclutter mi si chiude la sessione Gnome. E’ un problema mio o è una cosa nota?

  7. zefram said,

    June 29, 2007 @ 15:08

    @Francesco:

    mai successo - nemmeno con i checkout ultra instabili. che driver X stai usando?

  8. Francesco said,

    June 29, 2007 @ 15:26

    Sto usando driver proprietari ATI e sono in una sessione XGL. Spero che questo ti possa servire a capire…

  9. zefram said,

    June 29, 2007 @ 16:19

    XGL crasha a prescindere - non dovresti usarlo, specialmente con i driver proprietari della ATi.

  10. Francesco said,

    June 29, 2007 @ 16:27

    Purtroppo la mia scheda non funziona con i driver open per le ATI :/

  11. zefram said,

    June 29, 2007 @ 16:39

    XGL è instabile e non penso sia nemmeno mantenuto. ho provato varie volte ad usarlo ma mi è sempre crashato in maniera spettacolare. Clutter funziona perfettamente con i driver closed della ATi, su un X server normale; con i driver closed NVidia; e con i driver open della intel.

    quello che posso suggerire è di non usare XGL, ma di usare il normale X server della tua distribuzione.

  12. Francesco said,

    June 29, 2007 @ 16:43

    Proverò a fare come dici anche se ormai sono un compiz dipendente! Comunque nel frattempo sto provando ad usare un po pyclutter e devo dire che è davvero interessante anche se trovo difficoltà a muovermi nella documentazione delle API per C.

  13. Francesco said,

    June 29, 2007 @ 19:25

    zefram, cercando in giro informazioni su clutter ho letto di pigment che in pratica ha gli stessi obbiettivi di clutter. Cosa sai dirmi a proposito? Da quanto ho capito clutter è un po più avanti per l’integrazione con gtk

  14. zefram said,

    June 29, 2007 @ 19:33

    clutter è decisamente più avanti di pigment in quasi tutto; buona parte della roadmap di pigment è presa pari dal feature set di clutter, più altro che si trova già nella nostra roadmap oppure è già stato implementato in trunk.

    tra l’altro, oggi abbiamo rilasciato il primo snapshot per sviluppatori, 0.3.0, in attesa della release 0.4.0 che sarà fatta subito prima o subito dopo il GUADEC di quest’anno (metà luglio).

    lo snapshot per sviluppatori fuori dalla porta significa che i binding per perl, python e c# stanno per essere aggiornati alle nuove API.

  15. Francesco said,

    June 29, 2007 @ 19:39

    Ho capito. Senti volevo sapere se è in programma della documentazione specifica per i vari binding (a me interesserebbe python) o no, o se eventualmente hai del materiale a cui linkarmi per poter imparare qualcosa su pyclutter.

    Grazie

  16. zefram said,

    June 29, 2007 @ 19:59

    nope, niente documentazione specifica. le API sono essenzialmente le stesse del C, tranne per alcuni dettagli. quindi le API reference sono tendenzialmente valide per tutti i binding.

RSS feed for comments on this post · TrackBack URI

Leave a Comment

I'm the sound, thorough-paced, red-hot desperate, and Herculean Wordpress Hashcash!