Sei sulla pagina 1di 134

Caratterizzazione dei window compositing

manager in ambienti embedded

Mirto Musci

10 ottobre 2010
Ancora una volta,
ai miei genitori.
Indice

Introduzione ix

1 Concetti di base 1
1.1 Alcune denizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 X Window System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Caratteristiche principali . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.2 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 X Core Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3.1 Risorse ed identicatori . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.2 Atomi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3.3 Finestre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3.4 Proprietà ed attributi . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.5 Pixmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3.6 Eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3.6.1 Esempio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.7 Estensioni del protocollo . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4 X Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4.1 Xlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.4.2 X Toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4.3 GTK+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.4 Clutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.4.5 Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.5 Qt Graphics View Framework . . . . . . . . . . . . . . . . . . . . . . . . 25
1.5.1 Scene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.5.2 View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.5.3 Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.5.3.1 Nota per i sistemi embedded . . . . . . . . . . . . . . . . 29

v
2 Compositing manager 31
2.1 Window Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.1 X Window manager . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.1.2 Re-parenting e decorazione . . . . . . . . . . . . . . . . . . . . . . 33
2.1.3 Classicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1.4 Standard EWMH e ICCCM . . . . . . . . . . . . . . . . . . . . . 37
2.2 Compositing manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.2.1 Cenni storici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.2.2 Meccanismi di base . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.2.3 Composite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.2.4 XFixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.2.5 Damage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.2.6 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.3 Rendering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.3.1 Alpha-compositing . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.3.2 XRender . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.3.2.1 Richieste . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.3.2.2 Accelerare XRender . . . . . . . . . . . . . . . . . . . . . 55
2.3.3 OpenGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.3.3.1 Rendering diretto e indiretto . . . . . . . . . . . . . . . . 56
2.3.3.2 Redirected Direct Rendering . . . . . . . . . . . . . . . . 57
2.3.4 Qt Rendering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.4 Eetti graci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.4.1 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.4.2 Trasparenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.4.3 Exposé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.4.4 Altri eetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.5 Composizione in ambito embedded . . . . . . . . . . . . . . . . . . . . . . 65
2.6 Note implementative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.6.1 Verica del supporto al compositing . . . . . . . . . . . . . . . . . 67
2.6.2 Utilizzare Composite . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.6.2.1 Accedere agli attributi delle nestre . . . . . . . . . . . . 69
2.6.3 Utilizzare XRender . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.6.3.1 Finestre dalla forma particolare . . . . . . . . . . . . . . . 70
2.6.4 Filtrare gli eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.6.5 Utilizzare Damage . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.6.5.1 Gestore personalizzato per i DamageNotify . . . . . . . . 73
2.7 Un esempio completo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
2.7.1 Inizializzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.7.2 Gestione degli eventi . . . . . . . . . . . . . . . . . . . . . . . . . 80
2.7.3 Note nali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
3 MeeGo 85
3.1 Principali caratteristiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
3.2 Rapporto con il mondo Open Source . . . . . . . . . . . . . . . . . . . . . 86
3.3 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
3.3.1 OS Base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.3.2 Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.3.3 UX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.4 MeeGo Touch UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.4.1 Stile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.4.2 Lavorare con MeeGo Touch . . . . . . . . . . . . . . . . . . . . . . 94

4 MeeGo Compositor 95
4.1 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.1.1 Scene-Item-View . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.1.2 Possibili ottimizzazioni . . . . . . . . . . . . . . . . . . . . . . . . . 98
4.2 Compositore: classi principali . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.2.1 MCompositeScene . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.2.2 MCompositeWindow . . . . . . . . . . . . . . . . . . . . . . . . . . 101
4.2.3 MTexturePixmapItem . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.2.4 MDeviceState . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
4.2.5 MCompositeManager . . . . . . . . . . . . . . . . . . . . . . . . . 104
4.3 Decoratore: classi principali . . . . . . . . . . . . . . . . . . . . . . . . . . 106
4.3.1 MRMIClient e MRMIServer . . . . . . . . . . . . . . . . . . . . . . 106
4.3.2 MAbstractDecorator e MDecorator . . . . . . . . . . . . . . . . . . 107
4.3.3 MDecoratorWindow . . . . . . . . . . . . . . . . . . . . . . . . . . 107
4.3.4 MSimpleWindowFrame . . . . . . . . . . . . . . . . . . . . . . . . 107
4.3.5 MDecoratorFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
4.4 Funzione principale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
4.5 Un caso reale: composizione sulla U8500 . . . . . . . . . . . . . . . . . . . 109
4.5.1 Architettura graca della U8500 . . . . . . . . . . . . . . . . . . . 110
4.5.2 Ottimizzare la composizione . . . . . . . . . . . . . . . . . . . . . . 111

5 Conclusioni 113
Bibliograa 115

vii
Introduzione
Un lungo e travagliato percorso, partito dai primi esperimenti nei laboratori Xerox a
Palo Alto, e passato dalla novità Macintosh di Apple e dalle prime versioni di Microsoft
Windows, ha fatto sì che, piano piano, si creasse in informatica l'imprescindibile necessità
delle interfacce grache utente.
Ai giorni nostri si tende persino a dare per scontata questa possibilità, e il paradigma
di nestre, pulsanti, icone e menù, pur tra mille varianti, appare oramai una componente
di base di ogni sistema d'interazione.
Certamente è ancora possibile, soprattutto in ambiente Linux, interagire con il proprio
computer tramite le scarne ma potenti interfacce a riga di comando, ma sono davvero
pochi gli utenti che rinuncerebbero completamente alla comodità, alla familiarità, ed alla
non disprezzabile componente estetica oerta dalle interfacce grache.
Alla luce di quanto appena detto, si capisce come i numerosi applicativi che complessi-
vamente permettono l'interazione graca con l'utente, siano componenti estremamente
importanti e degni d'interesse in ogni sistema operativo. Tra questi, sicuramente merita
particolare attenzione il window manager, ovvero quella componente che si occupa della
gestione di tutte le nestre mostrate sullo schermo, e della quale l'utente ha un'esperien-
za continua e diretta, anche se spesso inconsapevole. Si badi bene: non è compito del
window manager dialogare con la scheda graca o con i dispositivi di input, e quindi per-
mettere eettivamente il disegno sullo schermo di quanto le singole applicazioni vogliono
mostrare. Questo, infatti, è compito dei windowing system.
Il window manager è una componente che si interpone fra le applicazioni e i windowing
system, e decide come e dove saranno posizionate le nestre, crea e modica cornici
e barre di stato per ogni nestra, e decide cosa accade quando l'utente ne chiede il
ridimensionamento o la riduzione ad icona.
Dato il ruolo intermedio tra le applicazioni e il sistema graco, l'innegabile situazione
privilegiata e la relativa libertà da standard vincolanti, i window manager possono essere,
e sono stati negli anni, terreno di sperimentazione.
Ogni sistema operativo, in ambito desktop quanto in ambito embedded, implementa
diversamente il proprio sottosistema graco ed il corrispondente window manager. Ad-
dirittura, in alcuni casi le due componenti coincidono. D'altra parte, tutti quei sistemi
operativi che aondano le loro radici in Unix condividono lo stesso approccio, basato
sulla cosiddetta architettura X Window.

ix
Introduzione

App App App App


Motore di rendering

Window manager Compositing manager

Sistema grafico

Hardware

Figura 1: Le principali componenti in gioco. Con la linea tratteggiata sono evidenziati


gli elementi sul quale sarà concentrata l'attenzione.

Con la sempre maggior crescita del potere di calcolo delle macchine, nonché a causa
delle recenti tendenze di mercato, è stata introdotta una gura da aancare o da in-
tegrare con i window manager, quella dei cosiddetti compositing manager. Lo scopo di
questo componente è quello di consentire un modello d'interazione che, sebbene non com-
pletamente innovativo, di certo modica sensibilmente l'esperienza utente, che si trova
ad avere a che fare con nestre trasparenti, desktop tridimensionali, ombre dinamiche ed
eetti graci di ogni sorta. In questa maniera non viene solo soddisfatto il gusto estetico
degli utenti, ma vengono anche forniti una serie di strumenti che migliorano l'accessi-
bilità o comunque la facilità e l'immediatezza d'uso. Tra le tante novità, si pensi che
con i compositori è possibile introdurre una terza dimensione in un paradigma graco
notoriamente bidimensionale.
Il nome compositing manager è dovuto al principio base che consente la realizzazione
dei suddetti eetti, ovvero la composizione dei contenuti delle nestre, prima che queste
siano eettivamente disegnate a schermo. Perché queste operazioni siano possibili, i
compositing manager devono integrarsi perfettamente con i window manager, e in un
certo senso interporsi tra questi ultimi e i client del sistema graco.
In gura 1 sono rappresentate schematicamente le componenti che sono state introdotte
no a questo momento, e le loro mutue interazioni.
Sono diversi i motivi che rendono interessanti i compositing manager e le tecniche di
composizione. Un primo motivo è sicuramente dovuto alle tecniche innovative che ne per-
mettono l'implementazione, specialmente se si considera che il substrato graco risulta
praticamente invariato, in ambito Unix, da circa vent'anni. Un altro motivo d'interesse
è la grande varieta di sistemi che le hanno introdotte o le stanno introducendo. Non si
pensi, infatti, che la composizione sia un'esclusiva dei sistemi Unix-based. Attualmente,
i compositori sono diventati una delle componenti di base di tutti i più recenti sistemi

x
Introduzione

operativi: a partire dalle prime realizzazione commerciali da parte di Apple, per contin-
uare con Microsoft che, con Windows Vista, rende la composizione parte integrante della
sua interfaccia utente.
Inoltre, la composizione acquista interesse ancora maggiore quando si considera la sda
di introdurla in ambienti embedded. Cellulari, netbook e dispositivi per automobili sono
macchine estremamente più limitate nelle potenzialità dell'hardware di quanto non lo
siano i vari sistemi desktop.
La curiosità iniziale, che sicuramente ha contribuito ad avvicinarmi all'argomento, si
è concretizzata in un vero e proprio lavoro di studio quando mi è stato comunicato
l'interesse da parte di St-Ericsson, azienda nota nel campo della microelettronica. St
ha infatti sviluppato una nuova board, l'U8500, dotata di notevoli capacità grache, sul
quale è possibile immaginare sistemi operativi che sfruttino al massimo la composizione1 .
Lo scopo del presente lavoro di tesi non è, però, quello di trattare i dettagli d'imple-
mentazione della composizione sulla particolare macchina, quanto quello di fornire una
caratterizzazione ad ampio spettro delle tecniche di composizione e della loro integrazione
all'interno del sistema graco X Window.
La scelta di limitarsi (si fà per dire) allo studio della composizione e dei compositori
su sistemi Linux è dovuta a due fattori fondamentali. Il primo è la modularità intrinseca
di X, che permette di isolare i compositing manager dal sistema graco circostante; il
secondo è che, lavorando con software prevalentemente open source, si possono ottenere
facilmente sorgenti e documentazione, sono utilizzati standard aperti, e si ha la possibilità
di accedere ad un vasto supporto da parte della comunità.
Nel corso del lavoro, però, non ci si è limitati ad uno studio teorico, rinunciando alla
concretizzazione degli argomenti trattati. Infatti viene fornita una descrizione dettagliata
di un caso di studio particolarmente interessante: la composizioen all'iterno del nuovo
sistema operativo MeeGo, joint-venture di Intel e Nokia, e orientato principalmente al
mercato della telefonia e dell'embedded in generale. Di questo sistema, tra l'altro, esiste
già una prima implementazione per la scheda St citata in precedenza.
Per arrivare a realizzare questo documento è stato necessario un lungo periodo di
studio, nel quale sono state prese in considerazione molte tecniche implementative e
diversi sistemi operativi, tra i quali, ad esempio, sono compresi Android e Chrome OS.
La scelta è poi ricaduta su MeeGo per diversi motivi: il primo è il sopracitato l'interesse
da parte di St-Ericsson; il secondo è che la realizzazione di MeeGo è basata sulle librerie
grache Qt e in particolare paradigma Qt Graphics View, una tecnica implementativa
interessante ed innovativa; il terzo, e più importante, è che MeeGo è basato su Unix,
utilizza X, ed è open source, il che lo rende un caso di studio perfetto.
Sempre parlando di concretizzazione, viene presentata anche una semplice implemen-
tazione custom di un compositore, impiegata principalmente per descrivere gli argomenti
teorici trattati nel corso della tesi. Tale lavoro è stato realizzato basandosi sul toolkit
Clutter, alternativo a Qt, in modo da evidenziare le dierenze tra i due approcci.

1
http://www.stericsson.com/platforms/U8500.jsp

xi
Introduzione

Contenuti della tesi


Il primo capitolo è intitolato Concetti di base, e contiene una descrizione degli argomenti
propedeutici ad una trattazione completa delle tecniche di composizione. Sono introdotti
l'X Window System ed il protocollo che ne regola le interazioni. Una sezione è dedica-
ta alla tematica generale della programmazione graca sotto X. Tra le altre cose sono
descritti Xlib ed i più comuni toolkit graci: GTK+, Clutter e Qt.
Il secondo capitolo, intitolato semplicemente Compositing Manager, è il capitolo più
importante dell'intero lavoro. Inizialmente è oerta una descrizione dei classici window
manager, seguita poi da una descrizione dettagliata dei compositori ed una panoramica
delle tecniche implementative necessarie alla loro realizzazione. Il capitolo si conclude con
la descrizione di un semplice compositing manager basato su Clutter, utile per raorzare
i concetti teorici presentati nelle sezioni precedenti.
Il terzo capitolo, MeeGo, fornisce un'introduzione all'omonimo sistema operativo. Tale
introduzione è fondamentale per chiarire il contesto nel quale opera il MeeGo Composi-
tor, che dà il nome al quarto ed ultimo capitolo. In esso viene descritta dettagliatamente
l'architettura del compositore, completa dei relativi diagrammi architetturali. Il capitolo
si conclude con una serie di riessioni a proposito dell'implementazione di MeeGo Com-
positor, e della composizione in generale, su di una particolare macchina embedded, la
scheda St-Ericsson U8500.

xii
Capitolo 1

Concetti di base
In questo capitolo vengono presentati alcuni concetti di base, propedeutici alla compren-
sione di quanto viene discusso nei capitoli successivi.
Dopo aver fornito alcune denizioni basilari, nella prima parte del capitolo viene
introdotto l'X Window System (1.2) ed il protocollo che ne regola le comunicazioni:
l'X Core Protocol (1.3). Successivamente viene analizzato il problema della program-
mazione graca sotto X, introducendo la libreria fondamentale di interazione con il pro-
tocollo (Xlib ) e i vari toolkit (GTK +, Clutter e Qt ) che permettono la realizzazione di
applicazioni grache complesse (1.4). L'ultima sezione approfondisce il Graphics View
Framework, una componente di Qt innovativa ed interessante sotto diversi aspetti (1.5).

1.1 Alcune denizioni


• Una GUI (Graphical User Interface ) è un interfaccia di interazione uomo-macchina,
realizzata tramite nestre, icone e menù manipolabili dall'utente principalmente
con mouse e tastiera. Alle interfacce grache sono contrapposte quelle a linea di
comando, che presentano le informazioni sotto forma testuale e con le quali l'utente
interagisce quasi esclusivamente tramite tastiera.
• Con modello client-server si intende un sistema modulare le cui operazioni sono
suddivise tra due programmi, client e server per l'appunto, distinti ma in qualche
maniera collegati tra di loro. Tipicamente, ma non necessariamente, il server è in
esecuzione su una macchina remota, riceve le richieste da parte di molteplici client,
processa opportunamente le informazioni, e comunica i risultati ai client.
• Con il termine multi -piattaforma ci si riferisce alla capacità di un software di op-
erare su più piattaforme mantenendo invariate, o quasi, le proprie funzionalità. A
secondo del contesto, con il termine piattaforma si possono intendere:
 il tipo di sistema operativo (Linux, Mac OS X, Windows);
 il tipo di processore (x86, PowerPC, ARM);
 il tipo di macchina in generale (desktop, mobile, embedded).

1
Concetti di base

• Per free software (software libero) si intende un programma che si può ottenere gra-
tuitamente, e che può essere utilizzato in ogni circostanza, a prescindere dallo scopo:
lo si può studiare liberamente sotto forma di codice sorgente, lo si può duplicare,
distribuire e installare su qualunque numero di macchine, lo si può modicare ed es-
tendere. Il kernel e gran parte delle applicazioni Linux, compresa l'implementazione
di X, sono distribuite come software libero.

1.2 X Window System


Quando si parla di windowing system (o WS ) si intende la componente principale di un
sottosistema graco, in grado di gestire in maniera unicata l'hardware graco, il sistema
di puntamento e la tastiera.
L'utente non interagisce direttamente con un windowing system, e quello che vede a
schermo è normalmente frutto dell'interazione tra le applicazioni, i window manager e
gli ambienti desktop. Un sistema graco è in realtà una sorta di middleware, uno strato
software intermedio che mette a disposizione degli strati soprastanti le capacità grache
del sistema.
Complessivamente, un windowing system tiene traccia di tutte le applicazioni utiliz-
zate, le nestre e tutti gli oggetti graci a loro associati, e lo stato degli input e degli out-
put di ogni applicazione. Comprende inoltre un'interfaccia verso un motore di rendering
graco, liberamente accessibile alle applicazioni.
Più in dettaglio un windowing system :

• permette all'utente di utilizzare diversi programmi in contemporanea. General-


mente ogni programma viene eseguito in una nestra separata, ovvero una ben
precisa sezione rettangolare dello schermo. Molti WS orono un supporto basilare
al cosiddetto re -parenting, che in ultima analisi consente alle nestre di integrarsi
l'un l'altra;

• implementa una serie di primitive grache che permettono di renderizzare immagini


arbitrariamente complesse. Le primitive permettono il disegno a schermo di punti,
linee o caratteri di testo (font ); complessivamente costituiscono un'astrazione ad
alto livello dell'hardware sottostante.

Con il nome X Window System (comunemente abbreviato X11 o semplicemente X ) si in-


dica un particolare windowing system libero, completo, multi-piattaforma, standardizzato
e trasparente (rispetto al networking) che, nel corso degli anni, è diventato lo standard
1
de facto per i sistemi Unix e Linux in particolare [SG86, GKM90].

1
Esistono WS alternativi per Unix/Linux, ma X è di gran lunga il più diuso ed utilizzato, tanto che,
nonostante l'assenza di un'indicazione formale, risulta essere spesso l'unico WS preso in considerazione
da utenti e sviluppatori.

2
1.2 X Window System

1.2.1 Caratteristiche principali


X è altamente congurabile, ma anche dotato di un livello di complessità molto eleva-
to. Una delle sue caratteristiche principali è quella di essere completamente separato
dal sistema operativo. Questa condizione è in netto contrasto con quanto riscontrabile
altrove, dove il sistema graco è parte integrante del sistema operativo2 . La conseguenza
di quanto appena detto è che, nel caso in cui l'interfaccia graca non sia necessaria3 , si
può facilmente fare a meno di installare o eseguire un'istanza di X, eliminando l'overhead
e migliorando così le prestazioni della macchina.
X implementa solo una serie di meccanismi, senza forzare nessuna particolare policy,
né in riferimento all'aspetto né tanto meno rispetto al comportamento di un interfaccia
graca.
Questo signica, tra le altre cose, che X non si occupa della diretta gestione delle
nestre, ma fornisce una serie di strumenti utili allo scopo. Come si vedrà in segui-
to, la gestione delle nestre è demandata ad un'applicazione particolare, detta window
manager, di cui si parla approfonditamente nella sezione 2.1.

1.2.2 Architettura
Dal punto di vista architetturale, l'X Windowing System è costruito come un sistema
client-server. Tuttavia, in X la relazione è intesa in una maniera dierente rispetto alla
concezione tradizionale. Infatti, invece di avere molteplici client che interagiscono con un
singolo server remoto, secondo l'architettura di X in ogni macchina locale è in esecuzione
un X server che può interagire con un qualunque numero di client remoti.
Più in dettaglio, nel contesto di X:

• Un server è un programma di sistema, eseguito sempre in locale. Il server gestisce


l'accesso a scheda graca, schermo e dispositivi di input. Praticamente tutte le
operazioni di graca sono concentrate nel server.

• Un client è un programma applicativo che può girare sia in locale che in remoto. Per
disegnare su di una particolare macchina, i client devono interagire con l'X server
che ne gestisce le capacità grache. A parte questo i client sono completamente
indipendenti dai server. È importante notare come sia il gli ambienti desktop che
i window manager, possono essere visti come client (generalmente locali).

L'architettura client-server di X trova identica applicazione non solo tra computer col-
legati in rete, ma anche, e soprattutto, all'interno di una singola macchina. Nonostante
l'apparente contraddizione, la scelta è funzionale per diverse ragioni. Innanzitutto, viene
preservata la consistenza tra operazioni locali ed operazioni remote, che possono ad-
operare le stesse API e gli stessi protocolli. In secondo luogo viene semplica la pro-
grammazione delle applicazioni: si parla di network transparency, secondo la quale sia
2
Si sta parlando, ad esempio, di Microsoft Windows e MaC OS prima del rilascio di OS X.
3
Si pensi ad un server: dicilmente interagisce direttamente con gli utenti.

3
Concetti di base

per il programmatore che per l'utente, è completamente indierente interagire con una
controparte locale o remota.
Alla luce di quanto detto, in entrambi i casi le interazione tra server e client sono rego-
late da una protocollo che garantisce l'interoperabilità: si sta parlando dell'X Core Pro-
tocol, o protocollo principale, trattato in dettaglio nella prossima sezione (1.3).
Per conludere si nota come con il modello architetturale dell'X Window System, include
anche un implementazione di riferimento del server. Attualmente, in seguito al parziale
abbandono del progetto XFree86, viene inclusa l'implementazione X.org.

1.3 X Core Protocol


Il protocollo principale o Core Protocol denisce le modalità con le quali avviene l'inter-
azione tra client e server all'intero dell'X Window System [SG96].
La comunicazione tra server e client è costituita da uno scambio di pacchetti dati lungo
un canale di comunicazione. Il protocollo denisce le modalità dello scambio: quando
inizia, chi inizia, chi partecipa, chi risponde, eccetera. Inoltre denisce il formato ed il
signicato dei messaggi scambiati.
Una conseguenza della separazione dei meccanismi dalle policy, è che il protocollo non
specica in alcuna maniera le interazioni client-client, quelle tra i client e gli utenti, o
quale debba essere il comportamento di un window manager. Questi e altri argomenti
sono oggetto di speciche separate come lo standard ICCCM e le speciche freedesk-
top.org (2.1.4), il cui rispetto è normalmente assicurato dall'utilizzo di un determinato
ambiente desktop (2.1).
Perché tra client e server vi sia comunicazione, è necessario prima che si instauri una
connessione. Il protocollo prevede che la connessione debba essere avviata dal client.
Il primo pacchetto, inviato da client, deve contenere alcune informazioni di inizializ-
zazione: byte order, versione del protocollo utilizzata, tipo di autenticazione (se neces-
saria). Il server può rispondere con tre diversi pacchetti: di accettazione, di richiesta di
autenticazione o di riuto. Se viene inviato il primo pacchetto, il server informa il client
della sua disponibilità a partecipare alla connessione, mentre con il secondo il client viene
invitato a partecipare ad un qualche protocollo di autenticazione, propedeutico all'instau-
razione della connessione. Chiaramente, l'invio del pacchetto di riuto coincide anche
con il termine della comunicazione.
Una volta che la connessione è stata stabilita, il protocollo prevede che client e server
possano scambiarsi pacchetti appartenenti a quattro diverse categorie4 .

4
I pacchetti di richiesta e risposta hanno dimensione variabile, mentre i pacchetti di evento ed errore
hanno dimensione ssa di 32 byte. I pacchetti di richiesta sono numerati sequenzialmente dal server
non appena ricevuti: alla prima richiesta da parte di un client viene assegnato il numero 1, alla
seconda 2, e così via. All'interno dei pacchetti di risposta e degli eventuali pacchetti di errore, sono
inclusi i 16 bit meno signicativi del pacchetto di richiesta che ne ha causato l'emissione. Questa
sorta di codice di riconoscimento è incluso anche nei pacchetti evento per indicare quale richiesta
veniva processata dal server nel momento di generazione dell'evento.

4
1.3 X Core Protocol

primo pacchetto

auntenticazione
(opzionale)

accetta/rifiuta

...
richiesta

risposta
...
evento

client server

Figura 1.1: Le principali interazioni descritte dal protocollo principale.

Request (richiesta): viene generato ogni volta che il client inoltra una richiesta di infor-
mazioni o ordina al server di eseguire un qualche comando.

Reply (risposta): il protocollo non prevede che a tutte le richiesta segua una risposta.
Ogni volta che, per una qualche ragione, deve essere inviata una risposta, viene
generato un pacchetto Reply.

Event (evento): forse il tipo di pacchetto più importante. Viene generato ogni volta che
il server vuole informare il client di un qualche avvenimento, generato all'interno
del server stesso o da qualche agente esterno (l'utente o un qualche altro client).

Error (errore): i pacchetti di errore vengono generati ogni volta che una richiesta non
è valida. Dato che può accadere che le richieste vengano accodate dal server, i
pacchetti di errore possono essere inviati in maniera asincrona rispetto alle richieste.

In gura 1.1 sono riassunte, con un diagramma molto semplice, le possibili interazioni
tra client e server.
Nei paragra successivi vengono analizzate in dettaglio alcune delle componenti fonda-
mentali del protocollo. Richieste, risposte ed errori non vengono trattate esplicitamente;
tuttavia, il paragrafo 1.3.6 è interamente dedicato agli eventi.

5
Concetti di base

1.3.1 Risorse ed identicatori


Secondo il protocollo principale, i client interagiscono con il server per scambiare infor-
mazioni e chiedere che siano svolte operazioni su particolare strutture dati, o oggetti,
collettivamente noti come risorse. Tutte le risorse sono memorizzate dal server e, per
ogni oggetto, i client conoscono solo un identicatore, un intero che può essere utilizzato
per riferirsi ad una particolare risorsa mentre si dialoga con il server.
Ogni volta che un client richiede al server la creazione di una nuova risorsa, ha l'obbligo
di indicare l'identicatore che desidera sia utilizzato.
Un esempio classico è quello della creazione di una nestra: sebbene al programmatore
non sia direttamente visibile (a causa della mediazione di Xlib, vedi 1.4.1) la richiesta
inviata al server contiene, oltre ad una serie di attributi direttamente corrispondenti
ai parametri della chiamata a funzione, anche un valore numerico che servirà poi da
identicatore della particolare nestra.
Cerchiamo di formalizzare quanto, no a questo momento, è stato trattato intuitiva-
mente. Il protocollo identica come risorse, e quindi oggetti noti tramite identicatore
numerico:
• le nestre o Window ;

• le Pixmap ;

• i caratteri o Font ;

• le Colormap (letteralmente tabelle di colori)


• i contesti graci o Graphic Context (GC).
Gli identicatori sono interi a 32 bit, i cui tre bit più signicativi sono impostati a zero.
Ogni client deve mantenere un proprio insieme privato di identicatori, all'interno del
quale sceglie, senza duplicazione, i valori da utilizzare durante la creazione di nuove
risorse.
Anché sia preservata la proprietà di univocità degli identicatori a livello di server e
non di singolo client, è necessario che il pool di identicatori sia assegnato esternamente.
La soluzione più immediata è quella per la quale è il server ad assegnare l'intervallo dei
valori ammissibili, garantendo così l'univocità: due risorse qualunque, che siano nestre,
pixmap, font, colormap o GC, non hanno mai lo stesso identicatore.
La comunicazione del pool di valori è racchiusa all'interno del pacchetto di accettazione,
ovvero del primo pacchetto inviato dal server mentre viene stabilita la connessione (vedi
paragrafo precedente).
Il risultato è che due client diversi, connessi allo stesso server, possono usare lo stes-
so identicatore per riferirsi alla stessa risorsa. Naturalmente sarà responsabilità dei
client assicurarsi che tutti i partner posseggano l'identicatore della risorsa che vogliono
condividere, eventualmente comunicandolo egli stesso.5
5
Il client può utilizzare un metodo qualunque: il protocollo non specica, come detto, alcuna interazione
inter-client. Ad esempio, un'applicazione potrebbe scrivere il valore dell'identicatore in una variabile
d'ambiente o in un le di testo.

6
1.3 X Core Protocol

Normalmente, una risorsa è deallocata quando il client che ne ha richiesto la creazione


chiude la connessione con il server. Tuttavia, prima di disconnettersi, il client può
richiedere al server di mantenere la risorsa in memoria, consentendone così il riutilizzo
da parte di terzi.
Nel seguito saranno analizzate le due risorse che sono principalmente d'interesse nel-
lo studio dei window manager : pixmap e, naturalmente nestre. Saranno tralasciati
font, colormap e GC: il lettore interessato è invitato ad esaminare le speciche del pro-
tocollo [SG96, GKM90, SG86]. Tuttavia, prima di andare avanti nella discussione, sarà
introdotto un terzo concetto, in qualche maniera simile a quello degli identicatori: gli
atomi.

1.3.2 Atomi
Gli atom o atomi sono semplicemente interi a 32 bit, utilizzati per rappresentare in forma
compatta stringhe di caratteri arbitrariamente lunghe. I progettisti del protocollo pen-
sarono a questo espediente per rendere quanto più veloce ed eciente la comunicazione e
la decodica di stringhe anche parecchio complesse. L'utilità degli atomi è massimizzata
limitando il loro utilizzo a quelle tipologie di pacchetti che hanno più probabilità di essere
trasmessi ripetutamente. In questa maniera è possibile utilizzare la larghezza di banda
in maniera più ecace.
Più precisamente, gli atomi identicano stringhe memorizzate sul server. In questo gli
atomi si comportano in maniera analoga agli identicatori delle risorse (vedi 1.3.1) in
quanto il valore numerico associato ad un atomo deve essere univoco all'interno di uno
stesso contesto.
Vi sono, tuttavia, due importanti dierenze. Per prima cosa il valore numerico degli
atomi è scelto dal server, e non dal client. In altre parole, quando un client richiede la
creazione di un nuovo atomo, questi invia al server la stringa che vuole sia memorizzata,
senza avere voce in capitolo sul codice che poi servirà per identicarla; il server sceglie
un identicatore (ovvero il valore numerico dell'atomo) e poi lo inoltra al client.
La seconda importante dierenza tra identicatori di risorse e atomi, è che gli atomi non
sono associati a nessun client in particolare. Gli atomi hanno cicli di vita completamente
indipendenti dai client che ne hanno richiesto la creazione o che poi eventualmente gli
hanno utilizzati. La conseguenza è che, una volta creato, un atomo sopravvive no a che
il server si riavvia o termina la propria esecuzione.
Quando si parla del nome di un atomo, si fa riferimento alla stringa a questi associata.
Il nome non può essere modicato dopo la creazione dell'atomo, e atomi diversi devono
avere nomi diversi. La conseguenza è che il nome e il valore dell'atomo possono essere
usati in maniera intercambiabile: l'atomo ABCD sta ad indicare l'atomo la cui stringa
associata assume il valore ABCD .
Gli atomi servono diversi scopi all'interno del protocollo X: principalmente sono uti-
lizzati per memorizzare, analizzare, creare ed in generale trattare le proprietà associate
alle nestre.
In particolare, tuttavia, gli atomi assumono particolare rilevanza per le operazioni
legate alla comunicazione inter-client. Tramite gli atomi, infatti, sono identicate e gestite

7
Concetti di base

4
2

Radice 3
Figura 1.2: Un semplice desktop Unix. In gura sono visualizzate alcune nestre, nu-
merate per comodità: con il numero 1 è indicata la nestra radice, che copre
l'intero schermo. Le nestre 2 e 3 sono top-level. La nestra priva di titolo
(numero 4) è glia della nestra a cui si sovrappone. Dai confronti tra la 3 e
la 1 e tra la 4 e la 2, si può notare come le parti di una nestra situate al di
fuori del proprio genitore (compresa la stessa radice) non siano mai visibili.

le cosiddette selezioni, il principale meccanismo fornito dal protocollo per lo scambio di


informazioni tra i vari client. Ogni selezione ha un proprietario (owner ); gli altri client
possono accedere liberamente al suo contenuto ma non possono modicarlo.
Le selezioni e meccanismi analoghi, come il drag & drop, nonché gli atomi che ne
permettono l'utilizzo, sono specicati negli standard ICCCM ed EWMH (vedi 2.1.4). A
questo proposito è bene ricordare che un certo numero di atomi sono predeniti, ovvero
creati all'avvio del server, spesso proprio per seguire le speciche dei suddetti protocolli.

1.3.3 Finestre
Nel contesto dell'X Window System, la denizione di nestra è molto generale: in questa
categoria ricade una qualsiasi area sulla quale possono avvenire operazioni di input/out-
put (a volte solo di input), di forma generalmente (ma non sempre) rettangolare, di
esistenza autonoma (nestra top-level ) o dipendente da un'altra nestra (sub-window o
sotto-nestra6 ). Dal punto di vista del protocollo, una nestra è una risorsa controllata
da una o più applicazioni client, e memorizzata lato server.

6
Nell'implementazione dei più comuni widget toolkit (vedi 1.4), oggetti graci molto comuni come
bottoni, pannelli ed icone sono spesso rappresentati come sotto-nestre.

8
1.3 X Core Protocol

Le nestre possono essere raggruppate in due macro-tipologie: le nestre InputOutput


e le nestre InputOnly. Nella prima categoria ricadono le nestre che possono ricevere
comandi di output. Le nestre della seconda categoria non sono mai visibili, e sono
utilizzate semplicemente come ricettori di segnali di input.
Ad ogni nestra di output è associato un contenuto, ed è responsabilità del windowing
system assicurarsi che il contenuto venga mostrato a schermo. Normalmente, le nestre
vengono disegnate automaticamente sul framebuer.
Tuttavia, il protocollo non garantisce che il contenuto di una nestra venga sempre
conservato in memoria. Il contenuto potrebbe essere distrutto quando la nestra viene
spostata, ridimensionata, coperta da un'altra nestra o più in generale oscurata in parte
o in tutto. Nonostante i client possano chiedere al server di eettuare un back-up, la
specica non obbliga il server ad ottemperare alla richiesta.
In conseguenza di quanto appena detto, può accadere, e accade spesso, che l'intera
nestra o una sua parte abbia contenuto indenito o non specicato: in questo caso il
server notica al client, attraverso un evento, che quella parte deve essere (ri)disegnata.
Le nestra sono naturalmente disposte in una gerarchia ad albero, la cui radice è la
root window (letteralmente nestra radice), grande tipicamente quanto l'intero schermo .
7

Questa nestra principale è unica per ogni display e deve essere creata dal server all'avvio
della sua esecuzione. Ovviamente, tutte le nestre attive in un dato momento risulteranno
essere glie più o meno indirette della nestra radice: con il termine top-level window si
indicano le dirette discendenti della radice. Un client può richiedere al server la creazione
di una nuova nestra, purchè questa sia glia di una nestra già esistente.
Generalmente, osservando una qualunque nestra, si può notare come questa sia com-
posta, oltre che dall'area di diretta responsabilità del client, anche da un'area comune
alla maggior parte dele nestre: la decorazione. Della decorazione fanno parte la cornice,
o frame della nestra, così come la barra del titolo e tutti i bottoni interni alla cornice.
Queste componenti non sono di responsabilità dei client che, a meno di casi particolari,
non possono né crearle né modicarle.
La decorazione, infatti, non fa parte delle nestra, intesa come risorsa di X; al contrario,
nella maggior parte dei casi, la decorazione è costituita da una nestra a se stante, la
cui gestione è uno dei compiti del window manager. Alla stessa maniera, è il window
manager ad occuparsi della gestione dell'input relativo agli elementi di decorazione: un
esempio classico è quello per cui il WM deve occuparsi di ridimensionare o spostare la
nestra quando l'utente clicca sulla sua barra del titolo o la trascina (2.1.2). In gura
1.2 sono mostrati gli eetti delle relazioni di parentela tra nestre, nonchè quelli della
decorazione.
A questo proposito, si coglie l'occasione di anticipare un concetto che sarà poi ripreso
nella sezione 2.1. In quasi ogni occasione, i client operano sulle nestre di loro compe-
7
In realtà ha senso avere una radice più grande dello schermo: ovviamente né sarà visibile solo una
porzione per volta. All'utente è data la possibilità di modicare l'area visualizzata, tipicamente
muovendo il mouse in direzione del bordo dello schermo, attivando così lo scrolling. È anche possibile
che una stessa nestra radice si estenda su più schermi sicamente separati: in questo caso si parla
di un sistema multi-head.

9
Concetti di base

tenza senza doversi preoccupare del comportamento dei WM, che dovrebbe risultare loro
completamente trasparente.
A questa regola generale fa però eccezione una tipica operazione svolta dai gestori: il
re -parenting delle nestre top-level, che dovrebbe sempre essere tenuto in considerazione
dai client. Il re-parenting consiste nel modicare il predecessore gerarchico delle nestre
di più alto livello, cambiandolo dalla radice ad una nuova nestra creata appositamente
dal window manager. La principale motivazione dietro a questa tecnica è proprio quella
di gestire la decorazione.

1.3.4 Proprietà ed attributi


Ad ogni nestra è associato un insieme di attributi e di proprietà. In questa categoria
ricadono, ad esempio, le proprietà geometriche della nestra (dimensione e posizione), i
dati relativi ad un eventuale sfondo della nestra, l'indicazione se una nestra è stata
ridiretta e se sì, dove.
Il protocollo introduce e formalizza una serie di richieste che i client possono inviare al
server per richiedere il valore di un attributo o di una proprietà, ed eventualmente una
loro modica. Alcuni attributi sono predeniti dal protocollo e, per ogni nestra, è il
server ad occuparsi della loro gestione.
Più in generale, gli attributi rappresentano meta-informazioni sulla nestra, mentre
le proprietà rappresentano segmenti di informazione arbitrari connessi alla nestra, e
liberamente manipolabili dai client. Alla luce di queste due caratteristiche, le proprietà
non possono avere e non hanno alcun signicato al livello del protocollo principale di X8 .
Una proprietà è caratterizzata da un nome, un tipo ed un valore. Sia il nome che il tipo
ed il valore sono stringhe, memorizzate nel server ed accessibili ai client tramite identi-
catori univoci: in altre parole sono atomi (vedi 1.3.2). Le proprietà sono strettamente
collegate alle nestre, per cui possono esistere due o più proprietà con lo stesso nome,
associate a nestre diverse, con tipi e contenuti dierenti.
In un certo senso, le proprietà sono simili variabili di un linguaggio di programmazione.
Un client può creare una nuova proprietà assegnandole nome e tipo, ed utilizzarla per
memorizzare ed eventualmente riutilizzare una certa informazione.
Le proprietà sono utilizzate principalmente per implementare i protocolli di comuni-
cazione inter-client. Nella tabella 2.1.4 sono elencate le principali proprietà utilizzate
per implementare ICCCM ed EWMH. Ad esempio la proprietà WM_NAME9 è utilizzata
per memorizzare il nome che è stato associato ad una nestra. Tipicamente questa in-
formazione è impostata dai client e riutilizzata dai window manager per la decorazione
della nestre (2.1.2).
In virtù dei protocolli di comunicazione inter-client, i window manager spesso sfrut-
tano, oltre che le proprietà delle nestre generiche, anche le proprietà associate alla
nestra di root. Queste proprietà possono essere utilizzate sia in lettura che in scrittura.
8
Le proprietà, tuttavia, sono fondamentali per altri protocolli, come EWMH e ICCCM.
9
Precisamente: la proprietà che per nome ha un atomo a cui è associata la stringa WM_NAME.

10
1.3 X Core Protocol

Per esempio (vedi sempre la tabella 2.1.4), i WM dovrebbero mantenere l'identicatore


della nestra attiva all'interno della proprietà _NET_ACTIVE_WINDOW della nestra radice.

1.3.5 Pixmap
Una Pixmap è semplicemente una regione di memoria che può essere usata come output
per il disegno, sulla quale è possibile eseguire praticamente tutte le operazioni grache
eseguibili su una nestra. Una dierenza fondamentale è che il WS non tenta di render-
izzare automaticamente a schermo il contenuto delle pixmap, contrariamente a quanto
fa per le nestre. Tuttavia, il contenuto di una pixmap, o una sua parte, può essere
trasferito in una nestra e vice versa.
Questo comportamento è utile per implementare tecniche come il double buering.
Questa tecnica è stata implementata in risposta ad un noto problema, quello del cosid-
detto ickering, ovvero dello sfarfallio che si può osservare se si tenta di disegnare diretta-
mente a schermo l'output di un'applicazione complessa. Il problema nasce dal tentativo
del window system di disegnare il contenuto delle nestra quando l'operazione di render-
ing non è ancora conclusa. Una possibile soluzione è quella di redirezionare i comandi
di output10 , diretti alla nestra, verso una pixmap creata appositamente. In seguito,
una volta completato il rendering, il contenuto della pixmap è trasferito nella nestra
eliminando così il fastidioso sfarfallio. Oggi giorno gran parte dei più diusi toolkit (ad
esempio Qt a partire dalla versione 4.0) implementano il double buering in maniera
automatica e trasparente per l'utente [BS08].
Esiste un termine che è possibile utilizzare per riferirsi collettivamente a pixmap e
nestre: Drawable (letteralmente disegnabile ). La denizione è appropriata in quanto
pixmap e nestre condividono una sorta di interfaccia comune, specialmente per quanto
riguarda le operazioni di disegno. Il contenuto dei Drawable è normalmente mantenu-
to sul server: tuttavia il client è libero di richiedere il trasferimento del contenuto sul
client o vice-versa, per svolgere operazioni particolari. In questa categoria ricadono la
trasformazione del contenuto di una pixmap in una texture OpenGL (vedi 2.3.3). Queste
operazioni sono molto costose ed andrebbero evitate ad ogni costo.

1.3.6 Eventi
Il protocollo prevede che particolari pacchetti dati, detti eventi, siano inviati dal server ad
un client quando il server si accorge che è accaduto qualcosa di rilevante per quel client.
Vi sono molte situazioni che provocano l'emissione di eventi, e si potrebbe pensare che
queste situazioni avvengano in concomitanza della ricezione di input da parte dell'utente.
In realtà non è solo così e, nella categoria di situazioni che provocano l'emissione di
pacchetti evento, sono incluse situazioni come la creazione di una nuova nestra da parte
di un'applicazione o il suo ridimensionamento.

10
La tecnica, come si vedrà nel paragrafo 2.2.3 è alla base dell'implementazione dei compositing manager.

11
Concetti di base

Il protocollo richiede che ciascun evento sia relativo ad almeno una nestra11 . Come si
vedrà fra poco, questa caratteristica è strettamente connessa alla modalità di generazione
degli eventi.
Un client può richiedere che il server invii un certo evento ad un client dierente:
questa funzione è utilizzata per implementare alcune forme di comunicazioni inter-client.
Un evento di questo tipo è generato, per esempio, quando un client vuole accedere ad
una selezione testuale: l'evento creato viene inviato al client che gestisce la nestra nella
quale è attiva la selezione.
Un evento particolare è l'evento Expose, generato quando viene mostrata a schermo una
porzione di nestra il cui contenuto, per qualche motivo, non è valido. Le ragioni, come
visto in precedenza, possono essere molteplici; il caso più semplice è quello di una nestra
in precedenza coperta, e della quale il server non ha mantenuto copia del contenuto. La
ricezione di un evento Expose generalmente porta il client a ridisegnare una nestra, in
parte o in tutto.
Al di là di alcune eccezioni12 , un evento viene noticato al client solo se il client ha
mostrato esplicitamente interesse per la particolare classe o tipologia di eventi della quale
l'evento trattato fa parte. Questo comportamento non dovrebbe stupire: spesso ai client
interessa gestire solo un insieme limitato di eventi. Gli eventi che il client riceve in
ogni caso, a prescindere da ciò che ha richiesto esplicitamente, sono chiamati eventi non
mascherabili.
Scendendo nel dettaglio, prima di tutto i client devono selezionare una particolare nes-
tra. Nella stessa richiesta, devono anche specicare tutte le classi di eventi ai quali sono
interessati. L'eetto di questa chiamata è quello di modicare un particolare attributo
della nestra: la maschera degli eventi o event mask.
Può capitare, e il protocollo non lo vieta, che più client siano contemporaneamente
interessati agli eventi di una stessa nestra. Addirittura client diversi potrebbero im-
postare maschere diverse su una stessa nestra. Questo è reso possibile dal fatto che il
server mantiene, per ogni nestra e per ogni client, una event mask separata. Alla luce di
quanto appena detto, dunque, può capitare che un singolo evento, relativo ad una certa
nestra, porti no all'emissione di n pacchetti, dove n è il numero di client che hanno
selezionato la nestra.
Tuttavia, alcuni eventi sono esclusivi 13 , nel senso che possono essere selezionati, per
ogni nestra, da un solo client alla volta.

1.3.6.1 Esempio
Nel seguito è presentato un semplice esempio di interazione client-server secondo il pro-
tocollo principale14 . L'applicazione client crea una nestra contenente un'area completa-
mente nera, e termina l'esecuzione alla pressione di un tasto qualunque. Sono trascurate,
per semplicità, le risposte del server.
11
Nel corpo del pacchetto di un evento sono riportati gli identicatori delle nestre coinvolte.
12
A questa categoria appartengono gli eventi di MapNotify.
13
Tra questi sono compresi gli eventi generati dai click del mouse, ed altri relativi al window management.
14
L'esempio è tratto da [Wik10e]

12
1.3 X Core Protocol

evento: click del mouse


nella finestra 4521

X server
attributi della finestra 4521
altezza

x
...
(altri attributi)

event mask

event mask

event mask
larghezza

client 3

client 2

client 1

Figura 1.3: In gura è mostrato un esempio di generazione e gestione di un semplice even-


to. Quando l'utente clicca con il mouse all'interno di una nestra, il server
genera un evento. Per decidere se l'evento deve essere propagato ai client
collegati alla nestra, il server confronta la tipologia dell'evento con le event
mask associate ad ogni client. Le maschere sono liberamente modicabili dai
client.

13
Concetti di base

1. Il client apre la connessione con il server e invia il pacchetto iniziale.

2. Il server accetta la connessione (ipotizzando che non sia richiesta alcuna forma
di autorizzazione) inviando il pacchetto di accettazione. Tra le informazioni co-
municate sono inclusi l'identicatore della root (ad esempio A) e l'insieme degli
identicatori utilizzabili dal client.

3. Il client richiede la creazione di un contesto graco C (si noti, ancora una volta,
che si stanno trascurando le risposte del server).

4. Il client richiede al server di creare una nestra top-level (per farlo si limitare a
specicare che il genitore deve essere A) con identicatore B. Il client invia anche
alcune indicazioni su dimensione e posizione della nestra.

5. Il client richiede un cambiamento degli attributi della nestra B. Nella richiesta


specica l'interesse per gli eventi Expose e KeyPress associati alla nestra.

6. Il client richiede che la nestra B venga mappata a schermo.

7. Il server elabora la richiesta, e rende visibile la nestra. Dato che nessuno ne ha


ancora disegnato il contenuto, questo risulta non valido, ed il server genera un
evento Expose. L'evento viene inviato al client in virtù della richiesta al punto 5.

8. Alla ricezione dell'evento, il client richiede che venga disegnata un'area rettangolare
di colore nero inviando una richiesta FillRectangle con identicatore di nestra B
e contesto graco C (opportunamente congurato).

Se la nestra viene coperta da un'altra nestra, o comunque non è più visibile, il suo
contenuto viene invalidato. Di conseguenza, la prossima volta che la nestra ritorna ad
essere visibile, il server invia un nuovo evento Expose per segnalare al client che la nestra
deve essere ridisegnata, a cui fa seguito la stessa reazione del client descritta al punto 8.
Per terminare l'esecuzione del programma, il client viene programmato per chiudersi
alla pressione di un qualunque tasto. Nello specico, alla ricezione da parte dell'evento
KeyPress, il client chiama exit o una funzione analoga.

1.3.7 Estensioni del protocollo


Il protocollo principale ha attraversato numerose revisioni nel corso degli anni no a che,
nel 1987 e sotto la spinta di numerose grandi compagnie, ne è stata formalizzata la ver-
sione 11 che, a tutt'oggi, rimane la versione corrente. In seguito si sono succedute diverse
revisioni che ne hanno modicato sostanzialmente l'implementazione di riferimento, sen-
za però alterare il protocollo15 . Il motivo di questa evoluzione è chiaro: essendo una
specica fondamentale, il protocollo X deve rimanere praticamente costante nel tempo.
15
In realtà l'evoluzione dell'X Window System è molto più complessa di quanto schematizzato qui in
poche righe. Il lettore interessato è rimandato a http://en.wikipedia.org/wiki/X_Window_System#
History.

14
1.4 X Programming

Quanto appena detto non deve far credere che non si sia rivelato possibile inserire
nuove funzionalità. Infatti, X è stato progettato per essere un sistema estremamente
essibile, grazie all'utilizzo delle cosiddette estensioni. Naturalmente, l'introduzione di
un'estensione provoca una modica nell'implementazione del server.
A questo scopo, il protocollo principale specica un sistema generale che permette ai
client di richiedere al server l'elenco delle estensioni supportate, e, per ognuna di essere,
l'insieme delle nuove richieste, dei nuovi eventi, messaggi di errore e delle nuove risorse
supportate16 .
I pacchetti di un estensione sono molto simili ai pacchetti del protocollo principale
nel formato e nell'uso che se ne fa. In particolare è importante notare che, come tutti
i pacchetti, possiedono un identicatore, tramite il quale possibile discriminare tra pac-
chetti di estensione e pacchetti core. Ogni estensione denisce una base ed un range e
tutti i suoi pacchetti devono essere contenuti in {base, base + range}. Per il protocollo
principale base = 017 .
Nel corso degli anni sono state realizzate numerose estensioni al protocollo principale.
Nei capitoli successivi saranno presentate le estensioni rilevanti ogni qual volta se ne
presenterà la necessità.
Per concludere il paragrafo è bene chiarire una dierenza: non bisogna confondere
l'estensibilità e la modularità del protocollo, con quelle dell'implementazione. Nel primo
caso infatti si sta parlando della possibilità di estendere le speciche alle quali tutte le
possibile implementazioni devono conformarsi, nel secondo caso si parla di come una
singola implementazione, conforme ad una certa versione del protocollo, possa essere
realizzata in maniera estendibile o modulare18 .

1.4 X Programming
Per realizzare un applicazione che sfrutti le potenzialità grache di Linux è necessario
poter interagire con il protocollo principale utilizzando linguaggi di programmazione
di alto livello. All'interno del concetto generale di applicazione graca, naturalmente,
ricadono client più complessi ed assimilabili a programmi di sistema, come gli stessi
window manager (vedi sezione2.1).
A questo scopo, l'implementazione di riferimento mette a disposizione una libreria C
per l'interfacciamento con il server X, nota come Xlib (1.4.1). Nel corso degli anni sono
nate dei binding di Xlib in altri linguaggi, nonché una riscrittura in C completamente
nuova, XCB.
Tuttavia, tutte queste alternative sono abbastanza di basso livello, e potenzialmente
inadeguate per applicazioni sempre più complesse. Per rimediare al problema sono state
16
Possono essere introdotte anche modiche ed estensioni alle risorse preesistenti, tramite l'introduzione,
ad esempio, di nuovi attributi.
17
Per esempio, alla richiesta di creare una nuova nestra è associato il numero 1, che sommato al valore
di base principale (0) fa sì che l'identicatore del pacchetto sia sempre 1.
18
Possibilmente anche in relazione alle evoluzioni del protocollo stesso.

15
Concetti di base

X Application

X Toolkit

Xlib

X protocol
Figura 1.4: La gura mostra la relazione che sussiste tra le applicazioni grache e le
librerie utilizzate per implementarle (toolkit e, a più basso livello Xlib). Si
noti come i toolkit sono basati a loro volta su Xlib. L'ultimo passaggio
esemplica la stretta relazione tra Xlib ed il protocollo X.

implementate collezioni di librerie al di sopra di Xlib, a volte degli interi framework, noti
complessivamente con il nome di toolkit (1.4.2).
Dopo una breve introduzione ad Xlib, nel seguito sono presentati tre dei toolkit più
importanti: GTK+ (1.4.3), Clutter (1.4.4) e Qt (1.4.5).

1.4.1 Xlib
Xlib è una API C tramite la quale è possibile realizzare applicazioni client all'interno
dell'X Windowing System [Nye92]. Chiamando le funzioni fornite da Xlib, l'applicazione
può interagire con il server senza che il programmatore debba conoscere i dettagli del
protocollo principale. Tutte le chiamate di libreria di Xlib sono opportunamente tradotte,
pacchettizzate ed inviate al server.
Per consentire l'utilizzo delle funzionalità dell'X Window System, Xlib deve tradurre
gli oggetti descritti dalle speciche del protocollo in strutture dati consistenti con il
linguaggio, per poi organizzarle e gestirle in maniera coerente. Sono due i principali
oggetti manipolati da Xlib: la struct Display e gli identicatori delle risorse (1.3.1).
Questi ultimi sono la perfetta controparte degli identicatori descritti dal protocollo,
hanno tipo XID, e sono rappresentati internamente come interi a 32 bit.
Display, al contrario, è più complessa. Contiene infatti una serie di informazioni sul
display sico al quale il client è connesso, ma soprattutto tutta una serie di parametri
associati alla connessione stessa. Per esempio, sotto un sistema operativo Unix, Display
conterrà, tra le altre cose, il riferimento al socket utilizzato per la connessione. La
maggior parte delle funzioni in Xlib richiedono una struttura Display come argomento:

16
1.4 X Programming

certamente in questa categoria ricadono tutte le richieste indirizzate al server. Tuttavia


sono comprese anche alcune funzioni locali che devono operare su dati specici ad una
certa connessione, come le funzioni che operano sulla coda degli eventi.
Le funzioni di Xlib che vengono tradotte in richieste del protocollo, non provocano
l'invio immediato del pacchetto. Al contrario, sono memorizzate in un buer interno
del client ed inviate al momento opportuno. Lo svuotamento del buer è assicurato
chiamando le funzioni XSync o XFlush.
Xlib traduce i pacchetti evento ricevuti dal server (1.3.6) nel formato XEvent e li
memorizza in una coda locale (event queue ). La libreria fornisce una serie di funzioni
per analizzare e gestire eventi presenti in coda. Secondo il protocollo, gli eventi sono
ricevuti asincronicamente dal server, mentre utilizzando Xlib a i client è richiesto di
usare esplicitamente una chiamata a funzione per poter interagire con gli eventi.
Al contrario, gli errori sono ricevuti e trattati asincronicamente. Ogni applicazione
può indicare una funzione particolare che si occupi della gestione degli errori: in caso
contrario viene utilizzato un gestore di default che si limita a stampare su terminale19
Per concludere il paragrafo, si ricorda che, recentemente, è stata realizzata una libreria
graca concorrente ad Xlib, nota come XCB [MS01]. Anche XCB è scritta in C e, sebbene
sia un progetto relativamente nuovo, in alcuni casi permette un notevole miglioramento
delle prestazioni. Questo è dovuto, in massima parte, alla sua natura prevalentemente
asincrona. Le chiamate ad Xlib, infatti, nella maggior parte dei casi, sono chiamate sin-
crone: ovvero bloccano l'esecuzione no a che non viene ricevuta una risposta dal server
o non vanno in timeout. Questo approccio è sicuramente più semplice da implementare,
e più veloce nel caso peggiore : con chiamate asincrone potrebbe accadere di dover an-
nullare un certo numero di operazioni già svolte in virtù di una risposta negativa o di un
errore arrivati in ritardo. Tuttavia, le prestazioni medie sono migliori con l'approccio di
XCB [Fon09].

1.4.2 X Toolkit
Xlib nasconde al programmatore molti dei dettagli dell'interazione e in conseguenza di
questo non è in corrispondenza 1 : 1 con il protocollo. Nonostante questo, però, il suo
utilizzo potrebbe risultare ancora troppo macchinoso o di basso livello.
Xlib, infatti, non prevede nessun supporto diretto per la creazione e la gestione di
oggetti graci non primitivi, come bottoni, menù, pannelli, e così via, ma si limita a
permettere il disegnare di sole linee, punti e rettangoli. Sebbene in ultima analisi gli
oggetti graci più complessi, o widget, siano composti di primitive, sarebbe più comodo
per il programmatore avere librerie che contengano collezioni di widget completi, e che
permettano di gestire relazioni tra widget diversi.
Per questi ed altri motivi, tra cui l'impossibilità siologica di scrivere codice portabile,
la normale programmazione graca spesso viene svolta con strumenti di più alto livello,
noti complessivamente come toolkit, o widget toolkit. Questi strumenti, in ogni caso, non
19
Si sta parlando del terminale sul quale è in esecuzione il client, non quello sico collegato al server.
La distinzione è importante, ma spesso i due terminali coincidono.

17
Concetti di base

gestiscono direttamente l'interazione con il protocollo e continuano ad appoggiarsi su


Xlib20 , che rappresenta, così, un punto di accesso privilegiato alle funzionalità grache
di X.
Si potrebbe pensare che l'utilizzo dei toolkit sia impossibile per quelle applicazioni che
hanno bisogno necessariamente di interagire a basso livello con X, come ad esempio i
window manager (che chiaramente non sono indipendenti dalla piattaforma). Quello che
succede in realtà è che, sebbene spesso sia necessario utilizzare direttamente chiamate
Xlib, buona parte della loro implementazione può essere realizzata a livello di toolkit
(vedi 2.1). Ad ogni buon conto, i toolkit principali agevolando le chiamate dirette ad
Xlib, ad esempio raccogliendone una parte come metodi di una convenience class 21 .
Nella gura 1.4 è mostrato un semplice schema riassuntivo delle relazioni che intercor-
rono tra applicazioni, toolkit, Xlib e protocollo.
In ogni caso, Prima di iniziare una panoramica più dettagliata delle singole toolkit
library,è bene evidenziare alcuni degli aspetti comuni che le caratterizzano. Originaria-
mente, le librerie grache nacquero come semplici collezioni di widget costruiti a partire da
Xlib. In questa categoria ricadono l'accoppiata X Intrinsic (Xt) e Motif, con la prima che
si proponeva come collezione di template per la costruzione di widget, e la seconda come
collezioni di possibili implementazioni, eventualmente estendibili e personalizzabili22 .
Nel corso degli anni, tuttavia, i toolkit più utilizzati sono cresciuti e sono diventati ben
più che collezioni di oggetti graci, per quanto complessi potessero essere. GTK+ e Qt,
tra gli altri, sono diventati dei veri e propri framework per la programmazione graca,
adatti per implementare applicazioni di ogni genere.
Una caratteristica comune a queste librerie è quella di adottare un modello di pro-
grammazione detto ad eventi, o event-driven. Secondo questo paradigma, il sistema non
aspetta che una certa istruzione impartisca al programma il comando di elaborare una
certa informazione. Al contrario, il sistema è predisposto per eseguire all'innito un loop
di istruzioni, all'interno del quale viene vericata continuamente l'arrivo di nuovi eventi.
In risposta alla ricezione di un evento, il codice all'interno del ciclo provvede a mandare
in esecuzione quella parte del codice (event handler ) scritta appositamente per gestire
l'evento in questione. Oltre ai suddetti handler, che possono essere predeniti e/o per-
sonalizzabili dal programmatore, un sistema del genere prevede la presenza di un'altra
componente fondamentale, il dispatcher, che si occupa di gestire la coda degli eventi ed
eettuare materialmente la chiamata ai gestori.

20
Ovviamente, si sta prendendo in considerazione il caso dell'X Window System, sebbene gli stessi toolkit
possano essere disponibili anche per sistemi graci dierenti.
21
Si pendi ad esempio alla classe QX11Info del toolkit Qt [Tro09c].
22
I widget che fanno parte di uno stesso toolkit hanno tipicamente il medesimo design, specialmente per
quanto riguarda l'aspetto estetico. In questa maniera si tende a dare all'utente un senso di coerenza e
di coesione tra parti diverse di una stessa applicazione e anche tra applicazioni diverse. A sua volta il
design è spesso grandemente personalizzabile, permettendo all'utente di selezionare, dinamicamente,
un tema comune a tutte le applicazioni appartenenti allo stesso toolkit. Addirittura, in alcuni toolkit
sono disponibili temi che emulano l'aspetto di default dei toolkit concorrenti, permettendo una totale
integrazione (a livello estetico) di applicazioni dalle origini diverse.

18
1.4 X Programming

Listato 1.1 Un semplice Hello World scritto in GTK. Nel codice è illustrato il paradigma
di segnalazione di GTK.
# include < gtk / gtk .h >

void destroy ( void ) {


gtk_main_quit ();
}

int main ( int argc , char * argv [])


{
GtkWidget * window ;
GtkWidget * button ;

gtk_init (& argc , & argv );

window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );


gtk_signal_connect ( GTK_OBJECT ( window ) , " destroy " ,
GTK_SIGNAL_FUNC ( destroy ) , NULL );
gtk_container_border_width ( GTK_CONTAINER ( window ) , 10);

button = gtk_button_new_with_label ( " Hello World " );


gtk_signal_connect_object ( GTK_OBJECT ( button ) , " clicked " ,
GTK_SIGNAL_FUNC ( gtk_widget_destroy ), GTK_OBJECT ( window ));

gtk_container_add ( GTK_CONTAINER ( window ) , button );


gtk_widget_show ( button );
gtk_widget_show ( window );
gtk_main ();
return 0;
}

1.4.3 GTK+
GTK+ è un toolkit basato su C che permette di creare interfacce grache [Har99]. GTK
sta per GIMP Toolkit è riette l'origine storica della libreria, immaginata inizialmente
come back-end per il noto programma per la gestione delle immagini. GTK è stato
a lungo la principale libreria graca per sistemi Unix. Di questi tempi, si contende il
primato con Qt (trattato nel paragrafo 1.4.5). Ambienti desktop integrati come Gnome
e XFce, e programmi del calibro di Firefox ed Inkscape sono basati sulle librerie GTK+.
Pur essendo scritta in un linguaggio, il C, che normalmente non prevede questo ap-
proccio, GTK+ è object-oriented grazie all'utilizzo del sistema ad oggetti fornito da Glib,
GObject .
23

Complessivamente, GTK+ è costruita a partire da una serie di librerie più a basso


livello, che comprendono [Prob]:

23
Tra l'altro utilizzando GObject è stato reso più agevole creare binding di GTK+ verso altri linguaggi
di programmazione come C++, Python, Perl, Java, eccetera.

19
Concetti di base

Glib: una libreria di utilità generale, citata in precedenza. Oltre al potente sistema
ad oggetti, mette a disposizione nuovi data type, funzionalità per manipolare le
stringhe, riportare gli errori, logging, multithreading, eccetera;

Pango e ATK: librerie che forniscono, rispettivamente, supporto per l'internazionaliz-


zazione e l'accessibilità.

GdkPixbuf: un toolkit per la gestione e la manipolazione delle immagini a livello di pixel.


Cairo: una libreria per la graca vettoriale 2D;
GDK: la parte di GTK+ che gestisce la comunicazione con le funzioni di basso livello
per il disegno e per la gestione delle nestre. Nell'implementazione Unix, GDK
permette a GTK+ di accedere ad Xlib e, attraverso quest'ultima, al protocollo X.
Recentemente, alcune di queste funzionalità di wrapping sono state delegate alla
libreria Cairo.

Il listato 1.4.3 mostra il codice di una semplice applicazione, tramite la quale può essere
mostrato il modello d'uso basilare di GTK. Applicazioni di questo genere sono comune-
mente note in informatica come Hello World. Esaminando il codice possono essere no-
tate alcune caratteristiche interessanti del toolkit, senza per questo dover fornirne una
trattazione formale. Per riferimento, la documentazione uciale può essere reperita in
[Lib10b]
Le chiamate a gtk_init e a gtk_main_quit segnano, rispettivamente, l'inizio e la ne
del ciclo eventi principale di GTK, condizione durante la quale l'applicazione può ricevere
ed inviare eventi ed in generale interagire dinamicamente con il server graco. La natura
ad oggetti emerge osservando i semplici esempi di creazione e gestione di una nestra
e di un bottone. La nestra, pur essendo sicuramente collegata all'omonima risorsa del
protocollo, risulta comunque un concetto completamente astratto ed indipendente dal-
l'implementazione, la cui gestione interna da parte di GTK normalmente non interessa al
programmatore. Il bottone invece è il più classico esempio di widget messo a disposizione
da GTK.
Sicuramente è molto importante osservare il meccanismo dei segnali e delle connessioni,
una delle caratteristiche principali di GTK. Versioni modicate, ma fondamentalmente
simili, di questo meccanismo sono comuni a molte altre widget library basate sul modello
di programmazione ad eventi (vedi paragrafo precedente).
Un segnale viene emesso da un widget alla ricezione di un particolare evento o combi-
nazione di eventi24 . Impostando una connessione con la chiamata gtk_signal_connect,
si richiede a GTK di chiamare una determinata funzione di callback alla attivazione del
segnale prescelto.
L'ultima chiamata degna di nota è gtk_container_add, che evidenzia la possibilità
di instaurare relazioni di inclusione (child-parent ) tra widget diversi. Queste relazioni,
in ultimi analisi, vengono tradotte da GTK nelle corrispondenti relazioni del protocollo
principale.
24
Nel listato 1.4.3 sono utilizzati segnali di default, ma è possibile denire segnali personalizzati.

20
1.4 X Programming

1.4.4 Clutter
Clutter, alla base di progetti come Moblin di Intel25 , è una libreria che graca che si inte-
gra con GTK+ e ne condivide molte delle caratteristiche [CC09, Cum08]. Clutter è ideale
per la creazione di interfacce grache tridimensionali, in quanto fornisce la possibilità di
lavorare ad alto livello con widget che sfruttano l'accelerazione OpenGL. Permette un
approccio più immediato al 3D, quindi, di altri toolkit o della programmazione diretta
in OpenGL, pur consentendo all'utente, qualora lo desideri, di inserire codice GL per
lavorare direttamente a contatto con la scheda graca. Su dispositivi embedded, Clutter
può usare OpenGL ES, un sottoinsieme ristretto di OpenGL.
Vi è anche uno svantaggio in questa relazione così stretta con OpenGL: l'intera inter-
faccia di Clutter è immaginata dando per scontato come il rendering delle applicazioni
avvenga unicamente tramite OpenGL, e non è possibile, o risulta comunque estrema-
mente dicile, andare a modicare questa dipendenza. In altri toolkit, come Qt, il
motore di rendering è completamente indipendente dal codice principale, per cui è possi-
bile realizzare applicazioni che utilizzano contemporaneamente più modalità di rendering
(2.3.4).
Analizzando il semplice codice riportato (listato 1.4.4) salta subito agli occhi la somiglian-
za tra Clutter a GTK+, sia per quanto riguarda l'utilizzo di Glib e del sistema GObject,
sia per la forma simile che assumono molte delle chiamate a funzione.
Tuttavia emerge anche una dierenza fondamentale; l'utilizzo, da parte di Clutter, di
un paradigma particolare, noto come modello actor-stage. Il modello prevede che og-
ni widget e ogni oggetto graco appartenga ad una classe generale, quella degli attori.
Si può accedere alle proprietà di ogni attore (posizione, dimensione, colore, e così via)
tramite un'interfaccia comune. Anché sia visibile a schermo, un attore dev'essere as-
sociato ad una scena, una classe di oggetti atta a contenere attori; la scena di default
restituita da clutter_stage_get_default, corrisponde in X11 ad una nestra top-level.
La caratteristica interessante è che la scena stessa può essere vista a sua volta anche
un attore, di cui possiede le medesime proprietà. In questa maniera è possibile creare
gerarchie di scene annidate.
Per quanto riguarda l'evoluzione dinamica, in Clutter è presente lo stesso sistema di
segnali e connessioni presente in GTK; per vederlo è suciente osservare come la rma
di g_signal_connect sia simile a quella di gtk_signal_connect.
Tuttavia vi sono anche altre dierenze con GTK, dovute alla predisposizione di Clutter
verso il 3D. Infatti, Clutter mette a disposizione una serie di classi e di funzioni partico-
larmente utili per la costruzione di interfacce tridimensionali. Ad esempio, in Clutter è
presente una classe che automatizza la conversione di Pixmap X11 in texture OpenGL.
Come si vedrà questa caratteristica è estremamente utile per l'implementazione di un
compositing manager che sfrutta OpenGL quale proprio motore di rendering, e che uti-
lizza pesantemente l'estensione Texture from Pixmap di GLX (vedi 2.3.3 per la teoria, e
2.7.1 per l'implementazione).

25
http://moblin.org/projects/clutter

21
Concetti di base

Listato 1.2 Un semplice Hello World scritto con Clutter. Si notino analogie e dierenze
con un puro approccio GTK+.
# include < clutter / clutter .h >

static gboolean destroy_stage


( ClutterRectangle * rect , ClutterEvent * event , gpointer unused )
{
clutter_actor_destroy ( stage );
return TRUE ; /* non gestisco più l ' evento */
}

int main ( int argc , char * argv [])


{
ClutterColor stage_color = {0 x00 , 0 x00 , 0 x00 , 0 xff };
ClutterColor actor_color = {0 xff , 0 xff , 0 xff , 0 x99 };
ClutterActor * stage ;
ClutterActor * label ;

clutter_init (& argc , & argv );

stage = clutter_stage_get_default ();


clutter_actor_set_size ( stage , 300 , 200);
clutter_actor_set_color ( CLUTTER_STAGE ( stage ) , & stage_color );
g_signal_connect ( stage , " destroy " ,
G_CALLBACK ( clutter_main_quit ) , NULL );

label = clutter_text_new_full ( " Sans 32 px " ,


" Hello world " , & actor_color );
clutter_actor_set_size ( label , 200 , 100);
clutter_actor_set_position ( label , 50 , 50);
g_signal_connect ( label , " button - press - event " ,
G_CALLBACK ( destroy_stage ) , NULL );

clutter_container_add_actor ( CLUTTER_CONTAINER ( stage ) , label );


clutter_actor_show ( label );
clutter_actor_show ( stage );
clutter_main ();
return EXIT_SUCCESS ;
}

22
1.4 X Programming

Listato 1.3 Un semplice Hello World scritto in Qt. Si noti l'utilizzo di molte tecniche
object-oriented.

# include < QApplication >


# include < QPushButton >
# include < QWidget >

class MyWidget : public QWidget


{
public :
MyWidget ( QWidget * parent = 0);
};

MyWidget :: MyWidget ( QWidget * parent ) : QWidget ( parent )


{
QPushButton * hello = new QPushButton ( tr ( " Hello World " ) , this );
connect ( hello , SIGNAL ( clicked ()) , qApp , SLOT ( quit ()));
setFixedSize (200 , 120);
hello - > setGeometry (62 , 40 , 75 , 30);
}

int main ( int argc , char * argv [])


{
QApplication app ( argc , argv );
MyWidget widget ;
widget . show ();
return app . exec ();
}

Per concludere ricordiamo che, tra le altre caratteristiche, Clutter semplica enorme-
mente la creazione delle animazioni. A questo scopo mette a disposizione una timeline ed
un interfaccia che permette di associare alcune proprietà degli attori (come posizione, ro-
tazione o trasparenza) al valore di funzioni (in generale) tempo-varianti come, ad esempio,
una sinusoide.
Nella sezione2.7 viene mostrato il codice completo di un semplice compositing manager
d'esempio, la cui implementazione è basata proprio su Clutter.

1.4.5 Qt
Qt26 è una delle librerie grache più importanti e diuse, ed è alla base di un progetto
come KDE, un ambiente desktop supportato attualmente in moltissime distribuzioni
Linux27 . Maggiori informazioni su Qt, sono reperibili in [BS08] e naturalmente sulla
documentazione uciale [Tro09c].

26
La pronuncia è la stessa del termine inglese cute .
27
http://www.kde.org/download/distributions.php

23
Concetti di base

Tra le numerose applicazioni che ne fanno uso, si possono citare VLC, VirtualBox
e Skype. Inoltre, esistono anche numerosi binding di Qt per i principali linguaggi di
programmazione.
Originariamente Qt è stata rilasciata dalla norvegese Trolltech che, però, è stata ac-
quisita da Nokia nel 2008. Non dovrebbe dunque destare sorpresa che buona parte dello
sviluppo dell'interfaccia utente del nuovo sistema operativo di Nokia sia stato svolta
proprio utilizzando Qt (3.3.3).
Nel corso degli anni Qt si è evoluto in un completo e complesso framework di pro-
grammazione, le cui release comprendono, oltre che le librerie vere e proprie, una serie
di applicativi di supporto allo sviluppo. Tra questi è compresa una vasta libreria di pro-
grammi di esempio, nonché un IDE completo, Qt Designer [Tro09b], attraverso il quale
è anche possibile creare interfacce grache tramite un approccio puramente WYSIWYG
(What You See Is What You Get ) .
Una caratteristica fondamentale di Qt è l'inerente portabilità del codice, grazie alla
quale è possibile riutilizzare lo stesso sorgente su molteplici piattaforme28 .
A dierenza di GTK e Clutter, Qt è scritta in C++ e quindi supporta naturalmente il
paradigma di programmazione ad oggetti. Il codice presentato nel listato 1.4.5) mostra
un esempio dell'uso intensivo che si fa in Qt di concetti come l'ereditarietà. Nell'esempio
è stata costruita una classe di widget personalizzata, glia di QWidget, la classe generale
che rappresenta i widget in Qt. QWidget è una classe molto generale: sono sue istante
sia vere e proprie nestre, sia componenti più elementari come i bottoni.
Si noti la presenza di una classe particolare, QApplication, che gestisce il ciclo eventi
principale e le chiamate agli event-handler, alla base del paradigma di programmazione
ad eventi.
Sempre nel codice, può essere mostrato un semplice esempio dell'uso che si può fare in
Qt delle connessioni. In Qt il paradigma viene chiamato signal-slot, dove gli slot sono i
metodi di callback. Come detto in precedenza, GTK+ e Clutter mettono a disposizione
dei modelli analoghi, ma in Qt l'implementazione del paradigma di segnalazione risulta
molto più avanzata e per questo molto più complessa. Il prezzo da pagare è che tutte
le applicazioni Qt devono essere pre-compilate da un meta-compilatore, il Meta Object
Compiler. MOC difatti si occupa di riscrivere i sorgenti Qt, includendo codice in grado
di dare pieno supporto a run-time per l'invio di segnali, l'attivazione degli slot, e così via.
Per semplicare questo ed altri problemi, in ogni distribuzione Qt è compreso an-
che un programma, qmake, un'estensione di make in grado di eettuare i vari passi della
(ri)compilazione in maniera trasparente, o quasi, per l'utente. L'operato di qmake dipende
da alcuni particolari le di congurazione, simili a dei Makele 29 , tramite i quali il pro-
grammatore indica dipendenze, opzioni del linker e del compilatore, librerie da includere,
e così via.
28
Qt è un framework per la programmazione di applicazioni ed interfacce grache multi-piattaforma.
Utilizzando Qt, è possibile scrivere una sola volta un gran numero di applicazioni con pieno supporto
web, per poi poterle utilizzare su un gran numero di sistemi desktop, mobili ed embedded senza dover
riscrivere da capo il codice sorgente. Liberamente tradotto da [Noke].
29
I Makele sono i le di congurazione di make.

24
1.5 Qt Graphics View Framework

Per concludere, si ricorda che, a partire dalla versione 4.2 di Qt, è stata introdotta in
Qt un'architettura molto interessante, il Graphics View Framework. Alla sua descrizione
è dedicata l'intera sezione 1.5. Un interesse di questa portata è motivato dalla possibilità
di utilizzare questo framework come base per l'implementazione di window manager
innovativi, come il MeeGo Compositor a cui è dedicato l'intero capitolo 4. Inoltre, la
libreria graca utilizzata per l'interfaccia di MeeGo Handset è in buona parte basata
proprio su Graphics View (3.4).

1.5 Qt Graphics View Framework


Il Graphics View Framework [Tro09a] modica il noto paradigma di programmazione
model-view, basato sulla rigida separazione tra contenuto e rappresentazione, introducen-
do un approccio basato sugli oggetti, o item [Ber07].
La principale caratteristica del framework è quella per cui, sebbene esista un solo
insieme di dati, questo non preclude l'esistenza di numerosi punti di vista tramite cui
poterli osservare.
Riassumendo al massimo, il Graphics View Framework mette avere a disposizione:

• una contenitore (scena ) in grado di gestire un gran numero di oggetti graci 2D.

• un widget (vista ) associato al contenitore, attraverso il quale è possibile visualizzare


gli oggetti gestiti.

Una scena può comprendere una qualunque forma geometrica o, più in generale, un
qualunque oggetto. In questa categoria possono essere inclusi elementi arbitrariamente
complessi, da semplici widget a intere interfacce. Generalmente, se un oggetto fa parte
di una scena ci si riferisce ad esso come item 30 .
Nel framework è inclusa un'architettura di propagazione degli eventi estremamente
precisa, tramite la quale gli eventi, inizialmente ricevuti dalla vista, vengono dirottati
agli oggetti sottostanti. In questa maniera non è necessario lasciare l'onere della risposta
agli eventi alla scena o ad una qualche altra struttura centralizzata.
Per tenere traccia degli item contenuti in una scena, l'implementazione utilizza una
struttura particolare, nota come albero a partizione binaria dello spazio (BSP tree ). In
questa maniera, operazioni come la gestione del posizionamento o il calcolo delle collisioni,
possono essere svolte in maniera molto veloce ed eciente. Inoltre, la struttura è molto
scalabile, e permette la gestione di scene complesse in tempo reale 31 .
30
Nel seguito saranno spesso usati come sinonimi i termini item e oggetto (la più naturale traduzione
del primo termine). Per evitare confusione, dato che in informatica la parola oggetto può acquisire
n troppi signicati dierenti, si utilizzerà con maggiore frequenza il termine inglese.
31
Quello che succede, in realtà, è che Qt è molto rapido a calcolare quali oggetti o quali loro parti siano
visibili in un dato momento. Questo non implica che la scena sia renderizzata rapidamente, in quanto
questo dipende dagli algoritmi di disegno, dal sistema graco sottostante, e alla ne dei conti dalla
capacità della macchina. Il vantaggio di Graphics View è quindi un vantaggio relativo: ad esempio
si può vericare che questa architettura è più veloce dell'utilizzo di QWidget separati per ciascun
oggetto [Blo09].

25
Concetti di base

1.5.1 Scene
Secondo il modello, una scena deve:

• mettere a disposizione una serie di funzioni ragionevolmente veloci, atte a gestire


un grande numero di oggetti;

• fornire un'infrastruttura per la propagazione degli eventi (dispatching ) agli oggetti


opportuni;

• gestire lo stato degli oggetti.

Una scena può essere vista come un contenitore di oggetti. In Qt, la classe QGraphic-
sScene è usata per implementare le funzionalità di una scena, mentre gli oggetti sono
implementati come istanze della classe QGraphicsItem 32 . Gli item sono aggiunti alla
scena chiamando QGraphicsScene::addItem(). Per il recupero degli oggetti associati
alla scena sono messe a disposizione alcune particolari funzioni di discovery. Ad esempio
le dierenti versioni della funzione items() ritornano gli oggetti contenuti o intersecati
da una certa geometria, mentre itemAt() ritorna l'oggetto in primo piano rispetto ad
un punto particolare dello spazio. Tutte queste funzioni elencano gli oggetti in ordine
discendente, dal più vicino (rispetto all'utente, e dunque dall'oggetto con coordinata z
maggiore) al più lontano.
Nell'esempio seguente è illustrata la procedura di creazione di una scena e di un oggetto
(un'ellissi).
QGraphicsScene scene ;
QGraphicsEllipseItem * ellipse = scene . addEllipse ( QRectF (0 , 0 , 100 , 50));
QGraphicsItem * item = scene . itemAt (50 , 50);
// item == ellipse

L'architettura di propagazione implementata in QGraphicsScene riceve gli eventi, ne


modica il sistema di coordinate, ne gestisce lo scheduling, ed inne gli invia agli oggetti
corripondenti. Ad esempio, se la scena riceve un click del mouse, individua l'oggetto
a cui quel click è destinato, traduce le coordinate dell'evento nel sistema di riferimento
dell'oggetto e, al momento opportuno, trasmette l'evento all'oggetto.
Un'altra funzionalità della classe è quella di gestire alcuni stati particolari degli ogget-
ti che ne fanno parte: il focus e la selezione. Un oggetto è a fuoco se è attivo. Tra le
altre cose, gli eventi di tastiera sono diretti all'oggetto attivo, ma il concetto è più gen-
erale. Dal punto di vista della API, per selezionare un oggetti si può utilizzare la funzione
setSelectionArea(), passando come parametro una forma geometrica arbitraria. Ques-
ta funzionalità è chiamata, ad esempio, quando l'utente seleziona in una vista gli oggetti
di proprio interesse. Il metodo più comune è l'utilizzo di una rubberband, un'area rettan-
golare di cui è visibile solo il contorno, creata tramite click e trascinamento del cursore
del mouse. Per ottenere l'elenco di tutti gli oggetti selezionati si usa selectedItems().
32
Da questo momento in poi con i termini scena, oggetto o vista si intenderanno indierentemente sia i
concetti astratti descritti dal modello, che le loro implementazioni.

26
1.5 Qt Graphics View Framework

Figura 1.5: Due rappresentazioni diverse dello stesso insieme di dati. L'immagine è tratta
da un programma di esempio allegato a [BS08].

L'ultima macro-funzionalità fornita da QGraphicsScene è quella che consente il ren-


dering. Tramite la chiamata render() è possibile disegnare porzioni della scena in un
qualunque paint device, come una QImage o una stampante. Esistono due versioni di
render() a dir la verità: una è un metodo di QGraphicsScene, l'altra di QGraphicsView.
Le funzioni condividono la stessa API, la dierenza è nel sistema di coordinate utiliz-
zato: nel primo caso è quello della scena, nel secondo quello della vista, che riette
dell'interazione con l'utente.

1.5.2 View
La classe QGraphicsView implementa il concetto di vista, un astrazione tramite la quale
è possibile visualizzare il contenuto di una scena.
Il modello Graphics Viewpermette di collegare viste diverse alla stessa scena, perme-
ttendo così di avere punti di vista diversi sul medesimo insieme di dati (gura 1.5). Si
può dire che questa caratteristica sia proprio il cuore del paradigma stesso.
Ad una vista è necessario associare una ed una sola viewport, la componente dell'in-
terfaccia graca sulla quale avviene eettivamente il rendering graco. Tendenzialmente
una viewport è un area di scrolling, e l'implementazione base mette a disposizione una
serie di barre laterali per muoversi all'interno di scene particolarmente grandi.
Grazie a questo meccanismo, risulta estremamente facile ed immediato abilitare il
supporto al rendering accelerato. Ad esempio, impostando come viewport un QGLWidget,
si fa sì che tutti gli oggetti siano disegnati tramite chiamate OpenGL.
Nell'esempio viene mostrato come sarebbe possibile creare una vista ed una viewport,
per poi collegarle ad una scena33 :
33
Nell'esempio è anche abilitato il supporto all'antialiasing (vedi QGLFormat::sampleBuffers()).

27
Concetti di base

QGraphicsScene scene ;
populateScene (& scene ); // funzione custom
QGraphicsView view (& scene );
QGLWidget * glw = new QGLWidget ( QGLFormat ( QGL :: SampleBuffers ));
view . setViewport ( glw );
view . show ();

L'interazione con l'utente avviene interamente attraverso una vista. Ad essa, infat-
ti, sono diretti inizialmente tutti gli eventi interattivi generati dall'utente, ed è precisa
responsabilità della view convertire ed inviare questi eventi alla scena.
Riassumendo, la sequenza di gestione degli eventi è la seguente:
1. l'utente interagisce con la vista (più precisamente con la viewport associata); l'in-
terazione provoca la generazione di alcuni eventi, espressi nelle coordinate della
vista;

2. la vista riceve gli eventi e li traduce nel sistema di coordinate di scena; la vista
invia gli eventi alla scena;

3. La scena riceve gli eventi, individua gli oggetti interessati e traduce le coordinate
di scena nelle coordinate oggetto appropriate; la scena invia gli eventi agli oggetti.
Per la conversione discussa al punto 2, è utilizzata una opportuna matrice di trasfor-
mazione. Per semplicità sono fornite due convenience function che descrivono il pas-
saggio tra i due sistemi di coordinate: mapToScene() e mapFromScene(). Utilizzando
opportunamente le trasformazioni è possibile implementare funzionalità di navigazione
molto comuni come zoom e rotazioni.

1.5.3 Item
QGraphicsItem è la classe base con la quale è implementato il modello degli item. Da
QGraphicsItem discendono tutti i vari widget che possono essere inclusi in una QGraph-
icsScene. Sono istanze di questa classe oggetti graci standard e abbastanza comuni
come rettangoli (QGraphicsRectItem ), ellissi (QGraphicsEllipseItem ) e riquadri di testo
(QGraphicsTextItem ). Tuttavia è possibile, e spesso diventa necessario, costruire una
propria sottoclasse personalizzata, dalle proprietà speciche (gura 1.6).
Secondo il modello architetturale, ogni oggetto:
• reagisce agli eventi del mouse, compresi click, movimento, hover, etc.;

• sceglie se accettare o meno il focus da tastiera; in caso aermativo gestisce gli eventi
di tastiera;

• si presta all'utilizzo tramite drag & drop ;

• può essere raggruppato con altri oggetti, sia tramite relazioni genitore-glio, sia
tramite la classe QGraphicsItemGroup

• si occupa di riconoscere e noticare l'eventuale collisione con un altro oggetto;

28
1.5 Qt Graphics View Framework

Gli oggetti vivono in un sistema di coordinate locali. Così come QGraphicsView for-
nisce delle funzioni per passare dalle coordinate di vista a quelle di scena (e viceversa),
QGraphicsItem fornisce una serie di metodi che permettono di trasformare le proprie
coordinate locali in coordinate di scena o addirittura in coordinate locali di un altro
oggetto. Analogamente a quanto detto a proposito della vista, è possibile implementare
rotazioni e riscalamenti arbitrari dei singoli oggetti tramite matrici di trasformazione
locali.
QGraphicsItem supporta la collision detection tramite le funzioni virtuali shape()
e collidesWith(). Creando un oggetto personalizzato, l'unica preoccupazione dell'u-
tente, per quanto riguarda le collisioni, sarà quella di descrivere opportunamente la forma
dell'oggetto attraverso shape()34 .
Il framework permette che ad una scena siano aggiunti anche oggetti complessi. Con le
ultime versioni di Qt, infatti, è possibili inserire una scena un qualunque widget. Questo
signica che è possibile inserire intere main window o widget tridimensionali all'interno
di una scena. Allo scopo è utilizzata QGraphiscScene::addWidget(). L'architettura
permette di integrare completamente i widget all'interno di una scena: questo vuol dire
che saranno mantenute invariate la gestione degli eventi e dei widget gli, le animazioni,
le modiche dell'aspetto del cursore, la gestione del focus, eccetera. Dato che QGraph-
icsView è a sua volta un QWidget, è persino possibile includere una vista all'interno di
una scena, in modo da creare scene nidicate estremamente complesse. Questa tecnica
è utilizzata da libmeegotouch (3.4).

1.5.3.1 Nota per i sistemi embedded


Per poter trasformare ed animare rapidamente e con precisione una scena e le sue com-
ponenti, il Graphics View framework è stato progettato assumendo che l'hardware sia in
grado di svolgere operazioni in virgola mobile in maniera ragionevolmente veloce.
Tuttavia, molte macchine embedded non svolgono le operazioni in virgola mobile in
hardware, ma si limitano ad emularle via software. Il risultato è che alcune operazioni
potrebbero risultare signicativamente più lente; il programmatore può tentare di miti-
gare il problema ottimizzando il codice sotto altri aspetti. Una soluzione potrebbe essere
quella di usare OpenGL come motore di rendering, anche se l'applicazione si limita ad
utilizzare oggetti bidimensionali35 .

34
L'implementazione base di QGraphicsItem si occupa del resto.
35
Ovviamente in mancanza di scheda graca accelerata, tale soluzione introdurrebbe un ulteriore
elemento di emulazione software, peggiorando solo la situazione.

29
Concetti di base

QtGraphicsRectItem QtGraphicsEllipseItem QtGraphicsLineItem

Cat for sale


She is gray
Cat for sale and long-haired
with a small nose

QtGraphicsPolygonItem QtGraphicsSimpleTextItem QtGraphicsTextItem

QtGraphicsPathItem QtGraphicsPixmapItem QtGraphicsWidget

Figura 1.6: In gura vengono mostrate alcuni dei più comuni QGraphicsItem. Il concetto
può essere generalizzato no ad includere widget arbitrariamente complessi
[BS08]. Nel riquadro in basso a destra è mostrata un'immagine di WolfenQt
[Blo08].

30
Capitolo 2

Compositing manager
In questo capitolo, il più corposo, viene svolto il lavoro di caratterizzazione dei composit-
ing manager o compositori.
Nella prima sezione vengono descritti i classici window manager, mentre le sezioni
successive sono dedicate interamente ai compositing manager.
Per prima cosa ne viene illustrata l'architettura generale (2.2). Successivamente è
presentato un approfondimento sulle diverse tecniche di rendering a disposizione del pro-
grammatore (2.3), seguito da una descrizione dei più comuni eetti graci implementabili
grazie alle tecniche di composizione (2.4).
Nella sezione 2.5 vengono illustrate le principali dierenze tra la composizione in ambito
desktop e quella in ambito embedded.
La sezione 2.6 fornisce alcune note implementative, utili per comprendere come possano
essere utilizzati, nel concreto, i meccanismi descritti in precedenza. Il capitolo termina
con l'analisi dettagliata di un piccolo compositing manager basato su Clutter (sezione
2.7).

2.1 Window Manager


Fondamentalmente, un window manager 1 è una componente dell'interfaccia graca che si
occupa della gestione delle nestre. Dato che oggi giorno i paradigmi di interazione sono
basati sulle nestre, il window manager è probabilmente la componente più importante
del sottosistema graco.
Generalmente, tutti i window manager includono almeno le seguenti funzionalità:

• gestione del posizionamento e del dimensionamento delle nestre;

• tracciamento dinamico delle relazioni tra nestre;

• gestione adeguata dell'input utente, e redirezione degli eventi alle applicazioni.


1
Nel corso del testo il termine è spesso abbreviato in WM o in gestore, se ciò non comporta il nascere
di ambiguità.

31
Compositing manager

In realtà, la grandissima maggior parte dei WM supporta una serie di funzionalità


aggiuntive, fra le quali:

• gestione dell'aspetto graco ed eventualmente della decorazione delle nestre;

• gestione degli eventi di interazione con la nestra radice;

• gestione di menù e pannelli non direttamente legati ad alcuna nestra particolare;

• gestione diretta di alcuni input da tastiera (ad esempio, la nota combinazione


Alt-F4).
La maggior parte dei window manager permette inoltre di selezionare una serie di appli-
cazioni, che vengono mandate in esecuzione durante l'avvio dello stesso gestore. In questa
categoria potrebbero essere compreso lo stesso compositing manager, o un applicazione
separata che si occupi, ad esempio, della decorazione.
I window manager non dovrebbe essere confusi con gli ambienti desktop. Un desktop
environment, infatti, è una componente più generale, di cui il gestore delle nestre è
una parte fondamentale, ma non è l'unica. All'interno di un'ambiente desktop possono
coesistere una serie di librerie o applicazioni di contorno atte a gestire ogni aspetto
dell'interazione tra l'utente e l'interfaccia graca.
Chiaramente, ognuno dei principali sistemi operativi include un proprio sottosistema
graco, che modica, a volte anche notevolmente, le considerazioni che possono essere
fatte a proposito dei relativi window manager. Ad esempio WM diversi possono essere
implementati come applicazioni esterne o essere integrati nel corrispondente windowing
system.
In questa sede, tuttavia, ci si vuole concentrare sugli X Window manager, ovvero per
quei WM costruiti al di sopra dell'X Window system.
Dopo una breve introduzione sull'argomento(2.1.1), vengono approfondite le tematiche
legate alle decorazione (2.1.2), seguite da una breve classicazione dei window manager,
basata sulla modalità di costruzione della rappresentazione (2.1.3). La sezione si con-
clude con la discussione dei fondamentali protocolli ICCCM e EWMH, che specicano le
modalità di interazione con i client applicativi (2.1.4).

2.1.1 X Window manager


Un X Window Manager è un client in esecuzione in un contesto X11, che aderisce alle
speciche del protocollo principale e si conforma al modello architetturale dell'X Window
System.
Quando è in esecuzione2 , il window manager si interpone tra il server e i vari client
applicativi, potendo così mediare alcune delle interazioni tra le due parti. Tipicamente
2
Potrebbe sembrare paradossale, data l'importanza che si è attribuita ai WM, ma non è strettamente
necessario che vi sia un window manager attivo per ogni istanza del server. In assenza di un WM, le
applicazioni sono mostrate in una zona ssata del display (tipicamente l'angolo superiore sinistro).
Non è presente nessuna decorazione, e non è possibile interagire con le nestre in nessuna maniera
che non sia esplicitamente prevista dall'applicazione stessa.

32
2.1 Window Manager

le mediazione è totale, nel senso che vengono gestite tutte le nestre presenti sul display
prescelto.
Il compito fondamentale di un X Window manager è la costruzione a schermo di
una opportuna rappresentazione dell'albero delle nestre. Generalmente, un X window
manager non si occupa del redering, che viene lasciato all'interazione diretta tra i client
e il windowing system. Le modalità di costruzione della rappresentazione variano da
un window manager all'altro, e costituiscono la base della classicazione presentata al
paragrafo 2.1.3.
Allo scopo di controllare le interazioni dei client con le nestre, ogni richiesta di map-
ping da parte dei client viene intercettata dal gestore, che, tra le le altre cose, stabilisce
l'eettivo posizionamento della nestra, eventualmente ignorando le indicazioni fornita
dal client. Inoltre, la maggior parte degli X window manager sono re-parenting, il che
permette l'implementazione delle decorazioni. (vedi 2.1.2).
In generale, i window manager sono anche responsabili della riduzione ad icona delle
nestre3 . In seguito a una richiesta di questo genere, gli X window manager reagiscono
ponendo la nestra fuori dall'area di visibilità (unmapping ) e facendo sì che al suo posto
sia mostrata una rappresentazione stilizzata, sul cui aspetto e posizione il WM ha il
controllo completo.
Questo aspetto non è standardizzato dal protocollo principale, così un client che volesse
occuparsi direttamente di questo aspetto, senza adarsi alla gestione di default da parte
del WM, dovrebbe andare a modicare le corrispondenti proprietà ICCCM (2.1.4).

2.1.2 Re-parenting e decorazione


Un window manager può adottare due strategie di base per la gestione delle nestre. La
prima è quella per cui il gestore lascia immutato l'albero gerarchico in cui sono strutturate
le nestre. Così facendo, le nestre top-level rimangono dirette discendenti della nestra
radice.
La seconda, sicuramente più interessante, prevede che il window manager modichi la
gerarchia delle nestre tramite la tecnica di re-parenting, secondo la quale ogni nestra
top-level, e di conseguenza l'intero ramo che da queste ha origine, viene resa glia di una
nuova nestra. Lo scopo di questa strategia è quello di permettere la decorazione delle
nestre, ovvero quello di associare a ciascuna nestra una sorta di cornice decorativa,
tramite la quale l'utente può richiamare alcune delle funzioni fondamentali del window
manager4 .
Andiamo a vedere come la modica della gerarchia sia collegata alla decorazione. Si
è visto in precedenza come il server informi i window manager ogni qual volta che una
nestra top-level viene mappata a schermo. La risposta di un WM re-parenting è quella
di creare una nuova nestra, di dimensione poco superiore a quella della nestra appena
mappata, e che contiene una semplice cornice, o frame. Nella maggior parte dei casi
3
In realtà non tutti i window manager garantiscono il supporto alle icone. Del resto, neanche ICCCM
obbliga a farlo.
4
Della decorazione si era già accennato, dal il punto di vista del protocollo principale, nel paragrafo
1.3.3.

33
Compositing manager

Barra del titolo Icone

Client area

Cornice

Figura 2.1: Una nestra gestita dal window manager di Gnome, Metacity. La zona cen-
trale rappresenta quella che è l'area visibile all'applicazione. Sono indicati
anche i principali componenti della decorazione: una cornice che corre lungo
tutta la nestra, una barra di stato, che contiene il nome della nestra, ed
alcune semplici icone a cui corrispondono alcune azioni standard, gestite dal
window manager: riduzione a icona, ridimensionamento, chiusura.

34
2.1 Window Manager

viene anche creata un'ulteriore nestra, che comprende unicamente una barra in cui
viene mostrato il nome della nestra applicativa. Il re-parenting consiste nel rendere
glie della cornice, sia la nestra applicativa che la barra del titolo. Nel farlo, il gestore
deve, ovviamente, curare posizioni e dimensioni relative delle nestre, in modo da ottenere
l'eetto voluto. Nel caso siano previste, possono essere creati anche ulteriori oggetti di
decorazione, come i bottoni di chiusura o di riduzione ad icona. La strategia da seguire
è sempre la stessa: nel caso dei bottoni devono essere create delle nestre apposite, che
poi devono essere rese glie della nestra che contiene la barra del titolo.
La tecnica del re-parenting è utilizzata, oggigiorno, dalla quasi totalità dei window
manager. La prima soluzione rimane appannaggio di quei pochi window manager che
non implementano le decorazioni, come dwm, XMonad o ratpoison 5 .

2.1.3 Classicazione
L'architettura dei window manager risponde ad uno dei principi basilari di X, e di Unix
in generale, secondo il quale che un comportamento complesso può essere ottenuto dalla
collaborazione di più componenti indipendenti ma collegate tra di loro, più che su di
unico parte che cerchi di accentrare in se tutte le funzionalità richieste. Gli X window
manager, sono infatti, un modulo del sistema graco, non una componente integrato.
Non deve stupire dunque, che n dagli inizi, sono nati numerosi window manager, spesso
molto diversi l'uno dall'altro6 .
Inoltre, ogni WM può essere a sua volta estremamente personalizzabile e congurabile,
il che conferisce all'insieme una varietà ancora maggiore.
Il contemporaneo successo di così tanti modelli, anche molto diversi, è da attribuire
alla varietà che contraddistingue gli utenti, nonché ai numerosi segmenti di mercato in
cui sono diuse le interfacce grache, non più appannaggio dei soli sistemi desktop.
Proprio in questo aspetto risiede la dierenza principale fra i window manager per X
e quelli forniti nei sistemi Apple e Microsoft, che storicamente sono stati sempre stretta-
mente integrati nel sistema graco ed abbastanza limitati in funzionalità e congurazione.
Come detto, i vari X window manager dieriscono tra di loro sotto molti punti di vista,
fra cui il grado di personalizzazione, il livello di integrazione con l'ambiente desktop e,
passando alle dierenze implementative, le performance e l'occupazione di memoria. In
questa sede tuttavia, si preferisce classicare i window manager in un modo alternativo,
strettamente legato alla gestione vera e propria delle nestre. Con un po' di attenzione, è
possibile utilizzare la classicazione proposta anche per ripartire WM realizzati per altri
sistemi graci7 .
5
C'è un'eccezione, che vale la pena citare. Lo stesso Compiz, forse il più celebre window compositing
manager, no a poco tempo fa non utilizzava il re-parenting, ma si occupava di disegnare le decorazioni
come parte del processo di composizione vera e propria. A partire dalla versione 0.9.0 Compiz ha
cambiato strategia, in modo da poter funzionare da completo window manager anche nel caso in cui
la composizione viene disattivata [Spi10].
6
Questo stesso discorso, qui centralizzato sui window manager, può essere generalizzato ai numerosi
desktop environment disponibili e alle loro rispettive caratteristiche.
7
Un elenco abbastanza completo di window manager, ripartiti per ognuna delle categorie presentate, è
reperibile in [Wik10d]

35
Compositing manager

Stacking window manager


La prima tipologia che viene trattata è quella in cui ricadono attualmente la maggior
parte dei window manager. Uno stacking window manager costruisce la rappresentazione
complessiva delle nestre prendendone in considerazione una alla volta. A questo scopo
non è necessario impiegare un buer separato per ogni nestra, ma è suciente un
unico buer nel quale vengono disegnati volta per volta i contenuti di ogni nestra. Le
coordinate del disegno sono assegnate dalle applicazioni, ma il gestore le può modicare
secondo il criterio che preferisce.
Se due nestre si sovrappongono, in parte o in tutto, la nestra che viene disegnata per
ultima (ovvero quella che si trova in cima) occupa completamente l'area di intersezione
tra le due nestre, coprendo così il contenuto della nestra che si trova più in basso.
L'ordine secondo il quale vengono disegnate le nestre, completamente gestito dal window
manager, rappresenta una sorta di coordinata z associata alle nestre,
La presenza di un solo buer fornisce buone prestazioni, ma in questa maniera non è
possibile implementare eetti graci relativamente semplici come quelli di trasparenza.

Tiling window manager


Un tiling window manager organizza lo schermo come l'unione di aree disgiunte, non
sovrapponibili, nel quale vengono disegnate le varie nestre8 . Questo modello si discosta
molto, così, dal classico paradigma desktop, seguito invece dagli stacking window manag-
er. Spesso, i WM di questa categoria non forniscono alcun tipo di decorazione, pertanto
molti di loro non utilizzano la tecnica del re-parenting.
La costruzione della rappresentazione secondo il paradigma a tile, richiede natural-
mente una gestione molto accurata di posizionamento e dimensionamento delle nestre,
in modo da riempire lo schermo, senza dimenticare di fornire una rappresentazione
sucientemente chiara per l'utente.
Secondo questo modello non è necessario alcun buer intermedio: una volta calcolate
le coordinate delle nestre, il contenuto può essere inviato direttamente sul framebuer.

Compositing window manager


La terza ed ultima categoria è quella dei compositing window manager, di cui cui si
fornisce, per completezza, solo una breve presentazione.
La modalità con la quale viene costruita la rappresentazione è in qualche maniera simile
a quella utilizzata negli stacking window manager. La dierenza fondamentale, però è
che ogni nestra top-level utilizza un buer diverso. In seguito, il compositing window
manager compone i pixel associati a ciascuno di questi buer in maniera opportuna,
scrivendo il risultato in un ulteriore buer che viene poi inviato al windowing system.
Questa procedura in due passi permette di realizzare eetti graci, anche complessi,
inclusi quelli di trasparenza. Il prezzo da pagare è un utilizzo maggiore di memoria e di
tempo di elaborazione.
8
Come curiosità, si segnala che in questa categoria ricadevano i primi window manager Microsoft, per
via di dispute con Apple sulla licenza del paradigma stacking.

36
2.1 Window Manager

2.1.4 Standard EWMH e ICCCM9


L'architettura X11 richiede che, per mantenere una reciproca interoperabilità, tutte le
sue componenti ed applicazioni si conformino al medesimo protocollo, l'X Core Protocol
o protocollo principale. Tuttavia, come ribadito più volte, il protocollo principale non
include nessuna forma di standardizzazione per quanto riguarda le comunicazioni inter-
client. In questa categoria ricadono anche le interazioni tra window manager e client
applicativi.
La mancanza di speciche ha portato inizialmente ad un proliferare di interfacce di-
verse e spesso incompatibili. Il problema è stato risolto inizialmente con l'introduzione
degli ambienti desktop integrati che hanno stabilito una serie di linee guide interne per
assicurare interoperabilità e consistenza graca delle loro componenti. D'altra parte, an-
che in questa maniera viene a crearsi una barriera che divide applicazioni realizzate per
ambienti desktop dierenti: la soluzione a lungo termine è quella di creare una serie di
speciche di trasversali in grado di standardizzare il comportamento di ogni applicazione.
Già a partire dal 1993 è stato introdotto ICCCM (Inter -Client Communication Con-
ventions Manual ) [Sta93] che però ha faticato molto a imporsi a causa della sua presunta
ambiguità in molti passaggi e dalla dicoltà per le implementazioni di aderire ai suoi
standard. Il risultato è stato che le convenzioni interne agli ambienti desktop hanno
continuato ad essere predominanti. Inoltre ICCCM si è rivelato progressivamente sem-
pre più inadatto con l'introduzione di nuovi modelli di interazione e nuove componenti
all'interno dell'architettura X11.
Per risolvere i problemi di ICCCM, più recentemente10 è stato introdotto un nuovo
standard, EWMH (Extended Window Manager Hints ) [Gro06].
Similmente ad ICCCM, EWMH standardizza le interazioni tra window manager, ap-
plicazioni e di tutte quelle componenti che fanno parte di un ambiente desktop. Inoltre,
a partire dalla versione 1.4, EWMH prende in considerazione le esigenze dei compositing
manager. La specica è costruita al di sopra di ICCCM, che denisce le interazioni tra
client e window manager ad un livello più basso.
Nel corso delle release che si sono succedute, i window manager hanno iniziato a garan-
tire una compliance parziale agli standard. L'aderenza completa, infatti, non è un requisi-
to necessario per l'interoperabilità, e la maggior parte delle implementazioni si accontenta
di conformarsi ad un sottoinsieme, fondamentale ma limitato, delle speciche.
Entrambe le speciche si basano sul medesimo principio di funzionamento, secondo il
quale tutti i partecipanti all'interazione (client applicativi, window manager, eccetera) si
scambiano informazioni impostando opportunamente una serie di proprietà sulle nestre.
Il window manager, non essendo associato a nessuna nestra particolare, può utilizzare la
nestra radice per le segnalazioni ai client. Tutte le proprietà, come discusso nel paragrafo
1.3.2, sono associate e gestite tramite atomi. Un secondo meccanismo fondamentale,
quello delle selezioni, è denito da ICCCM, utilizzato da entrambe le speciche, e gestito
tramite atomi.
9
Sia ICCCM che EWMH sono ospitate da freedesktop.org.
10
La versione 1.4 del protocollo, la più recente, risale al 2006.

37
Compositing manager

Inoltre, le speciche contengono anche una serie di suggerimenti per la loro eettiva
implementazione. Ad esempio EWMH suggerisce ai window manager un modalità con
la quale stabilire l'ordinamento (stacking ) delle nestre.
Per concludere viene analizzata brevemente le relazioni tra i due protocolli ed i com-
positing manager:

ICCCM: ICCCM non prevede alcuna denizione specica per i compositing manager.
Tuttavia i suoi meccanismi di base sono largamente utilizzati.

EWMH: A partire dalla versione 1.4 del protocollo, EWMH prevede una serie di pre-
scrizioni, atte a regolare l'interazione tra applicazioni e compositing manager. Per
ogni display gestito dal compositore, quest'ultimo deve acquisire la proprietà (own-
ership ) della selezione
11 identicata dall'atomo _NET_WM_CM_Sn, dove n è il numero

associato dal WS al display. L'acquisizione della selezione deve avvenire secondo


le modalità descritte da ICCCM. EWMH specica inoltre come debba essere gesti-
ta la proprietà WM_TRANSIENT_FOR, denita da ICCCM, nel caso di nestre con
attributo override-redirect attivo.

2.2 Compositing manager


Tradizionalmente i windowing system permettono ai loro client di disegnare direttamente
sul frame-buer, traducendo i vari comandi che le applicazioni inviano al server, sotto
forma di richieste, in comandi comprensibili all'hardware. I window manager si inter-
pongono tra client e server e mediano il processo di rendering, indicando ai client dove
devono disegnare e quando eettivamente possono farlo. Così facendo, ogni volta che i
client ridisegnano il contenuto di una nestra, o di una sua parte, sovrascrivono quanto
era stato disegnato precedentemente. Questo comportamento impedisce di combinare
tra loro i contenuti delle varie nestre, limitando fortemente il tipo di rappresentazione
organizzata dal window manager; in particolar modo impedisce di creare eetti graci
complessi.
Nei più recenti window system, è stato introdotto un nuovo modello architetturale,
che fa sì che le applicazioni non disegnino più sul frame-buer, né su un unico buer
gestito dal window manager. Secondo questo modello, ogni nestra top-level disegna
su di un buer separato, non mostrato direttamente a schermo (o-screen ). Un nuovo
soggetto, il compositing manager, combina a piacimento il contenuto dei buer e costru-
isce la rappresentazione dello schermo, per poi disegnarla a video. La gura 2.2 riassume
gracamente il contenuto di questa introduzione.
Chiaramente il compositing manager è una componente critica per le prestazioni del-
l'interfaccia graca: ogni singolo pixel visibile è sotto il suo controllo, e gli aggiornamenti
dello schermo sono limitati solamente dalla sua velocità di elaborazione.
Attualmente le tecniche di composizione sono adottate su tutti i principali sistemi
desktop : da Quartz Compositor in Mac OS X [Sir05], a Desktop Window Manager in

11
Vedi paragrafo 1.3.2, verso la ne.

38
2.2 Compositing manager

Nome Specica Descrizione


_NET_ACTIVE_WINDOW EWMH Contiene l'identicatore della nestra
attiva, o None se non lo è nessuna.
WM_CLASS ICCCM Impostata dai client. I WM la utilizzano
per ottenere l'elenco delle risorse associate
al client.
WM_CLIENT_MACHINE ICCCM Contiene il nome della macchina sulla quale
è in esecuzione il client.
_NET_CLIENT_LIST EWMH Contiene l'elenco completo di tutte le
nestre gestite dal window manager.
WM_COMMAND ICCCM Il comando (e relativi argomenti) utilizzati
per invocare l'applicazione.
_NET_WM_NAME EWMH Il nome dell'applicazione. Sostituisce la
proprietà WM_NAME di ICCCM.
WM_NORMAL_HINTS ICCCM Impostata dal client. Suggerisce al WM la
dimensione da utilizzare quando la nestra
è in uno stato normale.
WM_PROTOCOLS ICCCM Elenco dei protocolli di comunicazione
client-WM supportati dall'applicazione.
_NET_WM_STATE EWMH Impostata dal client. Contiene dei
suggerimenti sullo stato da associare alla
nestra (modale, sticky, full-screen, ...).
_NET_SUPPORTED EWMH Impostato dal WM. Indica i suggerimenti
(hint ) supportati.
_NET_SUPPORTING_WM_CHECK EWMH Impostata dal WM sulla radice. Contiene
lo XID di una nestra particolare, la cui
presenza indica ai client che è attivo un
WM compliant.
WM_TRANSIENT_FOR ICCCM Impostata dai client su una top-level.
Indica al WM che la nestra è un pop-up di
una qualche altra top-level, ed è quindi è
destinata a sparire in fretta (transient )
_NET_WM_WINDOW_TYPE EWMH Impostata dal client prima del mapping.
Indica il tipo di nestra, classica per le
funzionalità. Usata dal WM per
determinare decorazione, ordine di stacking
e comportamento della nestra. Sostituisce
le proprietà MOTIF, puramente basate
sull'aspetto.

Tabella 2.2: Alcuni delle principali proprietà denite da ICCCM ed EWMH. Le proprietà
possono essere utilizzate liberamente grazie ad Xlib.

39
Compositing manager

App1 App2 ... AppN

Qt Gtk+ Xlib
buffer

buffer

buffer
Compositing manager
Qt, Gtk+, Xlib...

rappresentazione

Server
Composite, Damage, Xfixes

Framebuffer
Figura 2.2: L'architettura basilare di un X compositing manager. Le applicazioni client
utilizzano le librerie o le tecniche di rendering che preferiscono. Il compositing
manager fa sì che il loro contenuto sia redirezionato nei buer fuori schermo,
per poter poi comporre le immagini come preferisce e fornire la sua rappresen-
tazione dello schermo. Il compositore utilizza il proprio motore di rendering
per disegnare la rappresentazione. Alternativamente, il compositore potrebbe
decidere di utilizzare il rendering diretto, non passando così dal server (questa
possibilità non viene mostrata in gura).

40
2.2 Compositing manager

Windows Vista [Mic]. Tuttavia, le implementazioni Apple e Microsoft, come già detto
in relazione ai window manager, sono fondamentalmente diverse dalle implementazione
X11 per Unix, sulla quale ci si concentrerà in questa sezione.
Nel paragrafo (2.2.1) viene presentata un breve panoramica storica sull'introduzione
dei compositing manager, seguita da una discussione approfondita della architettura
(paragra 2.2.2 e seguenti). Si noti come sia stata separata la discussione sui meccan-
ismi che permettono l'introduzione della composizione, e che trattano di una modica
all'architettura del server X, dalla discussione sull'architettura stessa dei compositing
manager (2.2.6).
La discussione delle possibili modalità di rendering è rimandata alla sezione 2.3; la
sezione 2.4 invece approfondisce alcuni temi specici agli eetti graci ed alla loro
implementazione.

2.2.1 Cenni storici


I primi esperimenti nell'ambito della composizione avvennero a metà degli anni '90, grazie
ad alcuni membri dell'X Consortium12 . Modicando il server X, realizzarono un sistema
che usava la tecniche di composizione come primitiva fondamentale per la costruzione
della rappresentazione delle nestre. Il contenuto di ogni nestra glia veniva composto
con quello del proprio padre, e così via, con una procedura incrementale che risaliva
ogni ramo dell'albero no ad arrivare alla nestra radice [Get04]. In questa maniera era
possibile realizzare eetti di trasparenza reale: l'architettura però, presentava due grossi
problemi.
In primo luogo lo spreco di memoria, dovuto al fatto che ogni singola nestra richiedeva
di allocare due interi buer: uno per il contenuto eettivo della nestra, e l'altro per il
risultato della composizione con le sue glie. Inoltre, essendo inerentemente ricorsivo, il
processo di composizione richiedeva un lungo tempo di elaborazione.
Il secondo problema era che la tecnica di composizione non era stata implementa-
ta in maniera modulare, ma direttamente sul server, violando il principio basilare di
separazione delle policy dai meccanismi.
L'interesse verso la composizione non era suciente, i computer di allora non sembra-
vano abbastanza potenti: i problemi non vennero mai risolti e il progetto fu abbandonato
poco tempo dopo.
Qualche anno più tardi, era la ne del 1999, cominciarono a circolare le prime beta
pubbliche di Mac OS X, che presentavano la prima realizzazione commerciale di un
compositing window manager, Quartz Compositor 13 .
L'architettura di composizione era basata sulla creazione di buer separati per ogni
nestra top-level, in maniera analoga a quanto era stato fatto in precedenza. Tuttavia
vi era una dierenza sostanziale: in OS X non esisteva il concetto di sotto-nestra, per
cui tutte le nestre erano top-level.
12
Purtroppo non è stato possibile recuperare riferimenti più precisi su nomi e date.
13
Quasi contemporaneamente, tecniche simili erano state implementate da DirectFB.

41
Compositing manager

Avendo a che fare con alberi a soli due livelli, e non dovendo quindi trattare il caso
di nestre annidate, si eliminava il problema della ricorsione e del conseguente spreco di
risorse, potendosi permettere un'implementazione relativamente semplice.
Un approccio di questo genere, tuttavia era, ed è ancora adesso, completamente in-
adeguato per i window manager e gli ambienti desktop basati su X, nei quali la relazione
gerarchica fra nestre viene largamente sfruttata; si pensi proprio alla tecnica di re-
parenting. Addirittura alcuni window manager incapsulano l'intera gerarchia di nestre
in un'unica nestra top-level. A peggiorare le cose, l'implementazione Apple negava
ignorava completamente il principio di separazione dei meccanismi dalle policy.
All'inizio del 2000, Keith Packard e James Gettys presentarono un articolo [Get04]
nel quale discutevano di una riorganizzazione dell'X Windowing System, in grado di
eliminarne, o almeno limitarne, i vari difetti architetturali. Tra le altre cose, veniva anche
presentata una nuova architettura in grado di supportare al meglio la composizione. Da
allora, è iniziato un lavoro di sperimentazione che, qualche anno più tardi, ha portato al
rilascio uciale dei primi X composite manager14 .
Tra i compositing (window) manager disponibili attualmente per l'architettura X11,
citiamo Compiz 15 , pensato principalmente per la composizione vera e propria, e il piccolo
16
xcompmgr, realizzato principalmente come proof-of-concept . Inoltre gli stessi KWin
(gestore di KDE, dalla versione 4.0), Metacity (gestore di Gnome, dalla versione 2.20)
ed Xfwm (gestore di Xfce, dalla versione 4.2.0) supportano la composizione [Wik10c]. Si
vede, dunque, come i compositori siano diventati ormai una componente standard dei
principali desktop environment e, di conseguenza, delle principali distribuzioni Linux.

2.2.2 Meccanismi di base


Complessivamente, i meccanismi atti a permettere la realizzazione di un X compositing
manager sono forniti da tre, fondamentali, estensioni al protocollo principale:
Composite: permette di selezionare quei rami dell'albero delle nestre che si vuole siano
redirezionati su buer separati (2.2.3);
Damage: tiene traccia delle aree che vengono modicate all'interno della nestra, in
modo da segnalarlo al compositing manager (2.2.5);
XFixes: è un estensione di supporto alle due precedenti, che assicura che la maggior
parte delle operazioni richieste vengano elaborate lato-server. Include, tra le altre
cose, la denizione di una nuova risorsa, la regione. Su quest'ultima agiscono
estensivamente molte delle richieste di Composite e di Damage (2.2.4).
Anché possa essere realizzato un compositing manager al di sopra dell'X Window Sys-
tem, è necessario che l'architettura preveda un meccanismo tramite il quale le appli-
cazioni possono selezionare quali segmenti dell'intera gerarchia di nestre debbano essere
14
Uno dei primi compositing window manager per X, Metacity, fu rilasciato nell'agosto 2004. In seguito
(2009) fu integrato in Gnome.
15
http://www.compiz.org/
16
Una sorta di test per mostrare le basilari tecniche implementative e le potenzialità della composizione.

42
2.2 Compositing manager

disegnati direttamente nei buer di redirezione, e quali invece debbano essere memoriz-
zati nello stesso spazio dove sono contenuti i loro genitori. Questo comportamento è
assicurato dall'utilizzo di Composite [PJ07].
Inoltre, dato che le modiche alle nestre si riettono, per gli eetti di Composite, sulle
componenti della gerarchia fuori schermo, è fondamentale un meccanismo che permetta
al compositore di sapere quali aree sono state aggiornate, permettendogli così di agire di
conseguenza. Questo è lo scopo di Damage [PA07].
Il risultato nale, è che l'intera gerarchia delle nestre viene memorizzata nei buer. A
questo punto, una qualunque applicazione esterna può controllare la costruzione dell'im-
magine, combinando a piacere i contenuti delle nestre, tra di loro, o con un qualunque
altro oggetto graco.
A questo scopo può essere utilizzato un qualunque motore di rendering 17 , compreso
quello implementato all'interno al server per eetto dell'estensione XRender [Pac09].
Non c'è vincolo al numero di applicazioni che possono trarre vantaggio dalla presenza
dei contenuti delle nestre nei buer di redirezione. Si possono immaginare applicazioni
distinte che si occupano, ad esempio, dell'ingrandimento di porzioni dello schermo, o della
realizzazione di icone dinamiche da associare alle varie nestre. Tipicamente, però, c'è
una sola applicazione che si occupa di tutte le operazioni che coinvolgono la manipolazione
dei buer di redirezione: si sta parlando proprio dei compositing manager.
I prossimi paragra analizzano in dettaglio le tre estensioni sopra citate.

2.2.3 Composite
Normalmente, quando un client di X invia al server un comando di disegno relativo
ad una nestra, gli eetti di questi comandi vengono mostrati immediatamente sullo
schermo. Infatti, il sistema graco fa sì che le nestre siano automaticamente disegnate
sul frame-buer.
Tramite l'estensione Composite, un secondo client, tipicamente proprio il compositing
manager, può impedire che il rendering avvenga immediatamente. Questa estensione,
infatti, fa sì che il contenuto (sostanzialmente i pixel ) di una particolare gerarchia di
nestre sia redirezionato in un buer di memoria opportuno, e non venga più direttamente
scritto sul frame-buer. In questa maniera è possibile manipolare il contenuto originale
di una nestra, così come è stato creato, prima che questa possa essere mostrato a
schermo[PJ07].
Una volta che il contenuto è stato redirezionato, modicato e composto deve ancora
essere mostrato a schermo, per cui un compositore ha bisogno di aancare ad Com-
posite un qualche meccanismo che si occupi del rendering, come ad esempio l'estensione
XRender 2.3.2 o le opportune chiamate OpenGL.
Come detto nel paragrafo 1.3.3, le nestre sono organizzate in un albero, la cui radice
è la nestra di root. Quindi, quando si parla di gerarchie di nestre, si intende un ramo
dell'albero che fa capo ad una nestra scelta dal chiamante18 .
17
Del rendering ci si occupa, in particolare, nella sezione 2.3.
18
Ovviamente, se viene selezionata la radice, sarà selezionato l'intero albero.

43
Compositing manager

Questo meccanismo di selezione di intere gerarchie di nestre, rende Composite molto


dierente dalle analoghe implementazioni Apple [App08] dato che, come accennato, il
sistema graco di Mac OS X non prevede l'esistenza di gerarchie di sotto-nestre, ma
solo di nestre top-level.
I buer di redirezione godono delle seguenti proprietà:

• includono soli i pixel compresi all'interno della nestra a capo della gerarchia : tutto
quello che è al di fuori non è redirezionato nel buer;

• includono sia il contenuto della nestra principale (bordi inclusi), che il contenuto
di tutte le sotto-nestre della gerarchia;

• sono accessibili solo quando la nestra originaria viene mappata, ovvero viene resa
visibile;

• sono riallocati automaticamente quando viene ridimensionata la nestra a capo


della gerarchia.

Tra le richieste messe a disposizione da questa estensione, ne citiamo alcune particolar-


mente rilevanti per l'operato di un compositing manager; tali chiamate sono presenti nel
codice di compositori reali come xcompmgr e Compiz.
La prima, e più importante, è RedirecSubWindows, che accetta due parametri: il
primo è l'identicatore di una nestra, e il secondo è la modalità di aggiornamento che si
desidera sia applicata. La richiesta fa sì che il contenuto della nestra prescelta, insieme
a quello di tutte le sue sotto-nestre attuali e future, sia redirezionato in aree di memoria
appositamente predisposte allo scopo, e che non vengono automaticamente disegnate a
schermo: i buer di redirezione, o o-screen buer.
Il secondo parametro può assumere solo due valori, CompositeRedirectAutomatic o
CompositeRedirectManual. La scelta del tipo di aggiornamento è fondamentale; infatti
la modalità automatica fa sì che, ogni qualvolta che i buer vengono modicati, il contenu-
to aggiornato venga trasferito nelle nestre originarie, pronto così per essere disegnato.
La modalità manuale, al contrario, lascia il compito nelle mani del programmatore.
Tipicamente, un compositore utilizza questa richiesta per selezionare la nestra radice;
in questa maniera vengono redirezionate tutte le nestre associate al particolare display
cui la radice appartiene.
La modalità manuale è una scelta obbligata nel caso di implementazioni reali. Infatti,
un compositore spesso si troverà a modicare a più riprese il contenuto di uno stesso buer
prima di poterlo mostrare a schermo, oppure si troverà a trattare contemporaneamente
buer diversi (si pensi alle operazioni di blending necessarie per implementare ombre o
trasparenze).
È bene chiarire ancora una volta che, sia che si tratti di update automatici o manuali,
si sta parlando di come gli aggiornamenti del buer vanno a ripercuotersi sulle nestre.
Un'altra faccenda è quella del percorso inverso, ovvero della modalità con la quale le
modiche alle nestre originali (dovute, ad esempio, ai client che le controllano) si riper-
cuotono sul contenuto dei buer. Composite gestisce questi cambiamenti in maniera

44
2.2 Compositing manager

completamente automatica; tuttavia sarebbe opportuno che il compositore fosse infor-


mato ogni volta che avviene un cambiamento dei buer che sta manipolando. A questa ed
altre esigenze provvede un'estensione separata, Damage, trattata in maggiore dettaglio
nel paragrafo 2.2.5.
La seconda, fondamentale, richiesta introdotta da Composite è NameWindowPixmap, in-
trodotta a partire dalla versione 0.2 dell'estensione. Questa richiesta fornisce una maniera
per accedere al contenuto del buer di redirezione, associando ad essi una pixmap di cui,
poi, restituisce l'identicatore al chiamante. La pixmap così ottenuta riette dinami-
camente il contenuto del buer; è allocata automaticamente quando la nestra viene
mappata ed è riallocata quando la nestra originale viene ridimensionata. Tuttavia, la
pixmap non viene deallocata in nessun caso, neanche se la nestra originale viene distrut-
ta, o resa unmapped ; è responsabilità del programmatore deallocare la pixmap (tramite
la richiesta FreePixmap) una volta che non è più necessaria.
Qual'è l'utilità di avere a disposizione una copia del contenuto dei buer? Come si è
visto, i buer non sono accessibili quando le nestre a cui si riferiscono non sono mappate:
tramite queste pixmap è possibile aggirare il problema. Ci si potrebbe chiedere a cosa
serva accedere ai pixel di una nestra che non è neanche visibile sullo schermo. La
risposta è da cercare nell'implementazione di alcuni eetti particolari, ad esempio per
la costruzione di animazioni da associare alla chiusura o alla riduzione ad icona della
nestra. Inoltre, l'utilizzo delle Pixmap mette a disposizione un metodo per accedere,
lato server, al contenuto completo di una nestra, inclusi i bordi e decorazione .
19

Concludiamo il paragrafo con la descrizione di un'ultima richiesta, introdotta a par-


tire dalla versione 0.3 dell'estensione, e particolarmente signicativa nel caso che come
modello di rendering si sia scelto OpenGL (2.3.3).
CompositeGetOverlayWindow20 si limita a restituire al chiamante l'identicatore di
una nestra particolare, la cosiddetta nestra di overlay, con la fondamentale caratteris-
tica di essere sempre situata al di sopra di tutte le altre nestre21 . Inoltre, l'overlay gode
delle seguenti proprietà:
• è di classe InputOutput, e inizialmente non è mappata;

• ha dimensioni pari a quelle dello schermo (come la nestra radice);

• possiede l'attributo ovverride-redirect, grazie al quale ogni tentativo di redirezione


è destinato al fallimento;

• non viene vista da richiesta esplorative come QueryTree.


La conseguenza delle ultime due proprietà è che la nestra di overlay risulta, di fatto,
invisibile ai window manager22 : i compositori hanno a disposizione una supercie ideale,
sulla quale poter disegnare senza interferenze.
19
L'inclusione della decorazione è signicativa nel caso dei re-parenting window manager (2.1.2)
20
A GetOverlay è legata la corrispondente CompositeReleaseOverlayWindow.
21
La nestra di composizione è comunque sempre al di sotto della nestra dello screen-saver.
22
L'unico metodo per ottenere l'identicatore della nestra di overlay passa attraverso
CompositeGetOverlayWindow.

45
Compositing manager

Sebbene sia possibile renderizzare direttamente sulla nestra di overlay, la specica


assume che si utilizzi un metodo diverso, tramite il quale è possibile personalizzare le
operazioni di rendering. La tecnica, eettivamente utilizzata in molte applicazioni reali23 ,
consiste nel creare una sotto-nestra specica per le operazioni di rendering, glia della
nestra di overlay e dalla quale, ovviamente, eredita tutte le caratteristiche.

2.2.4 XFixes
Questa estensione non è altro che la raccolta di una serie di workaround utili per superare
alcune limitazioni del protocollo principale [Pac06].
In questa sede vengono trattate solo quelle componenti di XFixes rilevanti per la scrit-
tura di un compositing manager: nello specico risulta molto importante l'introduzione
del concetto di regione, supportato a partire dalla versione 2.0. Una regione è una risorsa,
rappresentata con un certo identicatore, composta da un insieme disgiunto di rettangoli
più un rettangolo particolare, denito come il più piccolo rettangolo in grado di contenere
tutti gli altri. Il concetto di regione è fondamentale per l'estensione Damage (2.2.5).
Tra le varie richieste, ve ne sono alcune di particolare interesse per le tecniche di
composizione.
La prima è CreateRegion, che accetta in input un insieme di aree rettangolari e
restituisce in output la regione corrispondente24 .
Utili sono anche UnionRegion e SubtractRegion che, come si evince dai nomi, sono
utili per combinare due regioni l'una con l'altra tramite operazioni di addizione e sot-
trazione opportunamente denite.
Vediamo come queste richieste possano essere utili congiuntamente a quelle denite da
Damage. Ad esempio, un'operazione di sottrazione potrebbe essere utilizzata per azzerare
l'intero contenuto di un'area di danneggiamento, segnalando che nestra associata è
da considerarsi riparata; un'addizione, d'altro canto, potrebbe servire per unicare le
modiche riportate da due eventi dierenti, aggiornando così lo stato di danneggiamento
della nestra.
Un'ultima richiesta interessante è SetPictureClipRegion che modica l'area di clip-
ping associata ad un'immagine (la risorsa principale di XRender, vedi 2.3.2). Ad esempio
si può far sì che l'area di clipping sia pari all'unione di tutte e sole le aree danneggiate.
In questa maniera le successive operazioni di aggiornamento andranno a interessare solo
quelle regioni che sono state eettivamente modicate, e non tutta l'immagine.

23
La tecnica è utilizzata anche da MeeGo Compositor, descritto nel capitolo 4.
24
Una volta che una regione non è più necessaria, può essere deallocata tramite la richiesta
DestroyRegion.

46
2.2 Compositing manager

2.2.5 Damage
Lo scopo di questa estensione è quello di monitorare una nestra o una pixmap25 , e di
segnalare tempestivamente quali delle sue aree abbiano subito una qualche modica. Le
modiche sono noticate ai client tramite un usso di eventi DamageNotify, in ognuno dei
quali viene riportato l'identicatore della nestra a cui ci si sta riferendo, e la descrizione
della regione modicata [PA07].
L'introduzione di questa estensione è dovuta al fatto che Composite, di per sé, non
prevede alcun meccanismo che consenta di segnalare al compositing manager, o ad una
qualunque applicazione che sta utilizzando il contenuto dei buer, che quest'ultimo è
stato modicato in parte o in tutto. Composite, infatti aggiorna le pixmap in maniera
silenziosa: Damage sopperisce a questa mancanza monitorando il contenuto delle nestre.
Se un client vuole tracciare le modiche associate ad una particolare nestra, dovrà
prima creare un oggetto particolare, di tipo Damage, in cui verranno via via accumulate
le notiche ricevute dal server. Fondamentalmente, un Damage non è altro che l'elenco
completo di tutte le regioni danneggiate 26 .
Tra le varie richieste denite da Damage, ne vengono riportate alcune di particolare in-
teresse per le operazioni di composizione. La prima richiesta analizzata è DamageCreate,
con la quale un client chiede al server di creare un oggetto Damage, associato alla nes-
tra indicata nel primo argomento. Con un secondo parametro, facoltativo, è possibile
indicare anche la dimensione minima (relativamente all'area complessiva della nestra)
raggiunta la quale iniziano ad essere generati i DamageNotify.
Un compositore che voglia gestire completamente il display, dovrà lanciare una richi-
esta DamageCreate per ognuna tutte le nestre a schermo. Da questo punto in poi, il
compositore continuerà a ricevere le notiche di danneggiamento, grazie alle quali saprà
in quale misura sono stati modicate le nestre e, di conseguenza, i buer di redirezione.
Potrà poi utilizzare queste informazioni per implementare gli eetti desiderati.
Ad esempio, prendiamo il caso dell'implementazione di un eetto di trasparenza. Ogni
volta che una nestra viene spostata, andrà inevitabilmente a sovrapporsi con qualche
altra nestra, causando così l'invio di un usso costante di DamageNotify. Per realizzare
l'eetto di trasparenza, la reazione del compositore sarà quella di eettuare il blend-
ing della porzione della nestra in movimento che, volta per volta, interseca le regioni
segnalate all'interno delle notiche.
La seconda, ed ultima, richiesta presentata è DamageSubtract. Tale richiesta permette
di modicare il Damage passato come primo argomento, in relazione alle regioni passate
come secondo e terzo argomento. Questa richiesta può essere utilizzata, tra le altre cose,
per riparare in parte o in tutto una nestra; in questa maniera il client segnala che ha
terminato di processare gli eventi di danneggiamento precedenti.
25
Nel corso del paragrafo, si parlerà principalmente di nestre. Si tenga presente che considerazioni
analoghe valgono anche per le pixmap, o viceversa.
26
Si noti che una nestra viene considerata danneggiata anche se viene modicata un'altra nestra
ad essa parzialmente sovrapposta. Ad esempio, ipotizziamo di avere due nestre, una sovrapposta
all'altra. Se un client le sta monitorando entrambe, ed una modica interessa una zona compresa
nell'intersezione delle due nestre, vengono inviati due DamageNotify.

47
Compositing manager

2.2.6 Architettura
Tipicamente, ad ogni X server corrisponde almeno un client, il window manager. Al
WM può essere aancato un client diverso, il compositing manager, che, come si è visto,
si occupa della composizione delle nestre redirezionate. Tra le altre cose, non è detto
che questi due client risiedano sulla stessa macchima. Un esempio di questo modello
architetturale è mostrato in gura 2.3.
Fondamentalmente, quello che accade è che allo stesso server sono connessi, oltre
ai client applicativi, altri due client speciali: i due gestori. L'architettura di compo-
sizione fa sì che tutte le richieste di rendering da parte delle applicazioni siano ridirette
vero i buer o-screen: così facendo l'intero rendering resta in mano del compositore.
Contemporaneamente, il window manager dialoga con le applicazioni, mediante l'im-
postazione e la lettura delle proprietà associate alle nestre, occupandosi tra le altre cose
del re-parenting 27 , delle ridimensionamento delle nestre, delle icone, e così via. Allo
stesso tempo, poi, il window manager comunica le informazioni che raccoglie al com-
positing manager, in modo che possa sfruttarle adeguatamente nella costruzione della
rappresentazione dello schermo.
Un'architettura di questo tipo rende più agevole il compito dello sviluppatore del com-
positore, che potrà concentrarsi sulle tecniche di rendering, senza doversi preoccupare dei
dettagli connessi alla gestione delle nestre.
Alternativamente, è possibile che le funzioni del window e del compositing manag-
er siano assommate in un unico soggetto, noto come window compositing manager.
In questo caso si riduce la complessità dell'architettura, al prezzo di aumentare quella
dell'implementazione.
In questa categoria ricadono, tra gli altri, Compiz e il compositore di MeeGo, descritto
nel capitolo 4.

Soluzioni alternative
Una soluzione architetturale interessante è quella utilizzata da Luminocity 28 , un compos-
itore sperimentale nato da una costola di Metacity, il window manager di Gnome. Nel
corso degli anni (il progetto è nato nel 2006) Luminocity è caduto in disuso ma molte
delle sue caratteristiche sono conuite in Compiz e Metacity.
Secondo il modello architetturale di questo compositore, il rendering avviene su di un
server diverso da quello al quale sono collegati i client. In poche parole, il compositing
manager gestisce un server X headless, non collegato a nessun display, al quale sono
dirette le connessioni da parte dei client. Il compositore copia il contenuto delle nestre
disegnate dai client del primo server, e lo ridisegna su di un secondo server, di solo output.
Un problema fondamentale che Luminocity ha dovuto risolvere è quello per cui gli
eventi di input vengono ricevuti dal server di output mentre i client risiedono sul server
headless. La soluzione è quella di inoltrare gli eventi, con una tecnica alquanto complessa,

27
A volte, si pensi alle versioni di Compiz precedenti alla 0.9.0, è lo stesso compositore ad occuparsi
della gestione delle decorazioni.
28
http://live.gnome.org/Luminocity

48
2.2 Compositing manager

Figura 2.3: In questa gura, tratta da [Fon09], viene mostrato un server X a cui è colle-
gato, tramite socket locale, un window manager. Il compositore gira su un
computer remoto, sul quale è in esecuzione anche un normale applicativo.
Nell'esempio i client interagiscono con due nestre: una di InputOutput e
l'altra di solo input. In questa architettura modulare, il window manager si
occupa della gestione vera e propria delle nestre, mentre il compositore ne
costruisce la rappresentazione a schermo e si occupa del rendering. La con-
seguenza è che il compositore ignorerà completamente le nestre InputOnly,
dato che non devono mai essere visualizzate.

49
Compositing manager

da un server all'altro, seguendo un percorso inverso rispetto a quello seguito dai contenuti
delle nestre..
Questa architettura non standard porta ad una notevole semplicazione per quanto
riguarda il rendering, in quando il compositing manager può funzionare come un normale
client ed utilizzare il direct rendering (2.3.3). Inoltre non ha cattive performance, per
lo meno nel caso di applicazioni che si limitano al 2D. Le cose cambiano drasticamente
se si vanno a considerare applicazioni 3D o che fanno uso di XVideo29 : non c'è alcuna
maniera di ottenere prestazioni decenti senza permettere alle applicazioni di dialogare
direttamente con il server di output.

2.3 Rendering
Si è visto come il compito fondamentale dei compositing manager sia quello di mostrare
a schermo la rappresentazione dell'albero delle nestre, dopo aver eventualmente appli-
cato una serie di eetti che, in larga misura, sono implementati utilizzando tecniche di
composizione digitale. Si capisce dunque come per un compositore sia fondamentale la
tecnica utilizzata per il rendering30 .
Purtroppo, il protocollo principale non è adatto allo scopo. Per vedere perché, si
immagini di aver ridiretto un'intera gerarchia di nestre nei buer opportuni. Senza uti-
lizzare nessuna estensione, la responsabilità di implementare le trasformazioni grache
necessarie ricadrebbe sul client, che dovrebbe così copiare tutto il contenuto dei buer
nel suo spazio di memoria. In questa maniera si introdurrebbe un ritardo, potenzial-
mente molto alto, dovuto al tempo necessario per la comunicazione tra client e server.
Chiaramente, se il carico del lavoro fosse implementato sul server questo ritardo verrebbe
estremamente ridotto, dato che il client dovrebbe limitarsi ad inviare una serie di richi-
este opportunamente denite. Inoltre, limitandosi ad utilizzare il protocollo principale,
sarebbe molto dicile realizzare un qualsivoglia eetto tridimensionale.
La conseguenza è che, scartato il protocollo core, un compositore ha bisogno di appog-
giarsi ad una qualche estensione o ad un architettura completamente diversa.
Osservando i compositing manager a disposizione, ci si rende conto che, per quanto
riguarda l'architettura di rendering dei compositing window manager, le opzioni sono fon-
damentalmente due. La prima è costituita dall'utilizzo dell'estensione XRender, mentre
la seconda si base su OpenGL. Due diagrammi architetturali semplicati sono mostrati
nelle gure 2.4 e 2.5. Ad essi si può far riferimento nella lettura dei due paragra
successivi.
Nessuna delle due è assolutamente migliore della precedente, in quanto spesso i driver
graci supportati da X hanno performance molto dierenti relativamente al metodo di
rendering utilizzato. Ad esempio, alcune produttori non mettono a disposizione le speci-
29
XVideo si occupa del ridimensionamento dei ussi video, per tanto si sta parlando di applicazioni che
fanno playback video a pieno schermo.
30
Si badi bene: le applicazioni, quando scrivono nei buer di redirezione, possono utilizzare una
qualunque tecnica di rendering, accelerata o meno. Il problema è completamente distinto da quello
del rendering da parte del compositore.

50
2.3 Rendering

Figura 2.4: Il meccanismo di base della composizione bidimensionale (ad esempio tramite
XRender). La gura è tratta da [LK06]. Sebbene il compositore sia un client,
è rappresentato come una componente del window system per evidenziare le
sue funzionalità di rendering. La freccia più a destra rappresenta l'eetti-
vo disegno a schermo dell'immagine composta; tale passaggio è compiuto
tipicamente all'interno del server grazie ad XRender.

Figura 2.5: Il meccanismo di base della composizione tridimensionale (ad esempio


tramite OpenGL). La gura è tratta da [LK06]. Valgono le considerazioni
riportata nel commento della gura precedente. Si noti come il compositore
non manipoli più pixmap, ma texture. Inoltre viene evidenziata la possibilità
del cosiddetto direct rendering, spiegato in maggior dettaglio in 2.3.3.2.

51
Compositing manager

che complete dei loro prodotti, e quindi, può capitare che i driver free per OpenGL
risultino poco performanti, mentre XRender si comporti ragionevolmente bene.
Non è detto, però che sia obbligatorio scegliere. Nonostante la maggior parte dei
compositing manager si adi ad un solo metodo per il disegno a schermo delle nestre,
potrebbe essere interessante un compositing manager in grado di supportare contem-
poraneamente più tecniche di rendering. Il guadagno in complessità potrebbe essere
bilanciato dal guadagno in essibilità.
Il primo paragrafo di questa sezione è dedicato ad una breve introduzione teorica alle
tecniche di composizione digitale (2.3.1). In seguito vengono presentati i due modelli di
rendering pricipali: XRender (paragrafo 2.3.2) e OpenGL (paragrafo 2.3.3).
La sezione si conclude con una discussione sul modello di rendering di Qt. Si analiz-
zano le astrazioni che nascondono i dettagli implementativi e permettono la scrittura di
applicazioni multi-piattaforma, in modo da comprendere come sia possibile utilizzare, in
un'applicazione Qt, uno dei vari motori di rendering o, addirittura, di come sia possibile
scriverne un'implementazione personalizzata.

2.3.1 Alpha-compositing
Prima di addentrarsi nel dettaglio dei due motori di rendering principali, è bene spendere
qualche parola per chiarire, dal punto di vista teorico, cosa si intende per composizione.
Nel corso di tutto il capitolo, infatti, si parla di tecniche di composizione, e di come
queste possano essere utilizzate per realizzare vari eetti graci. Queste tecniche sono
basate tutte sulle stesso concetto, noto come alpha compositing.
Formalmente l'alpha compositing, (o alpha blending ) è un operazione matematica ap-
plicata su due immagini digitali, che consiste nel combinare fra di loro i valori di col-
ore assegnati a ciascun pixel. La combinazione è ottenuta tramite l'introduzione, nelle
equazioni, di un valore addizionale, un'ulteriore parametro assegnato ad ogni pixel e
chiamato alpha.
La composizione digitale, e la relativa algebra di composizione, è stata presentata per
la prima volta in un celebre articolo di Porter e Du [PD84].
Aggiungendo un canale alpha a ciascuna delle pixmap o-screen, in grado di descrivere
il livello di trasparenza di ciascun pixel, è possibile ottenere nestre di qualunque forma
e opacità.
L'operazione di composizione più comune, eettivamente utilizzata dai compositing
manager, è descritta dalla semplice formula seguente, che illustra gli eetti dell'operatore
Over di Porter e Du applicato alle immagini digitali A e B :

cA · αA + cB · αB (1 − αA )
C= (2.1)
αA + αB (1 − αA )
Nella formula (2.1), cA e cB sono i valori di colore rispettivamente di A e di B ,
mentreαA e αB sono i corrispondenti valori di trasparenza. C è l'immagine risultante
dalla sovrapposizione.
In gura 2.6è mostrato un campionario delle possibili operazioni di composizione
descritte da Porter e Du, applicate a due immagini, A e B , parzialmente sovrapposte.

52
2.3 Rendering

A over B A in B A out B A atop B A xor B

Opaque
A and B

Partially-
transparent
A and B

Figura 2.6: Alcuni degli operatori di composizione digitale descritti da Porter e Du.
Immagine tratta da[Wik10a]

2.3.2 XRender
Contrariamente a quello che si potrebbe credere, non è richiesto che i compositori siano
implementati in OpenGL. Inoltre non è assolutamente vero il luogo comune per cui
l'accelerazione graca sia ottenibile unicamente tramite OpenGL. In questo paragrafo è
descritta un'estensione al protocollo principale di X, utilizzata fra l'altro, da compositori
come xcompmgr e Metacity. Le fonti principali sono [Pac09] e [Pac00].
Tramite XRender è possibile ottenere l'accesso ad una serie di operazioni di compo-
sizione graca, svolte interamente sul server. XRender è fondamentale per un composi-
tore, in quanto permette di implementare eettivamente l'apha blending (2.3.1).
XRender lavora grazie al cosiddetto paradigma a canali, che prevede che ad ogni pixel
di una certa immagine siano associati quattro valori: le tre componenti basilari di colore
(RGB) ed un valore di trasparenza, il canale alpha. Il problema è che il protocollo prin-
cipale non funziona così; ad ogni pixel è associato un intero a 32 bit, il pixelvalue. Le
possibili triplette (o quadruplette) a cui possono corrisponde i pixelvalue sono memoriz-
zate all'interno di una struttura, la Colormap, legata al supporto fornito dall'hardware
sottostante. Inne, le traduzioni tra Colormap e pixelvalue sono gestite dalle cosiddette
visuali [SG86, GKM90].
Tutte queste complicazioni vengono nascoste, grazie a XRender, all'interno di un nuo-
vo oggetto, PictFormat, che indica il tipo di traduzione da applicare ai pixelvalue per
estrarre i valori associati ai quattro canali ARGB. La nestra o pixmap di partenza,
associata ad un PictFormat, costituisce una nuova risorsa, detta immagine o più for-
malmente Picture. Rimane un requisito fondamentale, ovviamente, che le risorse di
partenza (pixmap o nestre) abbiano attiva una visuale (ed una colormap) che preveda
anche valori di trasparenza: questo è assicurato dalla presenza dell'estensione Composite
che, tra le altre cose, prescrive una modica dell'implementazione del server. La modi-
ca consiste nell'aggiunta di una nuova visuale, a 32 bit, in grado di utilizzare 8 bit per
descrivere i i valori di trasparenza31 .
Tutte le operazioni di XRender possono essere rappresentate simbolicamente con una
sola, fondamentale trasformazione, in cui tutti gli operandi sono proprio immagini. La
31
L'introduzione di questa visuale permettere anche ad altre applicazioni, diverse dal compositing
manager, di utilizzare le tecniche di composizione.

53
Compositing manager

formula seguente può essere interpretata così: XRender produce una certa immagine di
output (dest ) combinando, tramite un certo insieme di operatori, un'immagine di input
(source ) ed un'immagine maschera (mask ).

dest = (source IN mask) OP dest (2.2)

Come si può vedere, la formula prevede due operatori: IN è un generico operatore di


Porter e Du [PD84], mentre OP è uno degli operatori propri di XRender32 :

• PictOpOver corrisponde all'operatore Over di Porter e Du e può essere utilizzata


per implementare la trasparenza. In questo caso dest corrisponde alla nestra che si
sovrappone, mentre src è la nestra sorapposta; mask viene ignorato. Così facendo,
l'espressione diventa dest = src OV ER dest;

• PictOpSrc prevede che il contenuto della destinazione venga completamente sovrascrit-


to da quello della sorgente, compresi i valori alpha33 . Spesso questa operazione
viene utilizzata semplicemente per applicare la trasparenza alla nestra di desti-
nazione. In un compositore, questo operatore può essere utilizzato per realizzare
eetti come quelli di fading, secondo il quale una nestra lentamente sparisce via
via che il suo valore di opacità raggiunge lo zero.

2.3.2.1 Richieste
Tra le richieste denite dall'estensione, ve ne sono alcune particolarmente rilevanti per
l'implementazione di un compositing manager, e che sono eettivamente usate, tra gli
altri, da xcompmgr.
La prima è CreatePicture, che restituisce un nuovo oggetto immagine, a partire da un
PictFormat e da un disegnabile. In aggiunta, è possibile passare alcuni parametri opzion-
ali alla richiesta. Tra queste citiamo IncludeInferiors, che richiede che nell'immagine
siano contenute anche le relative sotto-nestre.
La richiesta più importante è Composite, che permette di implementare la fondamen-
tale trasformazione descritta dall'equazione (2.2). A dierenza di quest'ultima tuttavia,
Composite permette di specicare che l'operatore sia applicato solo tra due area rettan-
golari delle immagini di sorgente e di destinazione. Tali aree, ovviamente, devono avere
la stessa dimensione.
Un compositore, tipicamente, utilizzerà la prima chiamata per creare le immagini
XRender delle pixmap associate ai buer di redirezione. Questo passo è propedeutico
per il successivo, quello in cui il gestore produrrà l'invio di svariati richieste Composite
per disegnare la propria rappresentazione delle schermo.
Per concludere, si ricorda che, per ogni richiesta di creazione, è responsabilità dell'ap-
plicazione far corrispondere una richiesta, FreePicture, che consente di deallocare la
risorsa quando non è più necessaria.
32
Di seguito sono riportati solo quelli eettivamente utilizzati nell'implementazione di un compositing
manager.
33
Anche nel caso che la destinazione non ne possegga uno.

54
2.3 Rendering

2.3.2.2 Accelerare XRender


Implementando un compositing manager con XRender, si ha il vantaggio di lavorare con
quelli stessi oggetti che sono manipolati dal compositore: pixmap e nestre. Tuttavia, vi
sono anche alcuni svantaggi.
In primo luogo l'API di XRender non permette di sfruttare il potenziale delle schede
grache odierne. In secondo luogo è universalmente noto che, per avere delle performance
accettabili, bisogna fare uso dell'accelerazione graca. Si badi bene: il compositore, così
come ogni altro client, non è minimamente a conoscenza di quello che accade dietro le
quinte, e pertanto continuerà ad utilizzare le medesime richieste, senza rendersi conto
della diversità delle tecniche di accelerazione utilizzate.
Vi sono due approcci per implementare l'accelerazione graca utilizzando XRender :

1. Programmare direttamente l'hardware;

2. Implementare Render sulle librerie OpenGL supportate dal server.

Il primo approccio è utilizzato dalle implementazioni XAA, EXA e UXA, il secondo da


Glucose.
XAA può essere visto come una componente di basso livello del server X, uno strato
software dipendente dalla macchina. Questo strato è situato immediatamente al di sopra
di quello che gestisce l'interazione (non accelerata) con il frame-buer; in questa maniera,
così, è possibile intercettare tutti i comandi di rendering provenienti dagli strati superiori
del server. Nel caso che l'accelerazione hardware non sia disponibile per una chiamata
particolare, o per ragioni relative al dispositivo, l'architettura si limita a passare in una
modalità di fallback software.
In caso contrario, il principio di base è quello di spezzare le primitive di X, in operazioni
ancora più semplici, in modo da semplicare il processo di conversione dei comandi in
quelli messi a disposizione dal driver della scheda graca [Eic04].
EXA ed UXA non si discostano molto da questo approccio: la principale dierenza
è quella di essere implementato all'interno del kernel. Tuttavia, sia XAA che EXA
presentano una serie di difetti, dovuti all'arretratezza delle speciche, che le rendono
obsolete, per cui la scelta è limitata tra UXA e Glucose.
Glucose si dierenzia per la sua capacità di far dialogare XRender con OpenGL. L'im-
plementazione è basata su Glitz34 , un estensione simile a Render, costruita però al di
sopra di OpenGL.

2.3.3 OpenGL
Lavorando con OpenGL, è necessario ragionare non più in termini di pixmap, ma in
termini di texture applicabili a geometrie qualunque, bidimensionali o tridimensionali.
In questa maniera è possibile utilizzare le stesse tecniche sia per la semplice compo-
34
http://freedesktop.org/wiki/Software/glitz

55
Compositing manager

sizione bidimensionale, che per la realizzazione di eetti graci tridimensionali basati su


geometrie, cubica, sferica, o anche molto più complesse35 .
Per poter utilizzare OpenGL come proprio motore di rendering, il requisito fondamen-
tale è quello di avere a disposizione un meccanismo per poter eseguire comandi OpenGL
all'interno del contesto X11. Di questo si occupa proprio l'architettura GLX [Lee05].
GLX è costituito da tre parti:

• una API che fornisce funzioni OpenGL all'applicazione X Window System;

• un'estensione del protocollo X, che permette al client (l'applicazione OpenGL) di


spedire comandi che fanno richiesta di rendering 3D al server;

• un'estensione del server X che riceve i comandi di rendering dal client.

I comandi OpenGL hanno bisogno di un contesto graco nel quale poter essere eseguiti,
che in X non è altro che una nestra opportunamente congurate. I compositori che
fanno uso di GLX normalmente utilizzano allo scopo la nestra di overlay, descritta nel
paragrafo 2.2.3.
L'idea di base è quella di utilizzare OpenGL per operare sulle pixmap in maniera analo-
ga a quanto fatto da XRender, per poi tradurre il contenuto dei buer di redirezione in
texture. È necessario creare una texture per ognuna delle nestre gestite dal composi-
tore, ed ognuna di queste dev'essere aggiornata quando il contenuto della nestra viene
modicato. Una volta ottenute le texture, è possibile utilizzare le chiamate di interfaccia
OpenGL per disegnare sulla nestra di overlay.
Diventano centrali, dunque, le funzioni che si occupano della trasformazione delle
pixmap in texture. Di per sé, il calcolo non è particolarmente oneroso, per lo meno
se compiuto dalla scheda graca. Tuttavia si vorrebbe evitare di dover trasferire ogni
volta tutti i pixel dal server, dove la pixmap risiede, al compositore. Il principio è sempre
lo stesso che ha portato alla scelta di XRender rispetto a quella del semplice utilizzo del
protocollo principale. L'idea di base è di svolgere la trasformazione sul server, evitando
inutili overhead di comunicazione.
A questo scopo esiste un'estensione di GLX (, texture from pixmap o TFP; TFP prevede
persino che le texture vengano aggiornata automaticamente quando viene modicato il
contenuto delle pixmap da cui sono state create.

2.3.3.1 Rendering diretto e indiretto


In generale, esistono due tipologie di rendering, diretto e indiretto. Si ha rendering diretto
quando l'applicazione dialoga direttamente con la scheda graca (passando quindi, in
qualche maniera, attraverso il kernel), mentre si ha rendering indiretto ogni qual volta
l'applicazione invia tutti i suoi comandi di disegno ad un server X, senza avere rapporti
diretti con l'hardware sottostante. L'architettura GLX, di cui si è appena parlato, è
utilizzata in X11 proprio per il rendering indiretto.
35
Si veda ad esempio WolfenQt [Blo08], in cui il desktop è rappresentato come una mappa tridimensionale
navigabile con un sistema simile a quella utilizzato nei videogiochi.

56
2.3 Rendering

La classicazione appena descritta non dev'essere confusa con la classicazione tra


rendering software e accelerato, tanto che il punto fondamentale del rendering indiretto
è che le operazioni svolte dal server, possono (o meno) essere accelerate: difatti, questo
è ciò di cui si occupa l'Accelerated Indirect GLX, o AIGLX [Fed08b], grazie al quale, tra
le altre cose, è implementato proprio Glucose (2.3.2.2).
Se il sistema operativo utilizza driver graci open source, AIGLX utilizza la stessa
libreria DRI utilizzata dai client per il rendering diretto. In ogni caso, il server non
comunica direttamente con il kernel, in quanto il compito spetta a DRI, tramite un
particolare modulo kernel, DRM.
In generale, il rendering indiretto è più lento di quello diretto. La conseguenza è che
se si vuole realizzare un'applicazione pesante, specialmente se 3D, bisogna utilizzare il
rendering diretto.
Il problema è che non è aatto semplice coniugare la composizione con il rendering
diretto. Si tratta del cosiddetto problema del Redirected Direct Rendering.

2.3.3.2 Redirected Direct Rendering


Utilizzando XRender o OpenGL in modalità indiretta, non si ha alcun conitto con le
operazioni di composizione, in quanto tutte le richieste di rendering passano dal server
X a cui sono note tutte le eventuali redirezioni.
La situazione cambia, però, se si considera il direct rendering che, come visto in prece-
denza, rappresenta in molti casi la soluzione migliore [Hog07b]. Per prima cosa, l'ap-
plicazione attraversa una fase di inizializzazione mediata dal server, durante la quale
acquisisce l'indirizzo del frame-buer e di altri buer necessari ad OpenGL. Da questo
punto in poi non vi è alcun bisogno del server, e l'applicazione può programmare diretta-
mente la GPU e farla disegnare in quei buer. Tuttavia, in questa maniera l'applicazione
non ha modo di sapere se la nestra è stata redirezionata e, in ogni caso, continua a
disegnare sul frame-buer senza che il suo output possa essere composto con i contenuti
delle altre nestre. Il risultato è simile a quello mostrato nella gura 2.7.
Una delle possibili soluzioni al problema è quella di introdurre, a livello di DRI, un
gestore della memoria in grado, tra l'altro, di tenere traccia di quando e dove sono
redirette le nestre.
Un secondo problema, collegato al primo, si verica qualora si vogliano utilizzare con-
giuntamente rendering diretto e TFP. Infatti, dato che Pixmap e texture sono risorse
appartenenti a client distinti, perché possano interagire tra loro l'unica possibilità è che
l'architettura di rendering abbia conoscenza dei due oggetti a livello kernel. Anche in
questo caso il problema è risolvibile introducendo in DRI un memory manager unicato.
Prima della recente introduzione di DRI236 , la combinazione tra rendering diretto e
composizione su Linux era possibile, a meno di hack particolari, solo per alcuni driv-
er proprietari (per esempio i driver chiusi Nvidia), che scavalcavano completamente la
vecchia architettura DRI/DRM.
36
DRI2 è la nuova versione di DRI che risolve questi ed altri problemi. Lo sviluppo è iniziato nel 2007
e continua ancora adesso.

57
Compositing manager

Figura 2.7: Eetti del conitto tra compositore (Compiz) e direct rendering. glxgears,
un semplice benchmark GLX che fa uso del rendering diretto, viene
completamente ignorato dal compositore. Immagine tratta da [Hog07b].

2.3.4 Qt Rendering
In questo paragrafo viene illustrato come sia possibile gestire il rendering all'interno di
un framework complesso come Qt [Tro09d].
Il modello di rendering di Qt è basato sul cosiddetto Paint System, costruito a partire
dalle astrazioni fornite dalle classi QPainter, QPaintDevice, e QPaintEngine.
QPainter ore al programmatore un interfaccia attraverso la quale dare i vari comandi
per il disegno, QPaintDevice è l'astrazione di uno spazio bidimensionale su cui è possi-
bile disegnare tramite un QPainter, mentre QPaintEngine è l'interfaccia utilizzata dal
QPainter per disegnare sui paint device, le cui dierenti implementazioni permettono di
accedere all'hardware sottostante in maniera dierente (ad esempio utilizzando o meno
l'accelerazione graca, accedendo direttamente al frame-buer o passando per il sottosis-
tema X11). La classe QPaintEngine è normalmente nascosta al programmatore, a meno
che non voglia creare un proprio device personalizzato.

Figura 2.8: Le tre principali astrazioni alla base del Paint System Qt [Tro09d].

Il vantaggio principale di un approccio di questo tipo è la sua assoluta portabilità.


Inoltre, tutte le operazioni di disegno attraversano la medesima pipeline, il che rende
abbastanza facile aggiungere il supporto per nuove funzionalità.

58
2.3 Rendering

QPainter
La classe QPainter prende in carico le operazioni di disegno a basso livello sui widget e
su tutti gli altri paint device (ovvero le sottoclassi di QPaintDevice ).
In essa sono implementate ed altamente ottimizzate la maggior parte delle funzionalità
grache richieste da una GUI. Una istanza di QPainter può disegnare qualunque cosa che
vada da una semplice linea a forme molto più complesse; può anche disegnare pixmap
e testo con dierente allineamento. Contiene anche un meccanismo per la gestione di
diversi sistemi di riferimento.
Tipicamente i metodi di QPainter sono chiamati all'interno della funzione paintEvent()
dei widget. I paintEvent vengono generati automaticamente durante il ciclo eventi
principale di Qt ogni qualvolta è necessario ridisegnare una componente dell'interfaccia.
Questa classe può essere utilizzata in un gran numero di dierenti combinazioni di
hardware e software, ovviamente ottenendo dierenti risultati in relazione alle perfor-
mance. I progettisti hanno scelto di ottimizzare il più possibile, e su tutte le piattaforme,
un piccolo sottoinsieme delle funzionalità del painter tra cui sono comprese semplici
trasformazioni, operazioni di base su rettangoli e il disegno di pixmap.

QPaintDevice
Un QPaintDevice non è altro che l'astrazione di uno spazio bidimensionale disegnabile
tramite un painter. Tale interfaccia è implementata (e dunque si qualicano come oggetti
disegnabili) dalla basilare classe QWidget e da tutte le altre classi mostrate in gura 2.9.
Per poter supportare un nuovo back-end graco, è necessario re-implementare in una
sottoclasse di QPaintDevice la funzione virtuale paintEngine() in modo da dire al
QPainter che la utilizzerà quale motore dover utilizzare per il rendering.

Figura 2.9: Nella gura sono mostrate le principali classi Qt che ereditano l'interfaccia
QPaintDevice [Tro09d].

59
Compositing manager

QPaintEngine
La classe QPaintEngine è una interfaccia che descrive i possibili motori di rendering
utilizzabili dai painter per agire sui dispositivi. Chiaramente l'implementazione di questa
classe è strettamente legata alla piattaforma hardware/software utilizzata.
In Qt sono già presenti implementazioni che si interfacciano con i motori di rendering
più comuni. Per quanto riguarda X11 è presente un motore di rendering specializzato
basato sull'estensione XRender ; inoltre è possibile utilizzare il comune motore OpenGL .
37

Nel caso la macchina non supporti un determinato motore (ad esempio una macchina
priva di accelerazione graca) o una particolare caratteristica di un qualunque back-end,
in Qt è disponibile una implementazione di fallback completamente software, comune a
tutte le architetture.
La forza di questo approccio sta nella sua estrema essibilità: nel caso si desideri
utilizzare un back-end dierente, è suciente creare una sottoclasse di QPaintEngine e
re-implementarne tutte le funzioni virtuali. La sottoclasse è deve poi essere resa visibile,
re-implementando la funzione virtuale QPaintDevice::paintEngine().
Addirittura è possibile far sì che dierenti componenti della stessa applicazione uti-
lizzino motori diversi, questo è possibile in quanto ogni istanza di QPaintEngine è gestita
direttamente dal paint device che la utilizza38 .

I principali back-end graci


Raster utilizzando questo motore graco, tutte le operazioni di disegno sono implemen-
tate direttamente via software; questo sistema è utilizzato automaticamente dalle
istanze di QImage e relative sottoclassi. Questo motore è quello di default su
MS Windows e su Qt Embedded, ma è sempre presente su tutte le architetture
supportate da Qt.

OpenGL 2.0 (ES) rappresenta il motore graco principale per il rendering 3D accelera-
to. Normalmente è disponibili su tutte le piattaforme desktop e su quelle embedded
che supportino le speciche OpenGL o OpenGL/ES 2.0, tra cui anche la board
U8500 di St-Ericsson.

OpenVG questo back-end implementa lo standard Khronos per la graca 2D e vettoriale.


É utilizzato principalmente per i dispositivi embedded con supporto hardware per
lo standard OpenVG.

37
OpenGL, fra le altre cose, è il motore di rendering di default associato a QGLWidget.
38
A partire da Qt 4.5, è possibile sostituire i motori di default assegnati alle principali classi di Qt, come
QWidget o QPixmap.

60
2.4 Eetti graci

2.4 Eetti graci


Qualcuno potrebbe obiettare che i compositing manager siano dei semplici accessori,
utili solo all'amante dell'eccesso (graco). Molti sviluppatori39 , d'altro canto, ritengono
che i compositori debbano essere considerati una componente standard di ogni moder-
no sistema operativo. Del resto, i vantaggi ottenuti con l'introduzione degli eetti di
trasparenza e l'eliminazione del ickering (vedi 1.3.5) sono innegabili.
In questa sezione viene mostrata in maggior dettaglio l'architettura che permette di
implementare gli eetti graci all'interno di un compositore (2.4.1). In seguito vengono
approfonditi due eetti graci fondamentali: gli eetti di trasparenza (2.4.2), ed il cosid-
detto Exposé (2.4.3). Per entrambi gli eetti, prima ne viene descritto il comportamento,
e in seguito ne vengono fornite alcune note implementative.
La sezione si conclude con una brevissima disamina di alcuni altri eetti messi co-
munemente messi a disposizione dai compositori.

2.4.1 Architettura
Gli eetti graci possono essere parte integrante del codice principale, oppure possono
essere realizzati come plugin. Un plugin è un segmento di codice non autosuciente,
che può essere caricato dinamicamente dal compositore. Con questo secondo metodo, il
codice principale necessita semplicemente di orire un'interfaccia esterna che permetta
di caricare e gestire i plugin.
Sono diversi i punti di forza di questo approccio modulare, grazie al quale:

• possono coesistere numerose implementazione diverse di uno stesso eetto;

• è possibile introdurre nuove funzionalità senza modicare il codice principale (e


quindi non si corre il rischio dell'introduzione di nuovi bug o conitti);

• possono essere introdotti numerosi plugin senza incrementare la dimensione del-


l'applicazione;

• viene semplicato il lavoro degli sviluppatori, in quanto anche chi non ha una
conoscenza suciente del codice principale, può sviluppare nuovi plugin. L'unico
requisito è quello della conoscenza dell'API.

Lo svantaggio di un'architettura del genere, così come quello di ogni altra architettura
modulare, è quello di complicare le interazioni tra il codice principale e i plugin, forzando
questi ultimi ad un comportamento limitato da quanto consentito dall'interfaccia esterna.
Tuttavia, di fronte agli innegabili vantaggi, rimane probabilmente la scelta migliore.
Compiz rappresenta forse l'esempio più eclatante del successo dell'architettura a plug-
in, per lo meno a giudicare dal numero e dalla qualità di plugin sviluppati da parte della
comunità40 .
39
Quanto descritto è basato sulle considerazioni di Kristian Høgsberg, sviluppatore di Red Hat [Hog07a]
40
http://wiki.compiz.org/Plugins

61
Compositing manager

2.4.2 Trasparenza

Figura 2.10: Eetto di trasparenza dovuto a KWin, compositing manager integrato


nell'ambiente desktop KDE. Immagine tratta da [Fon09].

Prima dell'introduzione dei compositing manager, gli eetti di trasparenza dovevano


essere emulati completamente dai client. La mancanza di supporto lato server, e la
mancanza di un'architettura centralizzata, potevano però produrre solo eetti di cosid-
detta falsa trasparenza. Sostanzialmente i client si limitavano a copiare lo sfondo della
nestra radice all'interno della nestra applicativa, applicando poi, manualmente, la
composizione.
In questa maniera, oltre ottenere un eetto esteticamente poco convincente, era coin-
volto il trasferimento di una risorsa pixel per pixel lungo il canale di comunicazione
che, come si è visto, è un operazione da evitare il più possibile. Inoltre, non era pos-
sibile utilizzare l'accelerazione fornita dalla GPU, in quanto il rendering era eettuato
completamente via software.
Attualmente gli eetti di vera trasparenza sono estremamente comuni in tutti i sistemi
operativi, grazie ad un utilizzo basilare delle tecniche di composizione (2.3.1). La gura
2.10 ne illustra un esempio in KDE.
Gli eetti di trasparenza, tra l'altro, possono essere combinati con numerosi altri eetti,
producendo risultati esteticamente appaganti, ma anche molto complessi.
Un plugin che realizzi gli eetti di trasparenza potrebbe essere implementato basandosi
su una particolare proprietà delle nestre, che ne indica l'opacità. La proprietà, associata
all'atomo _NET_WM_WINDOW_OPACITY, potrebbe essere impostata dagli stessi client, oppure
da un applicazione stand-alone distribuita insieme al compositore o all'ambiente desktop;

62
2.4 Eetti graci

Figura 2.11: Il plugin Scale di Compiz in azione. Il desktop environment è Gnome. Si


notino le strisce e gli slot con i quali viene suddiviso lo schermo. Immagine
tratta da http://wiki.compiz-fusion.org/Plugins/Scale.

quello che conta, è che il compositing manager reagisca opportunamente al variare del
valore associato. Nel caso la proprietà non fosse impostata, il compositore potrebbe
assumere che la nestra sia completamente opaca.
Naturalmente, è necessario considerare le proprietà di opacità delle sole nestre map-
pate, in quanto le altre non sono sicuramente visibili. Tuttavia le proprietà di opacità
potrebbero cambiare quando è disattivato gli invio di eventi PropertyNotify, ovvero
proprio quando le nestre non sono mappate; di questa caratteristica il compositore
dovrebbe tenere conto in ricezione di ogni MapNotify.

2.4.3 Exposé
Già da tempo i window manager più diusi includono una funzionalità, comunemente
nota come application switcher o tab manager, che si attiva su richiesta dell'utente,
fornisce l'elenco delle nestre attive, e permette di selezionare rapidamente quella che si
preferisce.
Il problema di questo approccio è la mancanza del supporto visivo adeguato. Spesso,
infatti, i tab manager associano ad ogni nestra l'icona del programma corrispondente.
Tuttavia, nell'utilizzo comune della propria macchina, l'utente tende a tenere aperte
nestre dal nome simile, o con associata la medesima icona. All'aumentare del numero
di applicazioni attive, il problema diventa sempre maggiore, e diventa sempre più dicile
distinguere le varie nestre tra di loro senza ricorrere ad un continuo ed insoddisfacente
trial-and-error.

63
Compositing manager

I compositing manager permettono di risolvere il problema introducendo un nuovo


modello di tab manager, nel quale vengono mostrate non solo icone e nomi delle nestre,
ma anche il loro eettivo contenuto, aggiornato dinamicamente. Tra le altre cose es-
istono numerose varianti al medesimo modello di base, inizialmente introdotto in Quartz
Compositor, con il nome di Exposé [Sir05].
Componenti di questo genere sono presenti in Windows Vista e nei principali com-
positing manager per X. Tra questi è compreso Compiz, nel quale questa funzionalità è
realizzata da un plugin noto come Scale 41 (gura 2.11).
L'implementazione di un plugin di questo genere potrebbe essere basata su due pro-
prietà, impostate sulla nestra radice, individuate dagli atomi _NET_CLIENT_LIST e
_NET_ACTIVE_WINDOW. Al primo atomo sono associati gli identicatori di tutte le nestre
gestite dal window manager, mentre al secondo è associato l'identicatore della nes-
tra attiva ed impostata dai client. Entrambe le proprietà sono descritte dalla specica
EWMH.
Una volta ricevuto un certo evento, ad esempio in reazione ad un particolare input
utente42 , il compositore reagisce dividendo lo schermo in una serie di strisce, ognuna
ripartita in slot nel quali poi il compositore andrà a posizionare le immagini dinamiche,
o thumbnail, associate a ciascuna nestra. Il passaggio successivo è quello di assegnare
uno slot a ciascuna nestra, seguendo un criterio qualunque che potrebbe tenere conto
di dimensione e posizione originale delle nestre.
In seguito, e per ogni nestra, devono essere compiute le operazioni seguenti:

• mappare la nestra se non lo è già;

• ridimensionare la nestra se le sue dimensioni sono diverse da quelle dello slot


assegnato;

• disegnare la thumbnail.

Come ribadito più volte, X non assicura che il contenuto di una nestra sia conservato
quando questa non è visibile. Di conseguenza l'operazione di mapping è fondamentale,
in quanto assicura che il contenuto delle nestre sia accessibile e aggiornato in tempo
reale. Tuttavia, prima di inviare questa richiesta bisogna ricordarsi di impostare la ag
di ovveride-redirect, per evitare che le nestre siano prese in considerazione dal window
manager. Ovviamente, al termine delle operazioni, ag e visibilità delle nestre vanno
riportati ai loro valori iniziali.

2.4.4 Altri eetti


Magnier
Permettono all'utente di ingrandire un'area dello schermo a piacimento. Può essere
utilizzato per rendere più agevole la lettura, ma può essere utile anche per per
41
http://wiki.compiz-fusion.org/Plugins/Scale
42
Tradizionalmente, le funzionalità del tab manager sono richiamate dalla combinazione Alt+Tab.

64
2.5 Composizione in ambito embedded

concentrare l'attenzione su una piccola parte dello schermo. Tendenzialmente lo si


qualica come uno strumento per l'accessibilità.

Desktop switcher
Permettono all'utente di cambiare desktop, tramite la pressione di una certa com-
binazione di tasti, del mouse o della tastiera. La caratteristica è già messa a dis-
posizione dai normali window manager, tuttavia un compositore potrebbe creare
thumbnail dinamiche dei desktop, in maniera analoga a quanto fatto per le nestre,
migliorando così l'esperienza dell'utente.

Widget layer
Permettono all'utente di richiamare rapidamente le applicazioni di uso più comune,
come l'orologio, il blocco note o la calcolatrice. L'implementazione fa sì che queste
applicazioni siano sempre mappate, e continuino quindi renderizzare nei buer.
Tuttavia il gestore non ne tiene conto quando deve costruire la rappresentazione
dello schermo. Alla pressione di una certa combinazione di tasti, i widget sono
mostrati sullo schermo. Si noti che in questa maniera non viene richiesto nessun
repaint alle applicazioni.

Transizioni
Permettono di visualizzare particolari animazioni quando una nestra viene ridot-
ta ad icona, viene chiusa o viene ridimensionata. Possono essere di complessità
arbitraria, no ad arrivare ad eccessi come le nestre deformabili, o wobbling. Il
loro utilizzo può aiutare l'utente ad associare un immagine al cambiamento di stato
delle applicazioni, rendendo più chiaro cosa sta succedendo sullo schermo.

Altro
L'elenco sarebbe interminabile ma del resto, utilizzando le tecniche di composizione,
l'unico limite è la fantasia dello sviluppatore43 .

2.5 Composizione in ambito embedded


Quando il discorso sulla composizione si sposta sul mercato embedded, possono essere
fatte una serie di considerazioni molto diverse da quelle fatte per l'ambito desktop.
Al momento in cui si scrive, le realizzazioni commerciali di compositing manager em-
bedded sono relativamente poche. Tra di queste citiamo Matchbox, un window manager
open source realizzato per sistemi embedded che utilizzano l'X Window System [Proa].
La principale dierenza tra Matchbox (e buona parte dei compositori embedded) e
le controparti desktop, sta nella limitazione auto-imposta di poter mostrare una sola
nestra alla volta. Matchbox, tra l'altro, è stato utilizzato dalle versioni di Maemo
precedenti alla 6.
43
Un video val più di mille parole: http://www.youtube.com/watch?v=rNeWMLSmkXQ

65
Compositing manager

Il problema principale è la limitatezza, negli embedded, di due risorse fondamentali:


potere computazionale e hardware graco. Dato che, in queste condizioni, utilizzare un
rendering puramente software risulta infattibile, praticamente tutti gli embedded che
supportano la composizione sfruttano una qualche forma di accelerazione graca.
A questo punto, però, sorge un altro problema, dovuto alla libreria graca 3D che
viene utilizzata, che normalmente è OpenGL ES. La specica iniziale, ancora supportata
dalla maggior parte delle macchine sul mercato, presenta una serie di limitazioni parti-
colarmente rilevanti per il rendering di un interfaccia graca. Questa caratteristica non
deve stupire, in quanto OpenGL ES nasce principalmente per supportare il videogaming
[LK06].
Il problema più rilevante è quello della dimensione delle texture, limitate a 64 × 64 tex-
el, che rende molto dicoltosa la gestione delle texture ricavate dai buer di redirezione.
OpenGL ES supporta la compressione delle texture, che permetterebbe di gestire, abbas-
tanza semplicemente, texture della grandezza necessaria. Tale sistema può sicuramente
essere appropriato per i videogiochi, nei quali le texture vengono caricate una sola vol-
ta e tendenzialmente non cambiano nel corso dell'intera esecuzione del programma. Al
contrario, non può essere utilizzato nell'implementazione di un'interfaccia, in quanto le
texture associate alle nestre devono essere aggiornate molto di frequente.
Questi problemi, fortunatamente, sono stati risolti nella versione 2.0 di OpenGL ES44 ,
una specica molto più completa, ma allo stesso tempo molto più esigente nei confronti
dell'hardware. Attualmente sono poche le macchine che la supportano: tra queste vale
la pena citare i più recenti smartphone Nokia di fascia alta, a partire dall'N90045 .
La board U8500 di St-Ericsson, dalla cui analisi ha avuto origine il lavoro di tesi (vedi
capitolo introduttivo) monta una scheda graca Mali, che da pieno supporto a OpenGL
ES 2 [Gal10]. Nel seguito, in ogni caso, verrà data per scontata la possibilità di avere
accesso alle versioni più recenti della specica.
Ovviamente, programmando in un ambiente X11, è necessaria un'architettura che per-
mette di accedere alle funzionalità di OpenGL ES all'interno di una nestra o più in
generale gestisca il rendering ES all'interno di X. Allo scopo, analogamente a quanto
avviene con OpenGL (2.3.3), esiste EGL (Embedded-System Graphics Library ), la con-
troparte embedded di GLX. Fondamentalmente EGL può essere vista come un interfaccia
tra le API di rendering46 e il windowing system.
Generalmente, in un dato sistema saranno disponibili l'una o l'altra architettura, a
seconda del supporto fornito dall'hardware graco; nonostante questo, considerando che
ES non è altro che un sottoinsieme di OpenGL, esistono alcune librerie di raccordo, o
binding, che permettono di utilizzare EGL anche su sistemi OpenGL.

44
La specica di OpenGL ES2.0 è stata rilasciata nel 2007.
45
http://www.khronos.org/news/permalink/nokias-new-maemo-n900-with-opengl-es-2.0-
support/
46
EGL permette di interfacciarsi anche con OpenVG.

66
2.6 Note implementative

2.6 Note implementative


In questa sezione vengono fornite alcune note, che illustrano come tutti i meccanismi
descritti nelle sezioni precedenti si combinino tra loro e possano essere utilizzati concre-
tamente. Nel codice sono utilizzate praticamente solo chiamate Xlib, anche se l'ipotesi
di fondo è quella di lavorare all'interno di un ambiente Qt. Negli esempi viene illus-
trato XRender; la motivazione è quello di evitare sovrapposizioni con l'implementazione
approfondita mostrata nella prossima sezione (2.7).
I frammenti di codice sono estratti da [Hognd]. Si noti come la maggior parte delle
funzioni di libreria utilizzate siano la diretta controparte delle richieste denite dal
protocollo, e presentate nelle sezioni precedenti.

2.6.1 Verica del supporto al compositing


Per prima cosa, bisogna trovare un sistema per assicurarsi, a run-time, che il server di X
al quale ci si sta connettendo sia dotato dell'estensione composite. A questo può e deve
essere associato un controllo a compile-time, la cui utilità è tuttavia limitata all'assicurarsi
della presenza delle librerie necessarie per la compilazione.
Prima di chiamare una qualunque funzione Xlib, bisogna ottenere da parte di Qt
un puntatore alla struct Display. Questa fondamentale struttura è creata dal client
(in questo caso il toolkit) quando si connette al server e contiene un gran numero di
informazioni sulla connessione (1.4.1). A questo scopo può essere utilizzata la funzione
statica QX11Info::x11AppDisplay()47 .
Display * dpy = QX11Info :: x11AppDisplay ();

Una volta ottenuto il puntatore si può procedere a vericare il supporto alle estensioni:
bool hasNamePixmap = false ;
int event_base , error_base ;
if ( XCompositeQueryExtension ( dpy , & event_base , & error_base ))
{
// Se si arriva qui il server supporta il composite
int major = 0 , minor = 4; // La più alta versione supportata
XCompositeQueryVersion ( dpy , & major , & minor );

// major e minor contegono il valore della versione supportata


// il protocollo specifica che i la versione ritornata non è
// mai più alta di quella richiesta .
// La versione 0.2 è la prima a supportare NameWindowPixmap .
if ( major > 0 || minor >= 2)
hasNamePixmap = true ;
}

47
La classe QX11Info serve come punto di raccolta di tutte le informazioni di congurazione del display
di X. La classe espone due API: una di funzioni statiche che forniscono le informazioni associate
all'applicazione corrente, l'altra di funzioni non statiche che danno informazioni su uno specico
widget o una specica pixmap.

67
Compositing manager

2.6.2 Utilizzare Composite


Una volta vericata la presenza del compositing, bisogna attivare la redirezione. Tra le
varie possibilità, la più semplice consta nel chiamare XCompositeRedirectSubwindows()
per ciascuna delle nestre di root48 , specicando il tipo di redirezione richiesta:
for ( int i = 0; i < ScreenCount ( dpy ); i ++)
XCompositeRedirectSubwindows ( dpy , RootWindow ( dpy , i) ,
CompositeRedirectAutomatic );

L'eetto della chiamata precedente è quello di far sì che il contenuto di tutte le nestre
top-level, presenti e future, sia disegnato nei buer.
Non bisogno preoccuparsi di annullare la redirezione, in quanto ciò viene fatto auto-
maticamente quando l'applicazione chiude la connessione con il server. Inoltre, se un'altra
applicazione, tipicamente un altro compositing manager, ha già richiesto per se stesso la
redirezione dell'output, la chiamata diventa una NOP.
Le altre applicazioni non sono consapevoli della redirezione, così come le stesse nestre:
la conseguenza è che non dev'essere fatta nessuna modica ai programmi preesistenti. Sia
dal punto di vista dell'utente, che da quello dei programmi, tutto continua a funzionare
come se niente fosse mai successo.
Nel caso in cui siano d'interesse solo le nestre correnti o comunque un sottoin-
sieme ristretto di queste, è bene chiamare la più limitata XCompositeRedirectWindow(),
ricordandosi di annullare la redirezione prima di uscire.
Ogni volta che una nestra viene mostrata a schermo, Composite alloca una Pixmap
che funge da buer di redirezione. Tuttavia, ogni volta che la nestra diventa visibile
questa Pixmap è subito deallocata. In altre parole, ogni volta che la nestra è ridotta ad
icona, o portata su di un altro desktop, il contenuto di quella nestra non è accessibile49 .
Fondamentalmente, ci sono due ragioni alla base di questo comportamento. La pri-
ma è sicuramente la riduzione dell'occupazione della memoria video dovuto ai buer di
redirezione. La seconda è che uno dei principi tradizionalmente accettati, nella program-
mazione con Xlib, è che tentare di disegnare su una nestra nascosta si traduce in una
NOP. Spesso le applicazioni (e i toolkit) sfruttano questo principio e non sprecano risorse
cercando di disegnare su di una nestra che non è visibile.
Questo potrebbe rivelarsi un inconveniente per chi volesse realizzare alcuni eetti par-
ticolari. Ad esempio, si potrebbe desiderare che, passando con il puntatore sulla barra
di stato, fossero visualizzate le thumbnail di tutte le nestre, comprese quelle ridotte ad
icona, oppure si vorrebbe realizzare un eetto stile Exposé (2.4.3).
Ci sono almeno due possibili soluzioni: la prima consiste nel salvare da qualche parte
un'immagine della nestra prima che ne sia fatto l'unmap. La seconda soluzione è quella
48
Come detto in precedenza, ad ogni schermo è associata una ed una sola nestra radice, e normalmente
un sistema controlla un solo schermo. Tuttavia, nel caso dei cosiddetti sistemi multihead, gli schermi
possono essere due o più .
49
Mentre i contenuti di una nestra ridotta ad icona non saranno mai disponibili, i contenuti delle
nestre su desktop dierenti potrebbero essere disponibili, a seconda del design del window manager.
Ad esempio, se il WM usa una nestra radice virtuale per ogni desktop e non nasconde quelle inattive,
le nestre su quei desktop saranno accessibili.

68
2.6 Note implementative

di mappare temporaneamente le nestre quando è richiesta una funzionalità simile a


quelle sopra descritte. Questo secondo approccio è discusso nel paragrafo 2.4.3

2.6.2.1 Accedere agli attributi delle nestre


Per accedere al contenuto di una nestra, bisogna prima conoscerne l'identicatore. Tut-
tavia, per gli scopi di un compositing manager, l'identicatore non è suciente. Sono
infatti necessarie almeno altre tre informazioni: dimensione, PictFormat50 , e una ag
che indichi se la visuale utilizzata prevede anche valori di trasparenza (la si ricava dal
formato).
Chiamando XGetWindowAttributes(), è possibile inizializzare una struttura dalla
quale si possono ottenere queste e molte altre informazioni:
XWindowAttributes attr ;
XGetWindowAttributes ( dpy , wId , & attr );

XGetWindowAttributes è una chiamata sincrona, o bloccante, dunque sarebbe meglio


evitare di chiamarla troppo spesso. In un'applicazione reale andrebbe anche controllato
il valore di ritorno della chiamata in quanto, a causa della presenza in Xlib di una coda
per le richieste, durante l'attesa la nestra potrebbe essere stata deallocata.
Una volta inizializzata la struttura XWindowAttributes, bisogna estrarre le infor-
mazioni richieste. Ad esempio:
XRenderPictFormat * format = XRenderFindVisualFormat ( dpy , attr . visual );
bool hasAlpha =
( format - > type == PictTypeDirect && format - > direct . alphaMask );
int x = attr . x ;
int y = attr . y ;
int width = attr . width ;
int height = attr . height ;

2.6.3 Utilizzare XRender


In questo paragrafo viene mostrato come creare ed operare su una Picture (o immagine)
della nestra, struttura dati sulla quale operano le funzioni di disegno di XRender.
In Xlib, un oggetto Picture è un semplice riferimento ad una struttura memorizzata
sul server, che a sua volta contiene alcune informazioni addizionali su di una nestra o
una pixmap: formato dei pixel, regione di clipping da utilizzare, eccetera.
Per creare un immagine bisogna chiamare XRenderCreatePicture(). Questa funzione
non è sincrona, quindi ritornerà immediatamente, anche nel caso la nestra richiesta non
esista. Nel caso che l'esecuzione non vada a buon ne, il servre invia un messaggio di
errore, che l'applicazione dovrebbe gestire. La soluzione immediata è quella di far sì che
il riferimento ottenuto in precedenza venga invalidato51 .
Nel esempio seguente viene creata una immagine di XRender:
50
Si ricorda che si sta ipotizzando di utilizzare XRender.
51
Invalidare il riferimento alla picture potrebbe portare ad ulteriori errori qualora l'identicatore fosse
già stato utilizzato in altre chiamate a funzione.

69
Compositing manager

// Il subwindow mode viene impostato a IncludeInferiors ,


// in modo che i child widget vengano inclusi nell ' immagine .
XRenderPictureAttributes pa ;
pa . subwindow_mode = IncludeInferiors ;

Picture picture =
XRenderCreatePicture ( dpy , wId , format , CPSubwindowMode , & pa );

Una volta trasformato il buer di redirezione in un'immagine di XRender è nalmente


possibile disegnare a schermo il contenuto della nestra. Allo scopo si può utilizzare
XRenderComposite(), la cui rma è:
void
XRenderComposite ( Display * dpy ,
int op ,
Picture src ,
Picture mask ,
Picture dst ,
int src_x ,
int src_y ,
int mask_x ,
int mask_y ,
int dst_x ,
int dst_y ,
unsigned int width ,
unsigned int height );

In generale, scelto un oggetto come output del disegno, bisogna crearne una descrizione
comprensibile ad XRender (una Picture ). Se l'obiettivo è disegnare su un QWidget o
su una QPixmap, il compito viene semplicato da Qt: il metodo x11PictureHandle(),
implementato da entrambe le classi, ritorna al chiamante un puntatore alla struttura
richiesta52 .
Maggiori dettagli sulla richiesta Composite possono essere trovati nel paragrafo 2.3.2.
Concludiamo il paragrafo illustrando una possibile chiamata ad XRenderComposite.
Nell'esempio si suppone che dest rappresenti un QWidget, e che destX e destY rap-
presentino la posizione (relativamente al widget) dove si vuole che XRender disegni
l'immagine.
XRenderComposite ( dpy , hasAlpha ? PictOpOver : PictOpSrc , picture , None ,
dest . x11RenderHandle () , 0 , 0 , 0 , 0 , destX , destY , width , height );

2.6.3.1 Finestre dalla forma particolare


Un buer di redirezione ha sempre una forma rettangolare: questo, però, non è vero in
generale per le nestre. Si vorrebbe dunque evitare di copiare pixel del buer che non
fanno parte della nestra (e che quindi hanno valore indenito). La soluzione è quella
di impostare per la Picture una regione di clipping della stessa forma della nestra53 .
52
Si sta ipotizzando che Qt sia stato compilato con il supporto per il paint engine per XRender (2.3.4).
53
Quando si disegna una pixmap con XRender, vengono utilizzate due picture : una per la pixmap
sorgente ed una per quella di destinazione. Dato che è possibile assegnare una regione di clipping ad

70
2.6 Note implementative

Implementare questa funzionalità richiede l'uso dell'estensione XFixes della quale, al pari
di Composite, bisogna assicurare la presenza tramite controllo a run-time54 .
// Crea una copia della regione di bounding della finestra
XserverRegion region =
XFixesCreateRegionFromWindow ( dpy , wId , WindowRegionBounding );

// Sposto l ' origine della coordinate in cui è descritta la regione


// dall ' origine dello schermo all ' origine della finestra
XFixesTranslateRegion ( dpy , region , -x , -y );
XFixesSetPictureClipRegion ( dpy , picture , 0 , 0 , region );
XFixesDestroyRegion ( dpy , region );

Non bisogna dimenticare che, essendo solo una copia, la regione va aggiornata man-
ualmente ogni qual volta la nestra cambia forma o viene ridimensionata. A questo
proposito, XShape può fornire delle notiche ogni qual volta viene modicata la forma
di una nestra, attraverso la funzione XShapeSelectInput():
XShapeSelectInput ( dpy , wId , ShapeNotifyMask );

2.6.4 Filtrare gli eventi


Come detto nel paragrafo 1.4.1, una volta arrivati nei client gli eventi sono memorizzati
all'interno di XEvent ed inseriti in una coda, o event queue. L'applicazione può estrarre
l'evento in testa alla coda chiamando la funzione XNextEvent().
Più in dettaglio, ad ogni evento del protocollo corrisponde una struttura diversa:
XEvent è l'unione che contiene tutte le possibili strutture. Il primo membro, comune
a tutte le strutture, è il campo type, nel quale è contenuto un valore che identica
univocamente il tipo di evento ricevuto.
Normalmente, utilizzando un toolkit di alto livello come Qt, lo sviluppatore non deve
preoccuparsi di questi dettagli. Il funzionamento del compositing, tuttavia, richiede una
manipolazione a grana ne degli eventi, prima che questi siano processati da un qualsiasi
toolkit.
Utilizzando Qt, la soluzione è quella di re-implementare un metodo virtuale che viene
chiamato ogni qualvolta un evento viene estratto dalla coda, ma prima che sia processato
da Qt: si sta parlando di QApplication::x11EventFilter. Il valore di ritorno di questa
funzione indica se l'evento è considerato gestito (true ) o deve invece comunque essere
processato da Qt (false ). Una soluzione analoga, è riportata, con dovizia di particolari,
nella sezione successiva.
In una struttura di questo genere diventa fondamentale individuare gli eventi alla quale
si è interessati. A questo scopo il campo type sembra ideale. Tuttavia, per riconoscere
correttamente un evento originato da un'estensione è necessario conoscere il relativo
valore di base (1.3.7), che dipende dall'implementazione e deve essere ottenuto a run-

entrambe, è possibile eettuare questa operazione sulla Picture di destinazione invece che su quella
di origine, posto che non vengano eettuate trasformazioni geometriche durante il disegno.
54
Il codice per controllare il supporto server ad una estensione è praticamente identico in ogni caso.

71
Compositing manager

time. Fortunatamente, a questo scopo possono essere usate le chiamate di query come
XDamageQueryExtension.
A seguire è presentata una semplice re-implementazione di x11EventFilter. Il corpo
della funzione si limita a controllare se l'evento ricevuto è uno di quelli di interesse. In
caso aermativo provvede ad una gestione personalizzata, che qui non è riportata.
bool x11EventFilter ( XEvent * event )
{
if ( event - > type == damage_event + XDamageNotify ) {
XDamageNotifyEvent * e =
reinterpret_cast < XDamageNotifyEvent * >( event );
...
}

else if ( event - > type == shape_event + ShapeNotify ) {


XShapeEvent * e = reinterpret_cast < XShapeEvent * >( event );
...
}

else if ( event - > type == ConfigureNotify ) {


XConfigureEvent * e = & event -> xconfigure ;
...
}

return false ;
}

In un'implementazione reale, andrebbe tenuto a mente che nella coda potrebbero essere
presenti più eventi relativi ad una stessa nestra, per cui bisognerebbe processarli tutti
prima di compiere una qualunque azione. Si pensi al caso di una DestroyNotify in coda
mentre viene processato inutilmente un DamageNotify.

2.6.5 Utilizzare Damage


Dato che non ci si vuole limitare a visualizzare immagini statiche, è necessario ridisegnare
le nestre ogni qualvolta che il contenuto del buer viene modicato.
La prima cosa che bisogna fare, se si vuole reagire dinamicamente al cambiamento, è
vericare che il server supporti Damage.
int damage_event , damage_error ; // è importante salvare damage_event
XDamageQueryExtension ( dpy , & damage_event , & damage_error );

Il passo seguente è quello di creare, per ogni nestra gestita dal compositore, il cor-
rispondente damage handle. Ci sono diversi modi tramite i quali Damage può segnalare
i cambiamenti di una nestra55 . Nell'esempio specichiamo che dev'essere inviato un
evento ogni qualvolta lo stato della nestra cambia da non-danneggiato a danneggiato56 .
Damage damage = XDamageCreate ( dpy , wId , XDamageReportNonEmpty );
55
Si noti che Damage può seguire le modiche apportate ad una Pixmap, qualora questo fosse d'interesse.
56
Ad ogni chiamata a XDamageCreate deve corrisponderne una a XDamageDestroy, non appena non sia
più richiesto il tracciamento dei danni.

72
2.7 Un esempio completo

Si noti che Damage dierisce dalla maggior parte delle altre estensioni per quanto
riguarda la notica degli eventi. Normalmente, infatti, ci si potrebbe aspettare che i
client interessati eettuino una chiamata del tipo XDamageSelectInput(). Del resto
è così che si comportano molte estensioni, come XShape. Damage, invece, richiede la
creazione, da parte del client, di un oggetto particolare di tipo Damage.

2.6.5.1 Gestore personalizzato per i DamageNotify


Nell'esempio successivo, l'ultimo, viene riportata una possibile implementazione di un
gestore personalizzato per gli eventi di danneggiamento. Il gestore deve essere richiamato
all'interno di una struttura analoga a quella descritta nel paragrafo 2.6.4.
L'informazione sul danneggiamento viene utilizzata per impostare una regione di clip-
ping associata alla nestra. In questa maniera, al prossimo ridisegno, saranno copiati solo
quei pixel che non fanno parte della regione di clipping, ovvero quei pixel eettivamente
danneggiati secondo l'ultima segnalazione ricevuta57 .
// Crea una regione vuota grazie ad XFixes
XserverRegion region = XFixesCreateRegion ( dpy , 0, 0);

// Copia la regione danneggiata nell ' oggetto appena creato


// Contemporaneamente ripara anche la finestra
XDamageSubtract ( dpy , e - > damage , None , region );

// Traslazione nel sistema di coordinate della finestra


XFixesTranslateRegion ( dpy , region , e - > geometry .x , e - > geometry . y );

// Imposta la regione come zona di clipping


XFixesSetPictureClipRegion ( dpy , picture , 0 , 0 , region );

XFixesDestroyRegion ( dpy , region );

2.7 Un esempio completo


In questa sezione viene fornito, e analizzato in dettaglio, il codice di un semplice com-
positing manager. Il programma non può e non deve essere inteso come un compositing
window manager completo, ma come un esempio, utile allo scopo di mostrare le princi-
pali caratteristiche di cui si è discusso nella sezione precedenti. D'altra parte questi stessi
concetti sono gli stessi che sono alla base delle principali implementazioni reali.
Il compositore non assomma a sé le funzionalità di window management, ma è pre-
disposto per appoggiarsi ad un qualunque WM preesistente. Al peggio è in grado di
funzionare anche in un contesto in cui non è in esecuzione nessun WM ma, in questo
caso, non saranno possibile interagire con le nestre, né avere a disposizione alcuna forma
di decorazione.
57
Bisogna ricordare che questa implementazione è da rivedere nel caso che, prima di ridisegnare, si voglia
ridimensionare l'immagine.

73
Compositing manager

Per quanto riguarda le librerie utilizzate, oltre ad Xlib, l'implementazione è basata su


Clutter (vedi 1.4.4), per cui il codice è scritto interamente in C. Clutter, e di conseguenza
lo stesso compositore, utilizza OpenGL come proprio motore di rendering, per cui uno dei
compiti fondamentali sarà quello della trasformazione dei buer di redirezione in texture.
L'utilizzo di Clutter, inne, permette di potersi appoggiare al paradigma di scena e di
attori (vedi sempre 1.4.4) per la gestione della rappresentazione delle nestre.
L'architettura del compositore è basata, così come lo stesso Clutter suggerisce, sul
modello di programmazione ad eventi. A seguito di una fase di inizializzazione (2.7.1),
l'evoluzione successiva del programma è completamente guidata dagli eventi. Gran parte
del codice, infatti, è dedicata alla gestione degli stessi, e specialmente alla loro redirezione
da una funzione all'altra. La catena si interrompe al raggiungimento di un ltro, apposi-
tamente programmato, che richiama una serie di gestori personalizzati. Questi gestori,
di fatto, costituiscono il cuore del compositore (2.7.2).
Il codice riportato, tuttavia, si ferma qui. Prima di ottenere le texture, fondamentali
per il rendering OpenGL, non viene implementato nessun eetto, tanto che non sarà
notata nessuna dierenza rispetto alla semplice esecuzione di una tradizionale window
manager.
La dierenza rispetto a quanto discusso nella sezione 2.6, è che qui le funzionalità
vengono illustrate in un contesto reale. Inoltre, non vi è ripetizione in quanto, utilizzando
Clutter, l'approccio è radicalmente diverso.
Buona parte del codice è basata sull'implementazione riportata in [Win08].

2.7.1 Inizializzazione
La funzione principale del programma è molto semplice: si limita a chiamare una serie
di funzioni di inizializzazione e ad entrare nel ciclo eventi principale di Clutter.
int main ( int argc , char * argv [])
{
init_clutter (& argc , & argv );
init_root ();
init_overlay ();
init_stage ();
init_input ();

clutter_main ();

return 0;
}

Nel seguito, saranno analizzate una ad una le chiamate appena presentate. Si tenga
presente che per semplicità è stato omesso di controllare, a run-time, la presenza sul
server delle estensioni necessarie.
Per prima, lasciando momentaneamente da parte init_clutter, sarà analizzata la
funzione init_root:
Display * dsp ;
Window root ;

74
2.7 Un esempio completo

void init_root ( void )


{
dsp = clutter_x11_get_default_display ();
root = DefaultRootWindow ( dsp );
XCompositeRedirectSubwindows ( dsp , root , CompositeRedirectAutomatic );
XSelectInput ( dsp , root , SubstructureNotifyMask );
}
Dopo aver ottenuto le informazioni sulla connessione al server X (la struttura Display)
e di conseguenza l'identicatore associato alla nestra radice, le si salva in alcune variabili
globali in maniera che siano disponibili al resto del codice. Si noti che non è stato
necessario aprire esplicitamente una connessione con il server X, in quanto di questo si
occupa già Clutter.
Il fulcro della funzione sta, tuttavia, nelle ultime due righe. Per prima cosa viene
chiesto al server X di redirigere l'output della nestra radice e di tutti i suoi gli, presenti
e futuri, nei buer di redirezione. Allo scopo è stata utilizzata la stessa funzione descritta
nel paragrafo 2.6.2.
Tramite i buer di redirezione, è possibile accedere al contenuto di tutte le nestre map-
pate, anche se per l'X server queste sono completamente invisibili. Si noti che viene pas-
sato il parametro CompositeRedirectAutomatic che sta a signicare che ogni qualvolta
cambia il contenuto della nestra originale, X aggiorna automaticamente i buer. Come
detto nel paragrafo 2.2.3, questo comportamento non è desiderabile nel caso generale,
in quanto l'implementazione degli eetti graci spesso richiede di gestire manualmente
tutti gli aggiornamenti.
Con l'ultima chiamata, viene chiesto al server di riportare al window manager tutti
gli eventi concernenti modiche strutturali della nestra principale e di tutti i suo gli,
presenti e futuri58 . Questo sta a signicare che, al compositore, sarà inviato un evento
ogni qual volta una qualunque nestra59 viene mappata a schermo, cambia dimensione,
eccetera.
La seconda funzione analizzata è init_overlay:
Window overlay ;
void init_overlay ( void )
{
overlay = XCompositeGetOverlayWindow ( dsp , root );
input_passthrough ( overlay );
}
L'estensione Composite, mette anche a disposizione una nestra particolare, la nestra
di overlay. La sua caratteristica è quella di essere sempre al di sopra di tutte le altre
nestre, il che ne fa l'output naturale del processo di composizione. È possibile disegnare
direttamente sull'overlay, anche se normalmente si preferisce utilizzare l'overlay come
padre di una seconda nestra creata appositamente e sulla quale poi eettivamente si
disegna. In questo caso è utilizzato il secondo e più comune approccio: a fare le veci del
glio, come si vedrà in seguito, è lo stage principale di Clutter.
58
Si noti che si sta tralasciando, per semplicità, il caso in cui siano disponibili più display e dunque più
nestre radici. Si veda la sezione precedente per un'implementazione alternativa.
59
Si ricorda che, in eetti, tutte le nestre sono glie della nestra radice.

75
Compositing manager

Questa architettura presenta però un grosso problema: ridirigere l'output di una nes-
tra da una qualche altra parte non ha alcun eetto sull'input. Un esempio banale può
essere osservato in Compiz : è possibile posizionare e visualizzare una nestra sullo spigo-
lo di un cubo, ma in quel frangente non sarà possibile gestire alcun input. La ragione
che è alla base di questo comportamento è che, per poter interagire con una nestra il
server X ha bisogno di sapere come trasformare le coordinate globali associate a ciascun
evento in coordinate locali alla nestra interessata. Il problema non è banale e dovrebbe
essere risolto modicando l'implementazione del server [Win08].
In mancanza di una soluzione generale, il risultato è che tutti i compositing manager
devono essere molto attenti ed assicurarsi che le coordinate della nestra siano esatta-
mente identiche alle coordinate alle quali se ne sta disegnando l'immagine. In questa
maniera, quando l'utente clicca sull'immagine, ad esempio, di un bottone, il click in
realtà ltra attraverso l'overlay e viene gestito dalla vera nestra sottostante.
Detto questo, di seguito viene presentato il codice che permette questo passaggio, o
ltro, degli eventi attraverso l'overlay :
void input_passthrough ( Window w )
{
XserverRegion region = XFixesCreateRegion ( dsp , NULL , 0);
XFixesSetWindowShapeRegion ( dsp , w , ShapeBounding , 0 , 0 , 0);
XFixesSetWindowShapeRegion ( dsp , w , ShapeInput , 0 , 0 , region );
XFixesDestroyRegion ( dsp , region );
}

Sono richiamate una serie di funzionalità di XFixes il cui eetto complessivo è quello
di prendere la nestra passata come parametro, e renderla trasparente agli eventi di
X. Il risultato si ottiene azzerando l'area di input della nestra. Non si vuole, però,
che la nestra venga forzata ad avere dimensione nulla, pertanto la prima chiamata a
SetWindowShapeRegion si assicura che rimanga invariata l'area che delimita la nestra
(detta anche regione di bounding ).
Il passo successivo è quello di creare lo stage di Clutter, ovvero la nestra GLX che
servirà da output per il processo di rendering; il tutto avviene all'interno di init_stage:
ClutterActor * stage ;
Window win_stage ;
void init_stage ( void )
{
ClutterColor color ;
stage = clutter_stage_get_default ();
clutter_stage_set_fullscreen ( CLUTTER_STAGE ( stage ) , TRUE );
win_stage = clutter_x11_get_stage_window ( CLUTTER_STAGE ( stage ));
clutter_color_parse ( " Grey " , & color );
clutter_stage_set_color ( CLUTTER_STAGE ( stage ) , & color );

XReparentWindow ( dsp , win_stage , overlay , 0 , 0);


input_passthrough ( stage_win );

clutter_actor_show_all ( stage );
}

76
2.7 Un esempio completo

Come detto nel paragrafo 1.4.4, lo stage è un'astrazione che rappresenta il luogo in cui
si muovono tutti gli oggetti gestiti da Clutter (gli attori). Implementando il compositore,
si vuole che lo stage ne diventi la supercie di rendering principale, per cui questo deve
essere reso glio della nestra di overlay restituita da Composite. Allo scopo, una volta
ottenuto un puntatore allo stage, si usa XReparentWindow. Il risultato è che la supercie
di rendering del compositore si troverà sempre al di sopra di tutte le altre nestre e verrà
resa invisibile agli eventi.
Inne, con l'ultima riga si chiede di mappare a schermo la nestra X11 associata allo
stage.
Cosa accade, però, se un evento non gestito direttamente dallo stage né tanto meno
dall'overlay, non viene poi gestito da nessuna nestra? Se non si intervenisse, alla ne
questi eventi sarebbero ricevuti dalle nestra radice. Tuttavia, un comportamento più
appropriato potrebbe essere quello di riportare allo stage tutti gli eventi altrimenti non
gestiti. La risoluzione del problema è adata alla funzione init_input:
Window win_input ;
void init_input ( void )
{
XWindowAttributes attr ;
XGetWindowAttributes ( dsp , root , & attr );
win_input = XCreateWindow ( dsp , root ,
0 , 0 , /* x , y */
attr . width , attr . height ,
0 , 0 , /* border width , depth */
InputOnly , DefaultVisual ( dsp , 0) , 0 , NULL );
XSelectInput ( dsp , input ,
StructureNotifyMask | FocusChangeMask | PointerMotionMask
| KeyPressMask | KeyReleaseMask | ButtonPressMask
| ButtonReleaseMask | PropertyChangeMask );
XMapWindow ( dsp , input );
XSetInputFocus ( dsp , win_input , RevertToPointerRoot , CurrentTime );

attach_to_event_source ();
}

La soluzione utilizzata è quella di creare una nestra di tipo InputOnly, al di sotto di


tutte le altre nestre, radice esclusa. Questo naturalmente non basta: è anche necessario
modicare gli eventi ricevuti dalla nestra, indicando come nuova sorgente dell'evento lo
stage principale di Clutter.
Per realizzare questo proposito viene essere utilizzata una strategia alquanto complessa,
che obbliga a pre-trattare manualmente tutti gli eventi ricevuti dall'applicazione.
Sul socket attraverso il quale avviene la comunicazioni tra il compositore e l'X server
viene messo in ascolto un oggetto di tipo GSource 60 che controlla ciclicamente il socket
(operazione di poll ) per riconoscere l'arrivo di una qualche comunicazione. Quando ciò
avviene, prepara la sorgente con event_prepare, controlla di aver eettivamente ricevuto
un evento con event_check, ed inne chiama event_dispatch per chiamare il gestore
opportuno. Questo comportamento replica ciò che avviene normalmente in Clutter, con
60
Un GSource è un oggetto di uso molto più generale per la gestione dell'I/O, vedi [Lib10a]

77
Compositing manager

una fondamentale dierenza: prima di eettuarne il dispatch viene modicata la struttura


di tutti quelli eventi intercettati dalla apposita nestra InputOnly.
L'inizializzazione del GSource avviene all'interno di attach_to_event_source, ripor-
tata qui di seguito:
GPollFD event_poll_fd ;
static GSourceFuncs event_funcs = {
event_prepare ,
event_check ,
event_dispatch ,
NULL
};

void attach_to_event_source ( void )


{
GSource * source ;
source = g_source_new (& event_funcs , sizeof ( GSource ));
event_poll_fd . fd = ConnectionNumber ( dpy );
event_poll_fd . events = G_IO_IN ;
g_source_set_priority ( source , CLUTTER_PRIORITY_EVENTS );
g_source_add_poll ( source , & event_poll_fd );
g_source_set_can_recurse ( source , TRUE );
g_source_attach ( source , NULL );
}
Delle tre funzioni di callback chiamate da GSource, viene analizzata solo la più interes-
sante, event_dispatch, nel quale avviene l'eettiva redirezione degli eventi dalle nestra
di input allo stage:
static gboolean
event_dispatch ( GSource * source , GSourceFunc callback , gpointer user_data )
{
ClutterEvent * event ;
XEvent xevent ;
clutter_threads_enter ();
while (! clutter_events_pending () && XPending ( dpy )) {
XNextEvent ( dpy , & xevent );
/* NOTA BENE */
if ( xevent . xany . window == input ) {
xevent . xany . window = win_stage ;
}
clutter_x11_handle_event (& xevent );
}
if ( event = clutter_event_get ()) {
clutter_do_event ( event );
clutter_event_free ( event );
}
clutter_threads_leave ();
return TRUE ;
}
Il sistema appena creato sostituisce completamente la normale ricezione degli eventi
di Clutter: l'architettura è abbastanza complessa, ma necessaria per svolgere il compito
preposto data la mancanza di supporto da parte di Clutter.

78
2.7 Un esempio completo

Si noti come si sia costretti a indirizzare esplicitamente anche i ClutterEvent generati


dallo stesso Clutter, a volte proprio all'interno dei gestori degli eventi di X. La ragione è
che, se si disattiva il recupero automatico degli XEvent in modo da poter installare un
GSource personalizzato, viene disattivato anche il recupero dei ClutterEvent.
L'analisi delle funzioni di inizializzazione è completata dal codice della prima chiamata,
init_clutter:
GType texture_type ;
void init_clutter ( int * argc , char ** argv )
{
clutter_x11_disable_event_retrieval ();
clutter_init ( argc , argv );
clutter_x11_add_filter ( event_filter , NULL );
if ( NO_TFP ) /* macro */
texture_pixmap_type = CLUTTER_X11_TYPE_TEXTURE_PIXMAP ;
else
texture_pixmap_type = CLUTTER_GLX_TYPE_TEXTURE_PIXMAP ;
}

Il motivo per cui questa analisi è stata rimandata alla ne è quella di poter chiarire
il motivo della prima chiamata, che disattiva il recupero automatico degli eventi da
parte di Clutter. Dovrebbe essere ormai chiaro che tale funzionalità è stata comple-
tamente rimpiazzata dall'implementazione custom appena presentata. La chiamata a
clutter_x11_add_filter fa sì che gli eventi X11 passati a Clutter dalle chiamate a
clutter_x11_handle_event (all'interno di event_dispatch) vengano ltrati dalla fun-
zione locale event_filter.
Per comprendere il contenuto della struttura condizionale (if-else ) che chiude la fun-
zione, bisogna ricordare quanto detto a proposito del redirected direct rendering (2.3.3.2).
Alla luce di quello discusso, infatti, non è possibile utilizzare l'estensione Texture From
Pixmap di GLX se si utilizzano driver open e la propria distribuzione non dispone di
DRI2. Ovviamente si potrebbe risolvere il problema forzando il rendering indiretto61 ,
trascurando così la perdita prestazionale. Tuttavia questa opzione potrebbe non essere
disponibile, specialmente se il compositore viene eseguito in un server X emulato come
Xephyr (vedi 2.7.3). Per tutto quello che si è appena detto si è preferito lasciare all'utente
la possibilità di compilare il compositore escludendo esplicitamente l'utilizzo di TFP. La
possibilità è lasciata tramite una semplice macro personalizzabile a mano (teoricamente
anche tramite un opportuno script di congurazione).
Si noti comunque che, sia nel caso appena descritto, che in quello gran lunga più
comune in cui viene utilizzato TFP, non è necessario scrivere che poche righe di codice,
in quanto la libreria di Clutter contiene delle pseudo-classi (ovvero dei GObject ) che
svolgono tutto il lavoro.
Concludiamo il paragrafo riassumendo la catena di gestione degli eventi:
1. Un qualche avvenimento esterno (generato dall'utente o da un'altra applicazione)
fa sì che il server di X generi un XEvent ; alternativamente lo stesso Clutter genera,
per qualche motivo, un ClutterEvent;
61
Sarebbe suciente impostare LIBGL_ALWAYS_INDIRECT=1 tra le variabile d'ambiente

79
Compositing manager

2. In virtù delle varie chiamate ad XSelect fatte dal compositore, il server invia alcuni
di questi eventi alla applicazione tramite un socket locale o remoto;

3. Il GSource in ascolto sul socket riconosce l'arrivo di un evento X da parte del server
o semplicemente la presenza di un ClutterEvent non gestito;

4. Se necessario, gli eventi vengono modicati; subito dopo, event_dispatch ne


demanda a Clutter la gestione;

5. Il ltro per gli eventi, installato dall'applicazione, intercetta tutti gli eventi di X
prima che siano eettivamente gestiti da Clutter;

6. All'interno del ltro vengono trattenuti tutti quelli eventi di cui il compositore
richiede una gestione personalizzata. I restanti sono nalmente ricevuti dai gestori
di default di Clutter.

2.7.2 Gestione degli eventi


Fino a questo punto sono state mostrate le funzioni di inizializzazione del compositore,
nonché l'architettura di redirezione degli eventi. A questo punto restano da analizzare le
funzioni di gestione personalizzata degli eventi, che poi, di fatto, costituiscono la logica
del compositore vero e proprio.
Andiamo ad analizzare in maggior dettaglio event_filter:
static ClutterX11FilterReturn
event_filter ( XEvent * ev , ClutterEvent * cev , gpointer unused )
{
switch ( ev - > type ) {
case CreateNotify :
window_created ( ev - > xcreatewindow . window );
return CLUTTER_X11_FILTER_REMOVE ;
default :
return CLUTTER_X11_FILTER_CONTINUE ;
}
}

Come detto nel paragrafo 2.6.4, la lettura del campo type permette di individuare
la particolare classe a cui appartiene un evento. L'implementazione è molto semplice
e prevede una risposta personalizzata ai soli eventi di tipo CreateNotify, ovvero quelli
eventi che segnalano l'avvenuta creazione di una nuova nestra da parte di una qualche
applicazione. Per tutti gli altri eventi viene restituito al chiamante un valore che indica
che l'evento deve essere propagato ai gestori di default di Clutter.
Il motivo per cui è suciente gestire solo gli eventi di creazione, emerge dall'analisi del
gestore personalizzato, window_created:
static void window_created ( Window win )
{
XWindowAttributes attr ;
ClutterActor * tex ;

80
2.7 Un esempio completo

if ( win == overlay )
return ;

XGetWindowAttributes ( dsp , win , & attr );


if ( attr . class == InputOnly )
return ;

tex = g_object_new ( texture_pixmap_type , " window " ,


win , " automatic - updates " , TRUE , NULL );

g_signal_connect ( tex , " notify :: mapped " ,


G_CALLBACK ( window_mapped_changed ) , NULL );
g_signal_connect ( tex , " notify :: window - x " ,
G_CALLBACK ( window_position_changed ) , NULL );
g_signal_connect ( tex , " notify :: window - y " ,
G_CALLBACK ( window_position_changed ) , NULL );

{
gint mapped , destroyed ;
g_object_get ( tex , " mapped " ,
& mapped , " destroyed " , & destroyed , NULL );
if ( mapped )
window_mapped_changed ( tex , NULL , NULL );
if ( destroyed )
window_destroyed ( tex , NULL , NULL )
}
}

All'inizio si indica che devono essere ignorati gli eventi relativi alla creazione del-
l'overlay e delle nestre di solo input, che non sono mai visibili. Le nestre d'interesse
sono tutte le rimanenti nestre di InputOutput.
La parte più rilevante del codice vede la creazione delle texture a partire dalle immagini
delle nestre redirette, texture che saranno poi utilizzate per il rendering sulla nestra
di overlay. Si nota, ancora una volta, come giovi alla semplicità del codice l'utilizzo del
paradigma dei GObject e dalla libreria di classi di Clutter62 .
Successivamente, ad alcuni dei segnali associati all'oggetto texture appena creato, ven-
gono collegate opportune funzioni di callback. È chiaro come i segnali per gli oggetti tex-
ture vengano attivati alla ricezione, sulle nestre dalle quali le texture sono tratte, dei cor-
rispondenti eventi di X: se le nestre vengono mappate, viene inviato un segnale mapped,
che provoca una chiamata a window_mapped_change; similmente un ridimensionamento
delle nestre porta a chiamare window_position_changed63 .
Di seguito viene presentato l'ultimo frammento di codice, con il quale viene mostrato
come sono state implementate le due suddette funzioni di callback :
static void window_position_changed
( ClutterActor * tex , GParamSpec * pasp , gpointer unused )
62
L'implementazione sarebbe potuta essere molto più complessa, pur svolgendo gli stessi compiti. Per
avere un'idea basta esaminare il codice di MTexturPixmapItem, la classe di MeeGo Compositor che
si occupa, tra le altre cose, del TFP (4.2.3).
63
Grazie ai segnali è alle connessione, nel ltro eventi sono stati considerati solamente i CreateNotify

81
Compositing manager

{
gint x , y , window_x , window_y ;
g_object_get ( tex , " x " , &x , " y " , &y ,
" window - x " , & window_x , " window - y " , & window_y , NULL );
if ( x != window_x || y != window_y )
clutter_actor_set_position ( tex , window_x , window_y );
}

static void window_mapped_changed


( ClutterActor * tex , GParamSpec * pspec , gpointer unused )
{
gint mapped ;
g_object_get ( tex , " mapped " , & mapped , NULL );
if ( mapped ) {
clutter_container_add_actor ( CLUTTER_CONTAINER ( stage ) , tex );
clutter_actor_show ( tex );
window_position_changed ( tex , NULL , NULL );
} else {
clutter_container_remove_actor ( CLUTTER_CONTAINER ( stage ) , tex );
}
}

A questo punto si è in possesso di tutti gli elementi per comprendere come vengano
visualizzate a schermo le immagini delle nestre trattate dal compositore. L'idea è quella
di utilizzare i normali meccanismi di creazione degli attori, di loro assegnazione allo
stage e di gestione delle loro proprietà (dimensione, visibilità, eccetera) per trattare le
operazioni di disegno.
In questo caso, gli attori sono le texture ricavate dai buer di redirezione e la scena nel
quale agiscono, lo stage, è glia della nestra di overlay e dunque un perfetto contesto di
rendering GLX.
Si noti come Clutter nasconda tutta la complessità associata alla creazione delle texture
ed alla loro visualizzazione a schermo grazie al paradigma actor-stage.
Se avviene una modica nel contenuto di una qualunque nestra, questo semplice
compositore non ha bisogno di far nulla. L'aggiornamento delle texture e gestito in
automatico da Clutter 64 , mentre l'aggiornamento dei buer (da cui le texture sono rica-
vate) è gestito automaticamente da Composite. Non bisogna dimenticare infatti, che in
precedenza era stata abilitata la redirezione automatica.
D'altra parte, non tutto è automatizzato o automatizzabile. Rimane da gestire man-
ualmente la risposta agli eventi di visibilità ed agli eventi che segnalano una cambiamento
nelle dimensioni delle nestre. Ricordandosi che gli eventi X riguardano modiche alle
sole nestre X11 sottostanti e non alle loro rappresentazioni in forma di texture, questa
gestione ammonta a tradurre il ridimensionamento della nestra originale in un ridi-
mensionamento dell'attore che la rappresenta, e a tradurre il mapping di una nestra
nell'entrata in scena dell'attore associato65 .

64
Clutter, a sua volta, utilizza la chiamata TFP di GLX, vedi 2.3.3.
65
Similmente, gli eventi di unmapping sono tradotti nell'uscita di scena dell'attore corrispondente.

82
2.7 Un esempio completo

Figura 2.12: Due diverse istanze di Xephyr in esecuzione all'interno del server X princi-
pale. Nell'istanza in basso a destra sono in esecuzione il compositore ed un
semplice processo xterm.

2.7.3 Note nali


Terminata l'analisi dettagliata del codice, vengono fornite alcune note pratiche per l'ef-
fettiva esecuzione del programma.
Il primo passo, naturalmente, è la compilazione. Una volta ottenuto il sorgente è
suciente digitare il seguente comando:
gcc `pkg - config -- cflags -- libs clutter - glx ` -o $NAME $SOURCE

L'espressione tra apici inversi permette di recuperare le opzioni del compilatore e del
linker necessarie per compilare un programma scritto con Clutter.
Per quanto riguarda il secondo ed ultimo passo, ovvero l'esecuzione del programma, è
bene notare che la via più comoda (in particolar modo per il debugging ) sarebbe quella di
eseguire il compositore all'interno del proprio server X principale. Normalmente questo
non sarebbe possibile, in quanto non ci possono essere attivi contemporaneamente due
window manager dierenti. A questo scopo può essere utile Xephyr, un server X completo,
ma molto leggero, in grado di renderizzare all'interno della nestra appartenente ad un
66
altro server . Addirittura Xephyr supporta le tre fondamentali estensioni Composite,

66
http://freedesktop.org/wiki/Software/Xephyr

83
Compositing manager

Damage e Xxes, anche se il server principale non ne è in grado.


Di seguito è presentato un semplice script, utilizzato per congurare Xephyr per l'avvio
del compositore:
# !/ bin / sh
# run - xephyr . sh

display = ':1 '

MCOOKIE = $ ( mcookie )
xauth add $ ( hostname )/ unix$display . $MCOOKIE
xauth add localhost / unix$display . $MCOOKIE
xinit " $@ " -- / usr / bin / Xephyr $display - host - cursor
xauth remove $ ( hostname )/ unix$display localhost / unix$display

exit 0

Una volta scelto un qualunque display, diverso da quello utilizzato dal server prin-
cipale, è necessario ottenere le opportune credenziali di autorizzazione. Allo scopo si
utilizza il comando xauth67 , che le ricava dialogando con il server principale. Il comando
xinit avvia un istanza Xephyr sul display prescelto. Nel farlo, manda in esecuzione,
come primi client, tutte le applicazioni che sono passate come parametro dello stesso
script68 . L'ultima riga rimuove, prima di uscire dal programma, le autorizzazioni usate
in precedenza.
Grazie a questo script, il compositore può essere lanciato semplicemente così:
./ run - xephyr $NAME

67
La funzione mcookie si limita a restituire un numero casuale adeguatamente formattato, necessario
per xauth.
68
La variabile $@ individua l'intera riga di parametri passati allo script in esecuzione.

84
Capitolo 3

MeeGo
MeeGo [Nokc] rappresenta la sintesi di due sistemi operativi open source, basati su Linux
e sviluppati da due grandi aziende multinazionali: Intel1 e Nokia. L'annuncio del progetto
è stato dato nel Febbraio 2010, in occasione del Mobile World Congress.
MeeGo è ospitato dalla Linux Foundation [Foua], un'organizzazione non-prot che
sostiene lo sviluppo del sistema operativo Linux2 .
Nokia contribuisce al progetto con il codice di Maemo 3 , sistema operativo embedded
per il mercato mobile. Intel, invece, porta in dote l'esperienza maturata con Moblin 4 ,
noto sistema operativo per netbook.
Il risultato complessivo è un sistema operativo innovativo e multi-piattaforma, indiriz-
zato ad un ampia gamma di dispositivi di nuova generazione: tablet, netbook e cellulari.
Il supporto per macchine così diverse è assicurato dalla presenza, di diverse interfacce
utente, ognuna ottimizzata per l'interazione con una tipologia diversa di dispositivo.
Il sotto-sistema graco di MeeGo è basato sull'X Windowing System. Inoltre, si an-
ticipa n da adesso che l'intera interfaccia utente e tutte le applicazioni principali sono
realizzate con Qt5 (1.4.5).
Nella prima sezione viene oerta una breve panoramica delle principali caratteristiche
del nuovo sistema operativo. In seguito è presentata una breve discussione del legame
tra MeeGo e l'Open Source (3.2), seguita da un'approfondita analisi architetturale (3.3).
Nell'ultima sezione (3.4) viene trattata in dettaglio il framework graco con la quale
sono sviluppate le applicazioni di interfaccia per MeeGo Touch, l'interfaccia per disposi-
tivi handset.

1
Le motivazioni di Intel vanno ricercate, secondo la stessa compagnia, nella mancanza di supporto al
processore Atom da parte dell'ultimo sistema operativo di casa Microsoft, Windows 7. [Bra]
2
Uno dei genitori di MeeGo, Moblin, era già ospite della Linux Foundation a partire dall'aprile 2009
[Sou09].
3
http://maemo.org/
4
http://moblin.org/
5
A questo proposito, si ricorda che, in conseguenza dell'acquisto di Trolltech, Qt è un prodotto Nokia.

85
MeeGo

3.1 Principali caratteristiche


Riassumendo, di seguito sono elencate le peculiarità di MeeGo [Had10, Mat10]:
• si propone di lavorare su una grande varietà di dispositivi: netbook, televisioni,
cellulari, automotive, eccetera. Tutte queste piattaforme condividono la compo-
nente di base del sistema operativo, nota come MeeGo core, e si dierenziano per
le modalità di interazione con l'utente;

• supporta sia processori ARM che x86; inoltre rappresenta uno dei primi sistemi
operativi ad utilizzare l'innovativo btrfs 6 come proprio le system principale;

• è una piattaforma aperta (vedi paragrafo 3.2), e questa sua natura viene evidenziata
dalla modalità scelta per il suo sviluppo;

• è basata su un kernel Linux e include le sue principali componenti software: server


graco X.org, D-Bus, GStreamer, Pulseaudio, eccetera. Questo semplica il com-
pito degli sviluppatori, che hanno a che fare con software noto e consolidato, e
favorisce la diusione di Linux;

• utilizza Qt come toolkit graco principale, il che ha notevoli conseguenze sulla


portabilità delle applicazioni. Gli sviluppatori possono riutilizzare il codice su pi-
attaforme software ed hardware molto diverse, grazie ad un API consistente. Anche
questo punto, dunque, concorre a facilitare il lavoro degli sviluppatori;

• mette a disposizione una piattaforma particolare, detta Web RunTime (WRT),


basata su Qt, grazie alla quale è possibile sviluppare applicazioni MeeGo con stru-
menti e tecniche dell'ambito web: HTML, CSS, Javascript ed Ajax. Spesso questo
approccio è più veloce e, a volte, più semplice della tradizionale programmazione
in C++ [Had10].

3.2 Rapporto con il mondo Open Source


MeeGo è sviluppato in maniera completamente pubblica, e l'intero codice sorgente è
liberamente scaricabili dalla rete tramite gitorious [Nokd], un portale web che ospita il
codice sorgente di numerosi progetti open-source. Gitorious è basato sul protocollo Git
per lo sviluppo concorrente del software7 . Nonostante le buone intenzioni, almeno in una
prima fase, il contributo da parte della comunità è stato abbastanza limitato8 .
Le cose sono iniziate a cambiare con l'avvento della versione 1.1 di MeeGo per dis-
positivi mobili. A partire da questa versione, infatti, è iniziato ucialmente lo sviluppo
pubblico del software [Nokc].
Naturalmente, la scelta di sviluppare MeeGo come un progetto aperto porta dei van-
taggi a Nokia ed Intel. Un primo aspetto potrebbe essere quello della manutenibilità del
6
https://btrfs.wiki.kernel.org/index.php/Main_Page
7
http://gitorious.org/about
8
http://wiki.meego.com/Contributing_to_MeeGo

86
3.3 Architettura

software nel lungo periodo: potendo contare sul supporto completo da parte della comu-
nità, Nokia e Intel potranno investire meno risorse nella fase di manutenzione software,
potendosi concentrare sull'innovazione e lo sviluppo. Un secondo aspetto da considerare
è che, così facendo, le due aziende avranno a disposizione un numero maggiore di pro-
grammatori esperti della propria architettura, potendo contare, oltre che su contributi
esterni signicativi, anche su nuovi potenziali collaboratori. Queste considerazioni sono
basate su quanto detto in [Som07].
La scelta di sviluppare MeeGo come un progetto aperto, porta dei vantaggi anche al
movimento del free software in generale, tra cui quello della diusione della cultura Linux
in nuovi ambiti e tra nuovi utenti. L'attendibilità di quest'aermazione è corroborata dal
fatto che Linux Foundation, consorzio open-source, ospiti il progetto MeeGo. Del resto
si può stimare, con ragionevole condenza, che nel prossimo futuro milioni di dispositivi,
di dierenti tipologie, utilizzeranno quello che è un sistema operativo basato su Linux.
La cosa non può che essere valutata positivamente da LF, dato che, come aermano in
scherzosi termini evangelici, il loro obiettivo principale è proprio diondere il verbo di
Linux [Foua].
Vantaggi vi sono anche dal punto di vista dei produttori di componentistica e degli
sviluppatori di web -application, che non sono vincolati dal dover sviluppare componen-
ti hardware e software per una sola specica piattaforma, o essere vessati da licenze
particolarmente restrittive.
Quanto detto non può che incidere positivamente, poi, sulla qualità del software stesso
e sul numero di applicazioni disponibili per la nuova piattaforma. Infatti, è noto da
tempo come il lavoro di sviluppo proprietario incorra nella duplicazione degli sforzi e
nella mancanza di feedback e di innesti da parte della comunità.

3.3 Architettura
Dire che MeeGo è l'unione di Moblin e Maemo in realtà è un'aermazione troppo generi-
ca. Con questa denizione diventa dicile, ad esempio, dire quali siano i tratti distintivi
o restrizioni a cui incorre una MeeGo application. In questa maniera si potrebbe ar-
rivare a considerare un'istanza di MeeGo anche un progetto come RdUX [Cyb]. RdUX
è basato su Moblin Core 2.0 ed è costruito a partire dalle librerie Qt, incorporando, così,
elementi anche di Maemo: allora perché non può essere denito una MeeGo application?
Per chiarire meglio questo problema ed altri più generali, è necessario esaminare più in
dettaglio l'architettura del sistema operativo.
Osservando il diagramma in gura 3.1 si nota immediatamente come l'architettura di
MeeGo sia schematizzabile in una struttura a strati (layered ). In un modello di questo
genere, uno strato X dipende dallo strato Y se e solo se Y è posizionato direttamente
sotto X. Per esempio lo strato d'interfaccia dipende da quello di Middleware, ma non
viceversa. Allo stesso modo, il livello di interfaccia non dipende direttamente dallo strato
di base.
Bisogna tenere bene a mente che lo schema presentato è solo uno schema concettuale:
andando ad osservare un'implementazione reale del sistema operativo sarà dicile iden-

87
MeeGo

Figura 3.1: Il diagramma architetturale di MeeGo. Si noti la separazione nei tre strati
Os Base, Middleware e Ux, e la presenza delle diverse implementazioni dello
strato superiore. Immagine tratta da [Nokc].

88
3.3 Architettura

ticare le singole componenti funzionali, quanto sarà invece facile separare tra di loro i
singoli software. Ciascuna applicazione può orire i servizi descritti da una o più com-
ponenti concettuali, o concorrere con altre per implementare un singolo servizio. Allo
stesso tempo è dicile immaginare che ogni strato possa orire a quello soprastante una
singola interfaccia unicata.
Si potrebbe immaginare dunque di non avere altro che le interfacce oerte dalle singole
componenti software, e molto probabilmente questo è vero per le interfacce oerta dal
primo verso il secondo livello. Tuttavia, se si va ad esaminare l'interfaccia tra il secondo e
terzo livello, le cose cambiano radicalmente. La maggior parte dei servizi infatti sono pre-
sentati all'esterno tramite il protocollo D-Bus, grazie al quale è presentata un'interfaccia
dalla semantica comune9 .
Nei paragra successivi vengono esaminati, una alla volta, i tre dierenti layer, utiliz-
zando un approccio bottom-up.

3.3.1 OS Base
La strato di base è basata principalmente su Moblin Core. Il sistema Intel, a sua volta,
è parzialmente ispirato alla distribuzione Linux Fedora [Int].
Lo strato è composto di due componenti principali. La prima coincide con un sotto-
livello chiamato Hardware Adaptation Software, che comprende tutte quelle componenti
che devono essere fornite dai produttori dell'hardware. In questa categoria ricadono
i driver di periferica ed in generale tutto quel software, patch del kernel comprese,
necessario per interfacciare l'hardware con il sistema operativo.
La seconda componente è il nucleo stesso del sistema operativo: nel caso di MeeGo è
un kernel Linux opportunamente congurato.
Nello strato di base sono compresi anche componenti come libc, udev o il bootloader.

3.3.2 Middleware
Lo strato di Middleware consta fondamentalmente di programmi di sistema, a cui è associ-
ata un'interfaccia comune. L'API, indipendente dall'hardware, permette di organizzare
le applicazioni in una serie di servizi d'uso generale10 . Nel seguito viene fornita una
breve panoramica dei servizi descritti dal modello; per maggiori informazioni è possibile
consultare il sito uciale [Nokc].

Visual Services: in questa sezione ricadono quelle librerie che si occupano del rendering
graco 2D (Cairo, QPainter ) e 3D (OpenGL, OpenGL ES ), nonché lo stesso X
9
D-Bus è un meccanismo che standardizza che unica la comunicazione inter-processo (IPC) e le chia-
mate a procedura remote (RPC); inoltre permette la comunicazione tra i processi di sistema e i
normali processi utente. La comunicazione avviene attraverso un'applicazione server centralizzata
(il bus ), ma è possibile anche la comunicazione diretta tra applicazioni. Per maggiori dettagli, vedi
dbus.freedesktop.org
10
In questo contesto, con il termine servizio si intende una componente software indipendente che perme-
tte al suo utilizzatore (utente o applicazione, locale o remoto) di svolgere un operazione ben denita.
A volte un servizio può operare contemporaneamente come client di altri servizi.

89
MeeGo

Window System. Non sono tuttavia compresi il desktop environment o il window


manager, che fanno parte, invece, dello strato superiore.

Communications: comprende il software per la gestione della connettività (ConnMan ),


che permette di interfacciarsi con un'ampia gamma di tecnologie tra cui: WiFi, 3G,
WiMax, e Bluetooth; è presente anche il software per la gestione del traco voce
e della telefonia in generale (oFono ).

Internet: comprende software per il render di contenuti web (LayoutEngine ), il supporto


web a run-time (WebKit ) e l'utilizzo di Web Service (libSocialWeb ).

Media Services: comprende software per il playback audio/video, lo streaming e in gen-


erale tutto il sottosistema per la gestione dei dati audio/video, compresi i vari codec
per la decodica dei ussi (GStreamer e relativi plugin, PulseAudio ).

Data Management: comprende i servizi per l'estrazione e la gestione dei meta-dati


(Tracker ). Sono inclusi anche servizi per il recupero di informazioni di stato del
sistema (ContextKit ), ed un gestore dei pacchetti, utile per la congurazione e la
rimozione del software, la gestione dipendenze, eccetera (PackageKit ).

Device Services: comprende una serie di servizi per la gestione dello stato del dispositivo,
inclusi servizi per la sicurezza per l'utente, lo scambio di dati, l'estrazione di dati
dai sensori, la sincronizzazione, il backup11 .

Personal Services: in quest'ultima categoria ricado quelle applicazioni che gestiscono i


dati dell'utente, inclusi quelli personali (si pensi ad esempio a calendari, agende,
lista contatti). Comprende anche il software che si occupa di gestire gli account
utente.

3.3.3 UX
Il layer della cosiddetta User Experience, o UX, è quello in cui avviene l'interazione con
l'utente. Per ogni segmento di mercato, e dunque per ogni dispositivo, è necessario fornire
una interfaccia utente dierente: questo discende non solo dalle particolari caratteristiche
siche del dispositivo12 , ma anche dalla composizione dell'utenza e dalla sua predilezione
verso un certo modello di interazione piuttosto che un altro.
La novità di MeeGo è quella di denire una serie di interfacce diverse ad uno stesso
insieme di servizi, forniti dallo strato di Middleware, a loro volta sono costruiti su una
base comune. Le release iniziali di MeeGo sono rivolte ai mercati dei netbook e dei
cosiddetti handheld (cellulari, tablet, eccetera), ma in futuro è previsto il rilascio di
ulteriori versioni con interfacce dedicate ad altri dispositivi.
11
Per questa voce e per la successiva, il sito uciale riporta pochi dettagli. Si può immaginare che siano
composti di applicazioni ad hoc, in fase di sviluppo.
12
Si pensi ad esempio come la presenzia di uno schermo touch o multi-touch possa radicalmente cambiare
le modalità di interazione.

90
3.3 Architettura

Figura 3.2: MeeGo Netbook UX. L'immagine mostra un eetto analogo a quello di Exposé
(descritto nel paragrafo 2.4.3). Le thumbnail in gura gli eettivi contenuti
delle nestre in esecuzione, e sono aggiornate dinamicamente grazie al cor-
rispondente compositing manager. L'interfaccia è completamente realizzata
con Clutter e GTK+.

Scendendo nel dettaglio, al momento sono state rilasciate o perlomeno sono state
annunciate le seguenti interfacce utente:

Netbook UX: discende direttamente dall'interfaccia di Moblin ed è basata principal-


mente sul binomio Clutter e GTK+. MeeGo Netbook UX è stata resa disponibile
già a Marzo 2010, e per il momento è molto più simile a Moblin che alle altre
interfacce per MeeGo (gura 3.2).

Handset UX: discende dall'interfaccia utente di Maemo 6, ed è basata su Qt. Le ver-


sioni rilasciate no a questo momento includono anche GTK+ e Clutter. La pri-
ma versione pubblica della MeeGo Handset UX è stata rilasciata il 30 Giugno
2010[Hal10].

Tablet UX: il suo sviluppo è ancora in uno stadio di pre-alpha. L'annuncio relativo a
questa nuova interfaccia utente, ed una sua breve dimostrazione su un tablet Intel,
è stato dato solo all'inizio di Giugno 2010, in occasione della COMPUTEX di
Taipei13 . Informazioni più dettagliate, come il toolkit graco utilizzato o i requisiti
hardware minimi, sono attualmente sconosciute.
13
La dimostrazione è reperibile su youtube, vedi ad esempio http://www.youtube.com/watch?v=
QqeeQd-YNL0.

91
MeeGo

Figura 3.3: Una tipica applicazione MeeGo Touch. Si noti la decorazione, fornita dal
window manager, e l'assenza di scrollbar o delle tipiche componenti di un
interfaccia desktop. Immagine tratta da http://thpmaemo.blogspot.com.

Il fatto che nell'interfaccia Mobile siano presenti anche GTK e Clutter non deve es-
sere sottovalutato. Sicuramente questo è un modo per gli sviluppatori per mantenere,
nel medio-lungo periodo, la retro-compatibilità con le applicazioni legacy scritte per le
precedenti versioni dei rispettivi sistemi operativi. Per Nokia, questo vuol dire continuare
a supportare le vecchie applicazioni per Maemo 5; per Intel le vecchie applicazioni per
Moblin. Inoltre, visto quanto detto in precedenza, il permanere del supporto a Clutter
permette per il momento l'interscambio di applicazioni tra l'interfaccia Netbook e quella
Mobile.
Nell'ambito del lavoro di tesi ci si è concentrati, alla luce dell'interesse di St, sull'in-
terfaccia Handheld, che in un futuro non troppo lontano sarà utilizzata insieme al loro
ultimo modello di board 14 . Per maggior informazioni, vedi la sezione 4.5.

3.4 MeeGo Touch UI


Quando è nata la collaborazione con Intel per lo sviluppo di MeeGo, Nokia stava già
sviluppando Maemo 6, nome in codice Harmattan. Nel concreto questo ha signicato
che il lavoro fatto su Harmattan è diventato la base dell'interfaccia MeeGo Handset UX,
ed in particolar modo di MeeGo Touch (MT).
MeeGo Touch è un framework, basato su Qt, orientato principalmente per la pro-
grammazione di interfacce grache [Nok10]. Così come lo stesso Qt, MeeGo Touch è
multi-piattaforma, nel senso che è in grado di operare su macchine dierenti. Il suo
target principale sono le macchine embedded dotate di interfaccia touch-screen.
14
http://wiki.meego.com/Devices/U8500

92
3.4 MeeGo Touch UI

Il legame tra MeeGo Touch e Qt è più stretto di quanto si possa pensare: Nokia prevede
che, in futuro, alcune delle funzionalità ora presenti in MeeGo Touch, migrino verso Qt
e dunque, in un certo senso, MT può essere visto come un ambiente di sperimentazione
per le nuove versioni di Qt.
Il framework è costituito da una serie di componenti, widget o di vere e proprie ap-
plicazioni, e da una libreria, libmeegotouch. Utilizzando questa libreria è possibile creare
nuove applicazioni grache basate sullo stile MeeGo Touch, in grado interagire con le
altre componenti del framework.
Lo stesso MeeGo Compositor, trattato nel capitolo 4, è distribuito insieme al framework
e, pur non facendone direttamente parte, utilizza alcune delle funzionalità della libreria
per implementare il suo motore di decorazione (4.3).
In particolare, MeeGo Touch è basato sul Graphics View Framework, di cui si era
discusso nella nella sezione1.5. In questo senso tutti gli oggetti manipolati dal framework
possono essere visti come item che si muovono all'interno di una scena, e sono visualizzati
tramite una o più viste.
A sua volta, poi, ogni singolo oggetto può essere decomposto in componenti più pic-
cole, e visto come una scena. Questa struttura ricorsiva porta alla realizzazione di un
interessante paradigma scene-view-item annidato. L'argomento è ripreso nel paragrafo
successivo.

3.4.1 Stile
Tutte le componenti del framework si adeguano ad un certo stile, o losoa di base. Rias-
sumendo, si può dire che in MeeGo Touch viene posta l'enfasi sulla diretta manipolazione
del contenuto. In una tipica applicazione MT è data più enfasi al contenuto che agli altri
elementi di interfaccia.
Lo stile tiene conto delle nalità embedded del framework, ed in MeeGo Touch non sono
presenti elementi tipici delle interfacce desktop: scrollbar, tab, dialoghi per la selezione
dei le e così via. Al contrario le applicazioni sono costituite da nestre o pagine multiple,
che non sono mai visibili contemporaneamente a schermo, e di una serie di oggetti che
permettono di passare da una pagina all'altra.
Ad ogni applicazione è associate un canvas, ovvero una scena, che si estende ben
oltre i limiti sici dello schermo, e che contiene tutto ciò che fa parte dell'applicazione.
L'operazione di cambiare pagina, dunque, è equivalente a quella di adottare un punto di
vista diverso sullo stesso insieme di oggetti.
Ogni oggetto della scena, poi, può essere manipolato, animato, reso trasparente, sposta-
to o ruotato, liberamente e con facilità, grazie alle apposite funzionalità fornite da lib-
meegotouch. L'eetto desiderato è quello di ottenere interfacce utente estremamente
uide.

93
MeeGo

Listato 3.1 MeeGo Touch UI, applicazione Hello World. Si notino le analogie con Qt
(listato 1.4.5), e la presenza delle pagine.

# include < MApplication >


# include < MApplicationWindow >
# include < MApplicationPage >
# include < MLabel >
int main ( int argc , char ** argv )
{
MApplication app ( argc , argv );
MApplicationWindow window ;
MApplicationPage page ;
page . setTitle ( " Hello World Page " );
page . setCentralWidget ( new MLabel ( " Hello World " ));
page . appear (& amp ; window );
window . show ();
return app . exec ();
}

3.4.2 Lavorare con MeeGo Touch


Tipicamente, MeeGo Touch e Qt sono utilizzati in maniera congiunte. Un'applicazione
reale potrebbe utilizzare MT per curare l'aspetto dell'interfaccia, e Qt per implementarne
la logica sottostante.
MeeGo Touch mette a disposizione un'API simile a quella di Qt, e la maggior parte
delle volte non è necessario essere consapevoli della presenza del canvas, o del paradigma
delle visuali e degli oggetti. Tuttavia, qualora fosse necessario lavorare a livello di canvas,
allo sviluppatore sono forniti tutti gli strumenti del caso.
Oltre ad una serie di widget pronti per l'uso, il framework mette a disposizione anche
alcune transizioni ed animazioni di base che possono essere personalizzate o usate diretta-
mente, ed ogni sorta di funzionalità per tentare di agevolare il lavoro del programmatore.
In aggiunta a questo, MeeGo Touch fornisce una serie di API espressamente immaginate
per i dispositivi mobile, che permettono di accedere, per esempio, a funzionalità come
quella del power management [Nok10].

94
Capitolo 4

MeeGo Compositor
Dopo aver descritto le principali caratteristiche e proprietà di un compositore, nonché
le possibili scelte architetturali che possono essere fatte per la sua implementazione,
in questa sezione viene descritto dettagliatamente il compositing window manager di
MeeGo.
Il particolare gestore è una componente essenziale dell'interfaccia graca di sistema,
ed è rilasciato come parte del MeeGo Touch Framework. Di consegeunza, MeeGo Com-
positor fa parte dell'interfaccia MeeGo per dispositivi mobili.
Per quanto detto in precedenza (paragrafo 3.3.3) MeeGo Handset è molto lontana dalle
esigenze di un sistema desktop, per la quale è a disposizione la MeeGo Netbook UX. La
conseguenza pratica, è che risulta parecchio dicile cercare di adattare il compositore per
una normale distribuzione di Linux per computer desktop. Il problema non sta solamente
nelle librerie utilizzate, o in alcune funzionalità presenti sono su dispositivi mobile. Il
problema principale sta proprio nel paradigma utilizzato (3.4).
Ad esempio, in una tipica sessione di MeeGo Handset viene visualizzata una sola nes-
tra applicativa per volta, anche se ne possono essere attive molte contemporaneamente.
Tale nestra è tipicamente a pieno schermo ed è circondata da una decorazione1 che
contiene i principali menù del sistema operativo, ed una serie di bottoni che permettono,
tra le altre cose, di passare alle altre nestre attive. Queste caratteristiche semplicano
notevolmente il lavoro del window manager e specialmente del compositore, come sarà
spiegato meglio in seguito.
Il lavoro di analisi è stato semplicato dalla lettura, tra le altre numerose fonti presenti
in bibliograa, anche del codice sorgente di xcompmgr2 , nonché dall'esperienza accumulata
con la stesura del piccolo compositore basato su Clutter, presentato nella sezione 2.7.
Tuttavia, rispetto all'esempio riportato in precedenza, nonché al codice di xcompmgr,
l'architettura studiata è parecchio più complessa, non fosse altro perché oltre che del-
la composizione, questo progetto realizza anche le complete funzionalità di un window
manager. Il codice del compositore è disponibile liberamente su gitorious [Nokb].
1
La decorazione a sua volta, per via delle tecniche di re-parenting, è costituita da una serie di altre
nestre.
2
http://freedesktop.org/xapps/release/xcompmgr-1.1.1.tar.gz

95
MeeGo Compositor

La prima sezione del capitolo è dedicata alla presentazione dell'architettura generale del
compositore(4.1). Le sezioni successivi sono dedicate descrizione delle classi principali del
compositore vero e proprio (4.2) e del decoratore (4.3), nonchè della funzione principale
del progetto 4.4.
L'ultima sezione si distacca dal tema generale del capitolo, è prova a studiare le prob-
lematiche connesse all'implementazione del compositore su di una macchina particolare.

4.1 Architettura
MeeGo Compositor è un compositing window manager. Questo vuol dire che fa le veci
di un completo window manager e, in più, è in grado di arricchire l'esperienza utente
tramite l'utilizzo delle tecniche di composizione. Come la maggior parte dei window
manager, mcomposer adotta le tecnica del re-parenting per gestire la decorazione.
La sua implementazione, a questo proposito, interessante. Infatti, le funzionalità di
decorazione sono svolte esternamente, in un'applicazione separata con la quale l'eseguibile
principale, il compositore, dialoga tramite invocazioni di metodi remoti (RMI).
L'utilizzo di RMI, peraltro in una versione personalizzata, è probabilmente una scelta
temporanea, propedeutica all'adozione di un sistema basato su D-Bus. Questa ipotesi
nasce osservando l'architettura di MeeGo, nella quale il dialogo tra processi viene gestito
da un apposito servizio di livello middleware, ContextKit (3.3.2).
La scelta di separare il decoratore dal compositore, è stata fatto nella direzione di
separare la logica applicativa dal codice che si occupa dell'aspetto3 .
L'implementazione del compositore utilizza principalmente Qt, la libreria con la quale
sono realizzate la maggior parte delle applicazioni d'interfaccia di MeeGo Handset. Quan-
do è necessario agire ad un più basso livello, vengono eettuate direttamente chiamate ad
Xlib. Per la costruzione della nestra di decorazione viene utilizzata anche libmeegotouch.
Per concludere, si nota che MeeGo Compositor si pone l'obiettivo di una piena aderenza
alle speciche ICCCM ed EWMH (2.1.4). Tuttavia, al momento, la compliance è solo
parziale e non tutte le proprietà sono interpretate come dovrebbero. I programmatori
hanno incluso all'interno dei sorgenti un le, EWMH_COMPLIANCE, che riporta lo stato di
adozione delle speciche.

4.1.1 Scene-Item-View
L'architettura di mcomposer è basata sull'utilizzo del framework Qt Graphics View, de-
scritto nella sezione (1.5). Fondamentale, dunque, risulta il paradigma scene-item-view.
In questo caso gli oggetti trattati sono proprio le pixmap associate ai buer di redirezione
incapsulati all'interno della classe MTexturePixmapItem. Gli item sono gestiti all'interno
di una struttura astratta, la scena, che nel caso del compositore è re-implementata in
MCompositeScene. Per la vista, non è necessario utilizzare nessuna classe personalizza-
ta, ma si può tranquillamente utilizzare un'istanza di QGraphicsView. A completare il
quadro è la viewport, contenuto all'interno della vista, che costituisce il contesto reale
3
In un certo senso può essere vista come una riproposizione della separazione tra meccanismi e policy.

96
4.1 Architettura

User

Interacts

Vista
(QGraphicsView)

ViewPort
(QGLWidget)

Scena
Render

(MCompositeScene)

Item Item Item

Finestre
(MTexturePixmapItem)
Figura 4.1: L'architettura di MeeGo Compositor è basata sul paradigma scene-item-view.
Si noti come l'utente interagisca solo sulla vista, mentre gli oggetti in realtà
fanno parte della scena. Le modiche della scena si riettono direttamente
sulla vista; viceversa è possibile interagire con la vista per modicare la scena.
Si noti che la scena è solo un modello astratto: anché siano visibili all'u-
tente, gli oggetti devono eettuare il rendering. Le operazioni di rendering
avvengono sulla viewport, incorporata a sua volta nella vista.

97
MeeGo Compositor

sul quale viene fatto il rendering delle pixmap. Dato che come motore di rendering
viene utilizzato OpenGL, la scelta più adeguata è utilizzare come viewport un'istanza di
QGLWidget che, fra l'altro, è associata alla nestra di overlay restituita da Composite.
Con questo sistema si dota l'overlay delle caratteristiche necessarie per far sì che diventi
un contesto di rendering GL.
L'utente, ovviamente, può interagire solo con la vista, mentre la gestione degli item,
delle loro collisioni e dei loro spostamenti viene lasciata a Qt. L'unica preoccupazione è
quella di assicurarsi che tutti gli eventi così generati siano ricevuti dalla classe in cui è
implementata la logica del compositore, che deve poi tradurli nelle azioni necessarie per
gestire le nestre X11 sottostanti.
Con questo sistema, le modica alla vista che, si badi bene, riguardano solo un concetto
astratto come gli item, vengono tradotte in modiche alla scena e da qui ai reali oggetti
sottostanti. Viceversa, una modica delle nestre, dovuta alle operazioni di window
management o all'applicazione degli eetti graci, viene tradotta dal compositore in
modiche dello stato degli oggetti corrispondenti. Gli item, a loro volta, noticati da
Qt della modica del loro contenuto, inviano i corrispondenti comandi di rendering alla
viewport. Inne, la modica è recepita dall'utente attraverso la vista, aggiornata grazie
ai meccanismi interni di QGraphicsView.
La gura 4.1 riassume le interazioni appena descritte.

4.1.2 Possibili ottimizzazioni


In questa sezione vengono descritte alcune possibili ottimizzazioni, sia di tipo architet-
turale che implementativo.

• Un grosso difetto dell'attuale implementazione del compositore, è quello di ignorare


gli eventi di danneggiamento, e produrre un ridisegno completo dell'intero scher-
mo ad ogni modica. Questo comportamento, altamente insuciente, deve essere
risolto il prima possibile.

• Per quanto riguarda il rendering, la modalità di fallback software è estremamente


ineciente e completamente da rivedere. Inoltre non esiste la possibilità di utiliz-
zare un motore di rendering dierente da OpenGL (ES). Ad esempio, si potrebbe
introdurre un motore basato su XRender. Si potrebbe, poi, introdurre un sistema
che permetta all'utente di modicare a run-time il motore di rendering utilizzato.

• Una possibile ottimizzazione potrebbe essere quella di modicare l'architettura


con la quale sono implementati gli eetti graci, da monolitica a basata sui plug-
in. Nella paragrafo 2.4.1 sono elencati vantaggi e svantaggi di un'architettura di
questo genere. Inoltre il numero di eetti graci a disposizione per il momento è
abbastanza limitato.

• MeeGo Composer è implementato al di sopra di X11; tuttavia sarebbe possibile


un'architettura alternativa che utilizzi direttamente il frame-buer. Infatti, in al-
cuni casi l'infrastruttura di X richiede un certo overhead che potrebbe risultare

98
4.2 Compositore: classi principali

ingiusticato. A questo scopo potrebbe essere utilizzata l'architettura Qt Embed-


ded che permette di far girare le applicazioni Qt senza che ciò richiede l'intervento
di X. Tuttavia, questa strada risulta impraticabile, in quanto comporterebbe una
rivisitazione della struttura interna di MeeGo.

• Manca la possibilità di sfruttare hardware apposito. Ad esempio, la U8500 di


St è dotato di una componente, nota come blitter, che permette di accelerare le
operazioni sulle pixmap. L'attuale implementazione di MeeGo Composer non tiene
minimamente conto di queste possibilità (vedi sezione 4.5).

Nota bene: tutte le considerazioni sono basate sulla


versione del compositore datata 30 Giugno 2010.

4.2 Compositore: classi principali


Le classi fondamentali che compongono il ramo principale del progetto sono:

• MCompositeScene (4.2.1)

• MCompositeWindow (4.2.2)

• MTexturePixmapItem (4.2.3)

• MCompositeManager (4.2.5)

A queste vanno aggiunte una serie di altre classi di minore rilevanza, sulle quali sarà
comunque fornito qualche dettaglio.
Per seguire meglio la discussione, in gura 4.2 è riportato il diagramma delle classi del
compositore e del decoratore, completo di cardinalità delle relazioni, e modellato tramite
lo standard UML [Som07].

4.2.1 MCompositeScene
MCompositeScene rappresenta la scena in cui si muovono gli oggetti di tipo MTex-
turePixmapItem trattati dal compositing manager. In altre parole è il contenitore delle
immagini delle nestre. Questa classe si occupa dunque di catturare gli eventi di input
generati dall'utente e ad inviarli verso gli oggetti appropriati. Inoltre gestisce lo sposta-
mento delle pixmap e in generale compie tutte quelle operazioni che una scena Graphics
View compie in relazione agli oggetti che contiene(1.5.1).
Sempre secondo il paradigma Graphics View, il contenuto della scena viene presen-
tato all'utente attraverso una vista (1.5.2), istanziata all'interno del funzione principale

99
Figura 4.2: Il diagramma delle classi di MeeGo Compositor. Per la modellazione è uti-
lizzato UML. Le classi tratteggiate sono implementate esternamente. Le
relazioni tratteggiate non sono standard, ma il loro signicato dovrebbe
connect 1
MRmiServer MRmiClient MCompAtoms
use
outside
1
MDeviceState
MAbastractDecorator MDecoratorFrame
1 1
1 MDecorator 1 MCompositeManager 1

manage
manage
manage

100
* 1

risultare abbastanza intuitivo.


* decorate 1
MDecoratorFrame MCompositeWindow MCompositeScene
*
view
1
* MSimpleWindowFrame QGraphicsView
MeeGo Compositor

1
MTexturePixmapItem MTexturePixmapItem render
(EGL) (GLX) QGLWidget
render
4.2 Compositore: classi principali

(main). Il rendering vero e proprio viene eseguito solo per quelli oggetti che ricadono
all'interno della visuale, usando come contesto di rendering la corrispondente viewport.
Ogni qualvolta che Qt riceve un evento di danneggiamento o comunque determina che
una nestra dev'essere ridisegnata, il gestore corrispondente chiama la funzione update
dell'oggetto o degli oggetti modicati. A loro volta gli oggetti si limitano a chiamare sem-
pre una stessa funzione di MCompositeScene, drawItems. Tra i parametri sono elencati
gli oggetti che devono essere ridisegnati, e il corpo della funzione ne chiama le corrispon-
denti funzioni di disegno, ovvero i metodi paint() di ciascuna delle MTexturePixmapItem
coinvolte.
Oltre alla funzione di disegno appena citata e ad un semplice error handler 4 , sono
altre due le funzioni principali che vale la pena citare5 .
La prima è prepareRoot(), analoga alla funzione init_root presentata per il Clutter
compositor descritto nella sezione 2.7. Questa funzione ha un compito fondamentale,
ovvero quello di selezionare diverse classi di eventi, tra quelli recapitati a tutte le nestre
e sotto-nestre X11 associate al display. A dierenza di init_root, non è in questa
funzione che viene richiesta la redirezione dell'output. Sarà fatto in seguito, nestra
per nestra, e in modalità manuale, nel metodo redirectWindows della classe principale
(4.2.5).
La seconda funzione presentata è setupOverlay, simile alla input_passthrough pre-
sentata nel paragrafo 2.7.1. La chiamata accetta due parametri: l'identicatore win di
una nestra, e un QRect geom. L'eetto della chiamata è quello di rendere invisibile
agli eventi l'area di win che non appartiene alla geom . Tramite una ag particolare è
possibile chiamare la funzione per annullare gli eetti di una sua precedente chiamata.
La funzione è utilizzata in fase di inizializzazione, impostando il QRect a zero, in modo
da rendere completamente trasparente l'overlay e sua glia, la nestra in cui avviene
eettivamente il rendering6 . Si vuole, infatti, che gli eventi di input siano generati dalle
nestre sottostanti per poi essere gestiti dal compositore, in virtù della selezione compiute
in prepareRoot.

4.2.2 MCompositeWindow
MCompositeWindow è la classe base che descrive i composited window item, ovvero è la
classe con cui vengono rappresentate tutte le nestre controllate dal compositing manager.
Infatti, sono istanze di questa classe tutte le tipologie di nestre: sia quelle originaria-
mente create dai client, prima che siano trattate dal WM, sia le nestra già trattate ed
opportunamente decorate, sia, inne, la stessa nestra di decorazione.
La struttura della classe è ovviamente legata alla vera natura degli oggetti trattati dal
compositing window manager che, come dovrebbe essere chiaro, non sono direttamente
le nestre, ma le loro rappresentazioni sotto forma di pixmap. MCompositeWindow ered-
ita da QGraphicsItem, e quindi ogni pixmap non è altro che un oggetto all'interno del
4
L'error handler è in grado di gestire il caso in cui sia in esecuzione un altro window manager sullo
stesso display, o di dettagliare meglio gli errori di bad match.
5
Vedi le considerazioni generali riportate nel paragrafo 4.1.
6
Per maggiori dettagli sulla nestra di overlay, è possibile consultare il paragrafo 2.2.3.

101
MeeGo Compositor

paradigma Graphics View, e gode di tutte le proprietà di base descritte nel paragrafo
1.5.3.
Tuttavia, MCompositeWindow è una classe astratta, e quindi non può essere istanziata
direttamente. L'idea è che tutti i metodi di disegno debbano essere implementati all'in-
terno di sotto-classi7 , in modo che possano coesistere implementazioni che utilizzano
diversi motori di rendering.
Al momento è disponibile una sola sottoclassin modo che e, MTexturePixmapItem,
anche se, esistendone due versioni dierenti, di fatto le sottoclassi sono due. Maggiori
dettagli sul rendering sono forniti nel paragrafo 4.2.3.
Ogni istanza della classe contiene un puntatore ad un MCompWindowAnimator, nel
quale è contenuta l'implementazione di tutti gli eetti graci realizzati dal compositore,
che così sono integrati nel codice e, quindi, non sfruttano l'architettura a plugin descritta
nel paragrafo 2.4.1.
Gli eetti sono richiamati in reazione alla riduzione ad icona delle nestre, la dis-
truzione delle stesse ed anche la visualizzazione delle thumbnail una volta che la nes-
tra è stata ridotta ad icona. MCompositeWindow memorizza lo stato della nestra, il
cui aggiornamento è demandato ad MCompositeManager, e chiama i metodi opportuni
dell'animatore.
Riassumendo, le scelte architetturali appena descritte portano sicuramente ad alcuni
vantaggi:

• la classe racchiude al suo interno un oggetto Window di X11, rendendone più facile
la manipolazione ed isolando la complessità della comunicazione con il server X per
quanto possibile;

• la classe è di uso abbastanza generale, e permette di descrivere oggetti simili ma al


contempo con dierenze rilevanti, orendo all'esterno la medesima interfaccia;

• le funzionalità di disegno sono disgiunte dal resto, aumentando la modularità del


codice e dunque la sua manutenibilità.

4.2.3 MTexturePixmapItem
Come detto nel paragrafo precedente, MTexturePixmapItem è l'unica sottoclasse di MCom-
positeWindow, ed ha lo scopo di implementarne i metodi astratti di disegno(4.2.2). Ovvi-
amente, grazie all'eredità, le istanze di MTexturePixmapItem sono anch'esse degli item
Graphics View.
La sua responsabilità principale è quella di fornire al compositing manager una serie
di chiamate che:

• permettano di trasformare il contenuto dei buer in un qualche altro oggetto più


facilmente manipolabile, come possono esserlo delle texture OpenGL;

• permettano di disegnare la nestra utilizzando il motore di rendering appropriato.


7
updateWindowPixmap e funzioni collegate sono metodi puramente virtuali.

102
4.2 Compositore: classi principali

Nei sorgenti sono disponibili due implementazioni: una basata su GLX ed una basata
su EGL (rispettivamente mtexturepixmapitem_glx.h e mtexturepixmapitem_egl.h).
L'analisi si è concentrata sull'implementazione GLX, quella più utilizzata e studiata
in quanto per quasi tutto il tempo si è lavorato su una macchina desktop. Questo non
dovrebbe essere un problema, per altro, in quanto gran parte delle considerazioni possono
essere applicate anche al back-end EGL.
Purtroppo la scelta tra le due diverse implementazioni avviene a compile-time, quando
vengono risolti i corrispondenti #ifdef. La conseguenza è che l'architettura, in realtà,
non è molto essibile né ovviamente modulare: dopo la fase di compilazione, il motore
di rendering non può essere più modicato.
Tornando a MTexturePixmapItem, quando un evento X11, dovuto ad una qualche ap-
plicazione esterna o allo stesso compositore, provoca una modica alle nestre visibili o ad
una loro parte, si attiva un meccanismo che porta a chiamare i metodi updateWindowPixmap
di alcune o tutte le nestre visibili. L'implementazione di questi metodi è basata sulle
tecniche di texture from pixmap discusse nel paragrafo 2.3.3.
Se, per un qualche motivo, non è disponibile la funzionalità TFP, nel codice è presente
una implementazione di fallback (custom TFP) realizzata completamente via software.
La modalità di fallback, tuttavia, risulta completamente inutilizzabile, salvo che per il
debugging. Del resto TFP è una componente critica, un collo di bottiglia del quale non
ci si può permettere un'implementazione non ottimizzata8 .
Una volta ottenuta, la texture è applicata ad un rettangolo delle medesime dimensioni
e della medesima posizione della nestra X11 a partire dalla quale la texture è stata
creata. Tutti questi oggetti sono renderizzati all'interno del contesto OpenGL indicato
in fase di inizializzazione.
Nell'implementazione disponibile, il contesto è lo stesso per tutte le texture e coincide
con la nestra di overlay. A sua volta, questa coincide con la viewport (4.1.1).
Le principali funzioni che costituiscono l'interfaccia pubblica della classe sono:

updateWindowPixmap: Si assicura che la texture corrispondente rietta il contenuto della


pixmap a cui è associata; se è il caso schedula un re-paint dell'oggetto. Si deve
assicurare che il driver graco gestisca correttamente l'operazione: in caso contrario
viene attivata l'implementazione di fallback di cui si è parlato precedentemente. I
due parametri dovrebbero servire ad implementare update selettivi delle sole aree
eettivamente da aggiornare; per il momento, tuttavia, tale comportamento non è
stato implementato.

saveBackingStore: Crea una Pixmap utilizzando NameFromPixmap, salvando al suo in-


terno il contenuto del buer su cui è ridiretto l'output delle nestre. Se è impostato
l'unico parametro renew (e ciò avviene quando la nestra è stata appena mappata
o ridimensionata) questo fa sì che venga aggiornato il contenuto del buer.

Le operazioni di rendering sono eettuate usando le chiamate standard di OpenGL (ES),


sfruttando rispettivamente GLX e EGL per l'interfacciamento con il sottosistema X11.
8
In particolare l'implementazione fornita è lungi dall'essere ottimizzata, ed è alquanto macchinosa.

103
MeeGo Compositor

Non sono usate, se non per alcune trasformazioni di coordinate, le funzionalità della
classe QPainter.
La classe, inoltre prevede una chiamata, enableDirectFBRendering, che permette di
disabilitare la redirezione. Naturalmente, dev'essere cura del compositore assicurarsi che,
se anche una sola top-level window non sfrutta la composizione, non lo facciano neanche
tutte le altre.
Riassumendo, ogni istanza della classe e quindi ogni nestra può essere in uno di tre
stati: non-ridiretta, ridiretta con rendering OpenGL, ridiretta con rendering software.

4.2.4 MDeviceState
Si tratta di una classe molto semplice che gestisce la comunicazione con l'hardware,
reperendo le informazioni di interesse per MCompositeManager. Utilizza il protocollo
D-Bus per la comunicazione inter-processo. Per il momento si limita a riconoscere se vi
è una chiamata telefonica in corso, o se lo schermo del device è spento (magari a causa di
una prolungata inattività da parte dell'utente) ed a trasmettere le informazioni di stato
tramite adeguati segnali Qt.
Data la stretta dipendenza di queste funzioni dal dispositivo, per poter compilare
l'applicazione su desktop è necessario modicare buona parte dell'implementazione di
questa classe. Il metodo più semplice prevede che le funzioni si limitino a restituire valori
predeniti (sempre true o sempre false), senza cercare mai di richiamare nessun servizio
esterno.

4.2.5 MCompositeManager
MCompositeManager eredita da QApplication, e quindi rappresenta la classe principale
del progetto. Il suo compito è quello di occuparsi tanto della gestione di base delle
nestre, quanto della composizione vera e propria. Al suo interno vengono mantenute
numerose strutture dati che tengono conto delle risorse manipolate. Le associazioni fra le
nestre e le corrispondenti istanze di MCompositeWindow sono gestite tramite un array
associativo, un QHash, di nome windows. Si noti che questa non è l'unica lista con le
quali sono gestite le nestre, vi sono liste diverse che tengono conto, ad esempio, delle
sole nestre non decorate, o delle sole nestre già mappate a schermo9 .
Quando è avvertito della creazione di una nestra, il compositore si attiva per in-
capsularla all'interno di un oggetto MTexturePixmapItem che viene poi aggiunto alla
scena. In questa maniera vengono gestite, con la stessa interfaccia, tutte le nestre: le
normali nestra applicative (con o senza decorazione), il frame di decorazione, eccetera.
Sono previste delle eccezioni per alcune nestra particolari, come la nestra di rendering.
L'implementazione è contenuta all'interno della funzione bindWindow.
L'implementazione reale è incapsulata all'interno della classe MCompositeManager-
Private, mentre la classe MCompositeManager vera e propria è utilizzata per fornire
un'interfaccia pubblica consistente.
9
rispettivamente framed_windows e windows_as_mapped

104
4.2 Compositore: classi principali

MCompAtoms è una piccola classe di utilità, presenti nello stesso le sorgente, utiliz-
zata per la gestione degli atomi di X11, fondamentali per le comunicazioni con le ap-
plicazioni, e per l'implementazione dei protocolli ICCCM e EWMH (vedi 1.3.2 e 2.1.4).
MCompAtoms permette di nascondere parte della complessità associata alla manipo-
lazione degli atomi, e fornisce a tutto il programma un metodo semplice per leggere ed
impostare proprietà sulle nestre.
La logica del compositore è basata sulla programmazione ad eventi. Come descritto nel
paragrafo 2.6.4, la strategia è quella di re-implementare QApplication::x11EventFilter,
in modo da avere la possibilità di ltrare tutti gli eventi diretti al compositore prima che
possano essere gestiti da Qt10 .
Il ltro è impostato in fase di inizializzazione e, in virtù delle chiamate di selezione11 ,
è in grado di intercettare la totalità degli eventi generati. A questo punto, gran parte
del codice di MCompositeManager è dedicato all'implementazione dei gestori person-
alizzati, richiamati in ricezione degli eventi di mapping /unmapping, danneggiamento,
ridimensionamento o spostamento di una nestra, modica di una qualche proprietà,
eccetera.
Uno dei metodi fondamentali della classe è redirectWindows, chiamato in fase di
inizializzazione, che richiede al server l'elenco completo di tutte le nestre e ne redireziona,
una per volta, l'output nei buer fuori schermo grazie a XCompositeRedirectWindow.
Un'altra funzione molto importante è checkStacking, strettamente legata ai compiti
di un puro window manager. Come dice il nome, l'eetto della funzione è quello di
controllare l'ordinamento attribuito alle nestre e, se necessario, modicarlo. Nel farlo
tiene conto delle convenzioni descritte da EWMH, e di alcune regole personalizzate.
L'ordine è una proprietà fondamentale, che determina quale nestra sia in primo piano,
e quali invece siano sullo sfondo, ed è fondamentale per il rendering.
Per concludere, si nota come il compositore sia in grado di funzionare anche come
semplice window manager. L'interfaccia comprende due slot Qt, enableCompositing e
disableCompositing, che permettono di passare da una modalità all'altra. Per farlo,
l'implementazione permette di modicare dinamicamente le modalità con le quale viene
fatto il rendering di tutti gli MTexturePixmapItem. Nel caso che, per un qualunque
motivo, non sia possibile redirigere l'output di una nestra top-level, è necessario, natu-
ralmente, che la composizione sia disattivata per tutto il sistema.

Esempio: Window Mapping


Supponiamo che il client decida di creare una nestra top-level, ovvero una nestra
glia direttamente della radice. Il compositore riceverà ed intercetterà la richiesta di
mapping dell'applicazione all'interno della sua funzione x11EventFilter che, a sua volta,
ne demanderà la gestione alla chiamata MapRequestEvent.
10
A dierenza di quanto visto nel paragrafo 2.7.2, si sta utilizzando un vero paradigma di pro-
grammazione ad oggetti. Pertanto, i gestori personalizzati sono implementati come metodi di
classe.
11
Si sta parlando delle chiamate che impostano la maschera di selezione degli eventi sulle nestre. Vedi
la descrizione di MCompositeScene.

105
MeeGo Compositor

Il codice di questa chiamata distingue tra nestre che richiedono la decorazione e


quelle che invece non la richiedono. Nel secondo caso, invece che il vettore windows,
viene utilizzato framed_window. In entrambi i casi, l'esecuzione si conclude con una
chiamata ad XMapWindow che mappa eettivamente la nestra. Questo evento genererà
a sua volta una MapNotify. In maniera analoga a quanto avvenuto in precedenza, la
notica sarà intercettata e gestito dal compositore all'interno del metodo mapEvent.
All'interno della chiamata vengono gestiti separatamente i casi delle framed window.
Inoltre si distingue se la nestra era già stata trattata dal compositore in precedenza
(sostanzialmente se ne è presente una pixmap). In caso aermativo si ci limita sem-
plicemente a fare un refresh della pixmap stessa, in caso contrario bisogna registrare la
nestra con il compositore, ed associarla ad un oggetto MCompositeWindow.

4.3 Decoratore: classi principali


4.3.1 MRMIClient e MRMIServer
MRMIClient ed MRMIServer fanno parte della semplice libreria libdecorator, compresa
nei sorgenti del decoratore. Sono classi che implementano una versione personalizzata
del paradigma di chiamata a procedura remota, utile per la comunicazione tra oggetti di
applicazioni diverse, scavalcando protocolli esterni come D-Bus 12 .
Per poter utilizzare le chiamate remote, è necessario che, presi due oggetti che vogliono
comunicare l'uno con l'altro, il primo comprenda un'istanza della versione client di MR-
MI, l'altro un'istanza della versione server. Entrambe devono passare al costruttore una
stessa chiave, che permetta di identicare univocamente il nome del server. L'unico pre-
requisito è che la classe che fa da server erediti da QObject (la classe più generale in Qt)
e che i metodi da invocare remotamente siano degli slot pubblici.
L'implementazione sfrutta il noto paradigma signal-slot di Qt, e dunque le funzionalità
messe a disposizione dal Meta Object Compiler (vedi paragrafo 1.4.5).
Al momento, le funzionalità presenti sono abbastanza limitate: infatti, ogni istanza
del server può supportare l'invocazione remota su un solo oggetto; inoltre sono possibili
solo comunicazioni tra processi che risiedono sulla stessa macchina, e non su macchine
remote.
Il metodo più importante è invoke, la cui rma risiede in MRMIClient, e grazie al quale
sono svolte le invocazioni remote. Di questo metodo sono presenti numerose versioni in
overloading, in modo da adattarsi a funzioni con diverso numero di argomenti. Questi,
però non possono essere di qualunque tipo: viene richiesto, infatti, che gli argomenti siano
tra quelli supportati da QVariant. Il che, a dir la verità, non è una grossa limitazione13 .

12
Considerazione tratta dai commenti al codice sorgente.
13
QVariant agisce come un unione dei più comuni tipi di dato usati in Qt. Ogni istanza di QVariant
contiene in un dato momento un singolo valore, di un singolo tipo [Tro09c].

106
4.3 Decoratore: classi principali

4.3.2 MAbstractDecorator e MDecorator


Anche MAbstractDecorator fa parte di libdecorator. È una classe astratta che fornisce
una una serie di funzionalità comuni, utili per costruire un decoratore compatibile con
mcomposer. In realtà, esiste una sua sola sottoclasse, MDecorator, che rappresenta il
decoratore eettivamente utilizzato.
Il compito principale di MAbstractDecorator è quello di gestire la comunicazione con
il compositore, e nello specico con MDecoratorFrame. L'implementazione eettiva dei
metodi è fatta invece in MDecorator.
Il compito principale del decoratore, come ci si potrebbe aspettare, è quello di ef-
fettuare il re-parenting tra la nestra indicata dal compositore e un opportuna istanza
di MDecoratorWindow. In ogni dato momento, in virtù delle caratteristiche di MeeGo
Touch, sarà necessario decorare una sola nestra: pertanto esiste una sola istanza di
MDecoratorWindow, creata in fase di inizializzazione.

4.3.3 MDecoratorWindow
MDecoratorWindow è la classe che rappresenta la nestra di decorazione, ovvero la cor-
nice che il window manager pone attorno alle nestre che ne hanno bisogno. Quando
il compositore comunica al decoratore l'identicativo della nestra da decorare, il com-
positore si assume la responsabilità di ridimensionare la nestra gestita ed eettuare il
re-parenting con la nestra di decorazione. In questa maniera viene realizzata l'illusione
di una sola nestra organica, mentre in realtà si stanno osservando due nestre distinte,
l'una glia dell'altra.
Il frame di decorazione ha la caratteristica di essere grande quanto l'intero schermo, il
che è diretta conseguenza del fatto che può essere presenta a schermo una sola nestra
per volta.
L'implementazione è basata sulla libreria MeeGo Touch, in modo da assicurare alla
decorazione un aspetto graco consistente con quello delle applicazioni14 .
Appoggiarsi al MeeGo Touch Framework consente anche di non dover scrivere codice
particolare per creare e gestire le informazioni contenute nelle diverse barre di stato e
icone che compongono la decorazione.

4.3.4 MSimpleWindowFrame
Come detto, la decorazione si ada ad un applicazione distinta dal compositore vero e
proprio. Cosa succede, però, se tale applicazione in un dato momento non è disponi-
bile? La soluzione, è quella di utilizzare la semplice classe MSimpleWindowFrame, la
cui implementazione è contenuta nei sorgenti del compositore. Questa classe denisce
una semplice cornice realizzata come una normale interfaccia utente Qt, senza utilizzare
le funzionalità del MeeGo Touch Framework. Per eliminare completamente eventuali
14
Tanto le applicazioni, quanto MDecoratorWindow sia appoggiano ad un oggetto esterno, un gestore
distinto e centralizzato dei temi graci. Il gestore è implementato sotto forma di un demone di
sistema, distribuito in un pacchetto diverso rispetto a quello in cui è contenuto il compositore.

107
MeeGo Compositor

dipendenze esterne, all'interno dell'eseguibile principale15 sono anche incluse due sem-
plici immagini di fallback da associare alle icone di chiusura e riduzione ad icona della
nestra.

4.3.5 MDecoratorFrame
Nonostante faccia tecnicamente parte dei sorgenti di mcomposer, in realtà è più naturale
discuterne in questa sezione. Questa classe, infatti, è quella che si occupa di gestire
l'interazione fra il compositore ed il decoratore. È una classe singleton, ovvero una classe
della quale in un dato momento esiste al massimo un'istanza. Questa classe implementa
la componente lato client della procedura di invocazioni remote, mentre il lato server,
come visto in precedenza, viene implementato da MDecorator.
Il compositore si limita ad indicare al MDecoratorFrame due soli parametri: il primo
è l'identicatore associato ad una nestra di decorazione16 , il secondo è l'identicativo
della nestra che, di volta in volta, ha bisogno di far decorare. L'associazione di questo
secondo parametro viene ripetuta ogni qual volta una nuova nestra viene mappata a
schermo, o comunque diviene visibile quando prima non lo era.

4.4 Funzione principale


L'esecuzione del compositore ha inizio dal codice della funzione principale del programma,
main, contenuta nell'omonimo le sorgente.
Nella funzione principale vengono create le istanze delle classe principali e ne vengono
chiamate le funzioni di inizializzazione. L'ultima chiamata, inne, permette di saltare al-
l'interno del ciclo eventi principale di Qt. Arrivati a questo punto, la successiva evoluzione
del programma è totalmente guidata dagli eventi.
I tre, fondamentali, oggetti che vengono creati nel main sono:

app l'istanza di MCompositeManager, che rappresenta il cuore dell'applicazione;


scene un istanza di MCompositeScene, creata e inizializzata dal costruttore del compos-
itore, in cui si risiedono gli item, ovvero le pixmap delle nestre;

view la QGraphicsView (non è una sottoclasse personalizzata, è suciente la classe base),


attraverso la quale vengono visualizzati gli oggetti associati alla scena.

La maggior parte delle righe di codice del main vengono utilizzate per congurare adeguata-
mente la view, che alla ne risulta avere le seguenti proprietà:

• nessun update: il disegno è temporaneamente disabilitato per gestire correttamente


le inizializzazioni. Una volta concluse gli update verranno riabilitati, in modalità
15
Allo scopo viene utilizzato il paradigma Qt per la gestione delle risorse.
16
La cornice descritta da MDecoratorWindow, di cui, come si è visto, esiste una sola istanza.

108
4.5 Un caso reale: composizione sulla U8500

manuale. Gli update automatici sono disabilitati in modo da avere il controllo


completo su tempi e modi del disegno17 ;

• nessuno sfondo, nessun pennello attivo, nessuna ombra, nessuna scrollbar;

• dimensione ssa con massimo e minimo coincidenti con le dimensioni del desktop;

• override redirect attivo (viene ignorata dal WM);

• la funzione drawItems della classe MCompositeScene è impostata quale suo metodo


di disegno.

Sostanzialmente l'eetto complessivo è quello di trasformare view in un mero conteni-


tore.Ad essa viene associata la viewport, un QGLWidget opportunamente creato, che
rappresenta il contesto OpenGL sul quale operano le funzioni di disegno.
Le ultime quattro righe del sorgente sono particolarmente interessanti:

view . show ();


app . prepareEvents ();
app . redirectWindows ();
return app . exec ();

Con la prima riga si rende visibile la vista, e quindi la corrispondente viewport (che
ne è glia)18 . Con la seconda si preparano le strutture dati del compositing manager,
mentre con la terza riga si da poi inizio alle redirezione delle nestre. Se questa va a
buon ne, risulterà abilitata la composizione.
Con l'ultima riga viene si entra nel ciclo eventi principale di Qt e inizia l'esecuzione a
regime del compositore.

4.5 Un caso reale: composizione sulla U8500


In questa sezione, l'ultima del documento, si provano a descrivere le problematiche con-
nesse all'implementazione di un compositore su di una particolare macchina embedded,
la scheda U8500 di St-Ericsson [Gal10]. Per riferimento, si immaginerà di avere a che fare
con il sistema operativo MeeGo, e con un'implementazione basata sul MeeGo Compositor
descritto in questo capitolo.
Naturalmente, nè MeeGo Compositor, nè l'architettura graca di MeeGo sono ottimiz-
zate per lavorare su una macchina specica, e del resto non potrebbe essere altrimen-
ti. Si discute, dunque, delle possibili ottimizzazioni da introdurre per sfruttare questa
particolare congurazione hardware.

109
MeeGo Compositor

Figura 4.3: L'architettura graca della U8500. FOSS sta per Free and Open Source
Software. Immagine tratta da [Gal10]

4.5.1 Architettura graca della U8500


In questo paragrafo viene fornita una breve descrizione dell'architettura graca della
U8500. La descrizione fa riferimento alla gura 4.3.
Innanzitutto si può notare come il diagramma sia assolutamente generale: l'unica
assunzione è quella di lavorare in ambiente Linux. Pertanto, si può tentare di contestu-
alizzarlo, immaginando di lavorare in un sistema operativo MeeGo Touch .
19

Nello strato applicativo, di conseguenza, risulterebbe automaticamente incluso tutto


il software dello strato di interfaccia di MeeGo. Si noti la particolare rilevanza data
al compositing manager, che potrebbe essere proprio il MeeGo Compositor descritto in
questo capitolo. Per quanto riguarda le restanti componenti presentate in spazio utente,
si può immaginare siano comprese all'interno dello strato Middleware dell'architettura
di MeeGo, ed in particolare nel gruppo di servizi Media e Visual Services (gura 3.1,
sezione 3.3). Si noti la presenza di un server graco compatibile con il protocollo X11.

17
A questo proposito si noti che l'unico oggetto che potrà ricevere direttamente gli update è
la viewport. Questo comportamento è ottenuto ridenendo la funzione paint() all'interno di
MTexturePixmapItem.
18
Questo farà sì che Qt generi un MapEvent una volta iniziata la gestione degli eventi.
19
Nel seguito sono ignorate tutte quelle componenti, come GStreamer e hardware audio, irrilevanti in
relazione all'architettura di composizione.

110
4.5 Un caso reale: composizione sulla U8500

In basso sono presentate le componenti hardware presenti sulla board. Innazitut-


to si nota la presenza di una GPU (una Mali ARM), il cui driver mette a dispo-
sizione un'interfaccia OpenGL ES. Un generico compositore, come detto nel paragrafo
2.3.3, può sfruttare OpenGL come proprio motore di rendering: sia direttamente, che
indirettamente attraverso l'X server.
In alternativa, un compositore potrebbe utilizzare XRender (2.3.2), passando così at-
traverso il server X. XRender a sua volta può scrivere direttamente sul frame-buer,
identicato dal kernel con il descrittore /dev/fb. Questo è ciò che avviene quando si uti-
lizza una modalità di rendering non accelerata. In alternativa, il server può dialogare con
OpenGL, accelerando così le sue funzionalità di rendering. A questo proposito, si noti in
gura la presenza dell'architettura EXA, descritta brevemente nel paragrafo 2.3.2.2.
Al momento, MeeGo Compositor non sfrutta le potenzialità di motori di rendering al-
ternativi: tuttavia questo non toglie che sarebbe possibile implementare un compositore,
compatibile con MeeGo, e alternativo a quello presentato in questo capitolo. Assumiamo
comunque che questo non sia necessario, e che la modalità di rendering OpenGL diretto
utilizzata da MeeGo Compositor possa fornire delle prestazioni ottime.
Fino a questo punto, non è stato detto niente di nuovo, nè sembra necessario modicare
radicalmente l'implementazione del compositore descritta no a questo momento.
Cosa succede, tuttavia, se una particolare macchina embedded, mette a disposizione
dell'hardware specico20 , in grado di accelerare signicativamente le operazioni di com-
posizione? Nel caso della U8500 si tratta di una componente particolare, detta blitter o
B2R2.
Il blitter è in grado di svolgere, in maniera estremamente eciente, alcune semplici
operazioni su pixmap, come rotazioni e riscalamenti. Soprattutto, però, il blitter com-
prende il concetto di trasparenza ed è in grado di svolgere operazioni di blending, che,
come si è visto, sono basilari per implementare una qualsiasi tecnica di composizione
(2.3.1). Inoltre è in grado di copiare rapidamente in memoria video le pixmap sulle quali
ha nito di operare21 .
Ovviamente, al blitter sono associate anche delle limitazioni. Inanzitutto è dotato di
un interfaccia di basso livello; in secondo luogo non comprende il concetto di memoria vir-
tuale ed è in grado di accedere solo alla memoria sica della macchina. Tuttavia, di fronte
ai possibili guadagni prestazionali, si vorrebbe tentare di sfruttare le sue caratteristiche
nell'implementazione di un compositore.

4.5.2 Ottimizzare la composizione


La discussione è basata su un caso particolare, quello del B2R2 implementato nella U8500.
Tuttavia, le considerazioni sono assolutamente generali, e possono essere applicate ogni
qual volta sia necessario ottimizzare la composizione su una macchina embedded che
mette a disposizione delle componenti hardware particolari.
20
Naturalmente, si assume che i driver della nuova componente siano forniti dal produttore dell'hardware,
in questo caso St-Ericsson.
21
Queste considerazioni sono tratte dal data sheet fornitomi da St. Tale documento non è liberamente
accessibile al pubblico.

111
MeeGo Compositor

Fondamentalmente, sono possibili due approcci diversi per ottimizzare la composizione:

• Il primo porterebbe a realizzare un'implementazione custom del compositore, in


grado di programmare direttamente l'hardware, senza dover passare dal server di
X.

• Il secondo consisterebbe nel modicare l'implementazione del server X, in modo


che quest'ultimo possa avere conoscenza della presenza del blitter.

Il primo approccio, purtroppo, presenta un difetto fatale. Operando in questa maniera,


infatti, si rinuncerebbe al supporto da parte del server e quindi le operazioni di ren-
dering dovrebbero essere svolte direttamente dal compositore. Purtroppo, questo com-
porterebbe di dover copiare tutte le pixmap, memorizzate lato server, nello spazio di
memoria del client.
Appare dunque necessario sfruttare il secondo approccio, che permetterebbe di lasciare
invariata l'implementazione del compositore. Si potrebbe, ad esempio, modicare l'im-
plementazione di XRender, facendo sì che le chiamate di composizione vengano tradotte
in chiamate di un'opportuna libreria d'interfacciamento con il driver del blitter.
Questa soluzione è illustrata in gura 4.3, come esemplicato dalla presenza della
componente B2R2 Library immediatamente al di sotto di un'implementazione modicata
del server X.org.
Nelle ipotesi iniziali, in cui si immaginava di utilizzare MeeGo quale sistema operativo,
una soluzione del genere porterebbe a dover modicare lo strato OS Base di MeeGo e,
parzialmente, anche la sua componente Middleware.
Nonostante non si possano fornire dati precisi, le prime indicazioni sperimentali fornite
da St sembrano indicare che l'utilizzo di una soluzione del genere sia conveniente dal punto
di vista prestazionale.

112
Capitolo 5

Conclusioni
Allo scopo di fornire una caratterizzazione completa dei compositing window manager,
sono stati arontati numerosi argomenti.
Inizialmente si è partiti con una lunga disamina dell'X Window System e dei relativi
protocolli, per arrivare poi a discutere dei meccanisimi alla base della composizione e dei
possibili modelli di rendering. I discorsi iniziali sui toolkit graci principali e su Xlib
sono stati fondamentali per poter parlare con sicurezza delle possibili scelte implementa-
tive. Sono stati mostrati alcuni esempi relativi ai più comuni compositing manager per
sistemi desktop ed embedded, no a poter presentare un progetto completo, sebbene solo
esemplicativo.
La discussione è stata concretizzata negli ultimi due capitoli, che hanno mostrato come
le combinazioni hardware-software di un particolare sistema operativo e di un particolare
sistema hardware inuenzino le scelte architetturali ed implementative di un compositing
manager.
Si è visto, inoltre, come l'evoluzione dei compositori e delle tecniche di composizione ab-
bia provocato l'introduzione di una serie di innovazioni in diversi campi dell'informatica,
specialmente nel campo della graca. Nel corso della trattazione poi, sono state introdotti
alcuni concetti di valenza generale, come il fondamentale paradigma scene-item-view.
La convinzione è che la scelta di concentrare il lavoro sui fondamenti teorici sia stata
quella vincente. In questa maniera, infatti, il lettore può facilmente comprendere da solo
i meccanismi alla base di un qualunque compositore e, se ne avesse bisogno, essere in
grado di ad implementarne uno da sé.
Nella sezione 4.5, l'ultima della tesi, viene fornito quello che può essere lo spunto per
un lavoro successivo. Si è visto infatti come il passaggio da un punto di vista puramente
teorico, come quello adottato nel corso di tutto il lavoro di tesi, ad un punto di vista
pratico, introduca tutta una serie di problematiche ulteriori, più speciche ma non per
questo meno interessanti.
Le nalità di questi studi ulteriori sarebbero quelle di concentrarsi sull'ottimizzazione
delle tecniche di composizione, con particolare riferimento all'hardware sottostante, e al
parallelismo insito nella composizione.

113
Conclusioni

A questo proposito, possono essere delineati alcuni dei principali problemi aperti:

• Attualmente non è possibile costruire un'architettura che permetta di sfruttare un


qualunque hardware ottimizzato per la composizione. Al contrario è necessario
ottimizzare manualmente in ogni singolo caso specico.

• In relazione al problema precedente, non è noto se sarebbe possibile sfruttare par-


allelamente componenti hardware diverse. A questo proposito si vorrebbe sco-
prire se eettivamente esiste un limite al parallelismo che può essere sfruttato dai
compositing window manager.

• Inne, nel problema più importante, e più generale, ci si chiede se esista un'ar-
chitettura software che permetta di realizzare la composizione su una congurazione
hardware arbitraria.

A tutte queste domande, di notevole interesse, si vorrebbe cercare di dare una risposta.
Si capisce, però, che senza la basi teoriche delineate in questa relazione, non sarebbe
possibile l'analisi approfondita che ci si propone di iniziare.

114
Bibliograa

Libri e articoli
[BS08] Jasmin Blanchette and Mark Summereld. C++ GUI Programming with Qt4.
Prentice Hall, 2nd edition, February 2008.

[CC09] Alex Crits-Christoph. Innovative interfaces with clutter. Linux Journal,


(186):5, 2009.

[Fon09] Arnaud Fontaine. Writing an X Compositing Manager. Master's thesis, Oxford


Brookes University, 2009.

[Gal10] Andrea Gallo. 3g and multimedia platform  linux activities on u8500.


Technical report, St-Ericsson, 2010.

[Get04] James Gettys. The (Re)Architecture of the X Window System. In Proceedings


of the Linux Symposium, pages 227238, July 2004.

[GKM90] James Gettys, Philip L. Karlton, and Scott McGregor. The X Window System,
version 11. Software: Practice and Experience Supplement, 20:S35S67, 1990.

[Had10] Ibrahim Haddad. Introduction to the MeeGo project. Technical report, The
Linux Foundation, 2010.

[Har99] Eric Harlow. Developing Linux Applications: With Gtk+ and Gdk. New Riders
Publishing, 1999.

[LK06] Andreas Larsson and Alexander Klinstrom. Visual Eect Managment in


a Mobile User Interface. Master's thesis, Umea University, Department of
Coumputer Science, April 2006.

[Mol07] Daniel Molkentin. The book of Qt 4 - The art of building Qt Applications.


No Starch Press, 2007.

[MS01] Bart Massey and Jamey Sharp. Xcb: An x protocol c binding. In Proceedings
of the 2001 XFree86 Technical Conference, October 2001.

[Nye92] Adrian Nye. Xlib programming manual: for version 11 of the X Window
System.O'Reilly & Associates, Inc., 1992.

115
Bibliograa

[Pac00] Keith Packard. A new rendering model for X. In Proceedings of the annual
conference on USENIX Annual Technical Conference, pages 5353, Berkeley,
CA, USA, 2000. USENIX Association.

[PD84] Thomas Porter and Tom Du. Compositing digital images. Computer
Graphics, 20(3):253259, 1984.

[SG86] Robert W. Scheifer and Jim Gettys. The X window system. ACM Transactions
on Graphics, (2):79109, April 1986.

[SG96] Robert W. Scheier and James Gettys. X Window System: Core and extension
protocols, X version 11.
Digital Press, 1996.

[Som07] Ian Sommerville. Ingegneria del software. Pearson, 2007.

[The07] Johan Thelin. Foundations of Qt Development. Apress, 2007.

Siti1
[App08] Apple. Mac OS X technology overview: Graphics and multimedia technolo-
gies.
http://developer.apple.com/documentation/MacOSX/Conceptual/OSX_
Technology_Overview/GraphicsTechnologies/GraphicsTechnologies.
html, 2008.

[Ber07] Joseph Bergin. Building graphical user interfaces with the MVC pattern.
http://pclc.pace.edu/~bergin/mvc/mvcgui.html, 2007. Pace University.

[Blo08] Qt Labs Blog. Widgets enter the third dimension: WolfenQt.


http://labs.qt.nokia.com/2008/12/02/widgets-enter-the-third-
dimension-wolfenqt/, 2008.

[Blo09] Qt Labs Blog. Qt graphics and performance  an overview.


http://labs.qt.nokia.com/2009/12/16/qt-graphics-and-performance-
an-overview/, 2009.

[Bra] Mary Branscombe. Intel: MeeGo exists because microsoft let us down.
http://www.techradar.com/news/computing-components/processors/
intel-meego-exists-because-microsoft-let-us-down-684665.

[Cum08] Murray Cumming. Programming with clutter.


http://www.openismus.com/documents/clutter_tutorial/0.6/docs/
tutorial/html/index.html, 2008.
1
Tutti i collegamenti a siti esterni risultano accessibili alla data 10 ottobre 2010

116
Bibliograa

[Cyb] CyberCom. Rdux - revolutionary device user experience.


http://www.cybercomchannel.com/rdux%E2%84%A2-%E2%80%93-
revolutionary-device-user-experience.
[Eic04] Egbert Eich. Xaa howto.
http://cgit.freedesktop.org/xorg/xserver/plain/hw/xfree86/xaa/
XAA.HOWTO, 2004.
[Fed08a] Fedora. Architectures for a compositing manager.
http://fedoraproject.org/wiki/RenderingProject/CMArchitecture,
May 2008.
[Fed08b] Fedora. Rendering project  AIGLX.
http://fedoraproject.org/wiki/RenderingProject/aiglx, May 2008.
[Foua] The Linux Foundation. Linux Foundation home page.
http://www.linuxfoundation.org/about.
[Foub] X.Org Foundation. Ocial home page.
http://www.x.org/wiki/.
[Gro06] X Desktop Group. Extended window manager hints.
http://standards.freedesktop.org/wm-spec/wm-spec-latest.html,
Septempber 2006.
[Hal10] Valtteri Halla. MeeGo Handset project day 1 is here.
http://meego.com/community/blogs/valhalla/2010/meego-handset-
project-day-1-here, 2010.
[Hog07a] Kristian Hogsberg. Compiz and Fedora.
http://hoegsberg.blogspot.com/2007/08/compiz-and-fedora.html,
2007.
[Hog07b] Kristian Hogsberg. Redirected Direct Rendering.
http://hoegsberg.blogspot.com/2007/08/redirected-direct-
rendering.html, 2007.
[Hognd] Frederik Hoglund. Composite tutorial.
http://ktown.kde.org/~fredrik/composite_howto.html, n/d.
[Int] Intel. Intel switches form ubuntu to fedora.
http://www.h-online.com/open/news/item/Intel-switches-from-
Ubuntu-to-Fedora-for-Mobile-Linux-736599.html.
[Jaa10] Ari Jaaksi. Personal blog. random notes, mostly about my work.
http://jaaksi.blogspot.com/, May 2010.
[Lee05] Jon Leech. OpenGL graphics with the X window system (version 1.4).
http://www.opengl.org/documentation/specs/glx/glx1.4.pdf, 2005.

117
Bibliograa

[Lib10a] GNOME Documentation Library. GObject reference manual, versione 2.26.0.


http://library.gnome.org/devel/gobject/2.26/, 2010.
[Lib10b] GNOME Documentation Library. Gtk+ reference manual.
http://library.gnome.org/devel/gtk/, 2010.
[Mat10] Marko Mattila. Meego thoughts  zchydem's blog.
http://zchydem.enume.net/2010/02/26/meego-thoughts/, 2010.
[Mic] MSDN Library Microsoft. Desktop Window Manager overview.
http://msdn.microsoft.com/en-us/library/aa969540%28VS.85%29.aspx.
[Noka] Nokia. Maemo 6 - Harmattan framework source tree.
http://qt.gitorious.org/maemo-6-ui-framework.
[Nokb] Nokia. Mcompositor source tree.
http://meego.gitorious.org/meegotouch/meegotouch-compositor.
[Nokc] Nokia. MeeGo home page.
http://meego.com/.
[Nokd] Nokia. MeeGo source tree.
http://meego.gitorious.org.
[Noke] Nokia. Qt homepage.
http://qt.nokia.com/products/.
[Nok10] Nokia. Introduction to meeGo Touch.
http://apidocs.meego.com/mtf/introduction.html, 2010.
[PA07] Keith Packard and Eric Anholt. The X Damage Extension protocol denition.
http://webcvs.freedesktop.org/xlibs/DamageExt/protocol?revision=
1.3, January 2007. FreeDesktop.org.
[Pac06] Keith Packard. The X Fixes Extension protocol denition.
http://webcvs.freedesktop.org/xlibs/FixesExt/protocol, December
2006. FreeDesktop.org.

[Pac09] Keith Packard. The X Rendering Extension protocol denition.


http://webcvs.freedesktop.org/xlibs/Render/protocol?revision=1.9,
July 2009. FreeDesktop.org.

[PJ07] Keith Packard and Deron Johnson. The X Composite Extension protocol
denition.
http://webcvs.freedesktop.org/xlibs/CompositeExt/protocol?
revision=1.8, July 2007. FreeDesktop.org.
[Proa] Matchbox Project. Matchbox documentation manual.
http://matchbox-project.org/documentation/manual/wm.html.

118
[Prob] The GTK Project. What is gtk?  ocial home page.
http://www.gtk.org/.
[Sir05] John Siracusa. OS X 10.4 tiger  Quartz Compositor.
http://arstechnica.com/apple/reviews/2005/04/macosx-10-4.ars/13,
2005.

[Sou09] Imad Sousou. Linux Foundation to host Moblin project.


http://moblin.org/about-moblin/linux-foundation-host-moblin-
project, April 2009.
[Spi10] Sam Spilsbury. Compiz 0.9.0 is released!
http://lists.freedesktop.org/archives/compiz/2010-July/003429.
html, 2010. Freedestkop.org.
[Sta93] X Consortium Standard. Inter-Client Communication Conventions Manual.
http://www.x.org/docs/ICCCM/icccm.pdf, December 1993.
[Tro09a] Trolltech. The Graphics View Framework  version 4.6.
http://doc.trolltech.com/4.6/graphicsview.html, 2009.
[Tro09b] Trolltech. Qt designer manual  version 4.6.
http://doc.trolltech.com/designer-manual.html, 2009.
[Tro09c] Trolltech. Qt online reference  version 4.6.
http://doc.qt.nokia.com/4.6/index.html, 2009.
[Tro09d] Trolltech. Qt paint system  version 4.6.
http://doc.trolltech.com/4.6/paintsystem.html, 2009.
[Wik10a] Wikipedia. Alpha compositing.
http://en.wikipedia.org/wiki/Alpha_compositing, 2010.
[Wik10b] Wikipedia. Comparison of window managers.
http://en.wikipedia.org/wiki/Comparison_of_window_managers, 2010.
[Wik10c] Wikipedia. Compositing window manager.
http://en.wikipedia.org/wiki/compositing_window_manager, 2010.
[Wik10d] Wikipedia. X window manager.
http://en.wikipedia.org/wiki/X_window_manager, 2010.
[Wik10e] Wikipedia. X window system core protocol.
http://en.wikipedia.org/wiki/X_Window_System_core_protocol, 2010.
[Win08] Wingolog. So you want to build a compositor.
http://wingolog.org/archives/2008/07/26/so-you-want-to-build-a-
compositor, 2008.
Ringraziamenti

Innanzitutto desidero ringraziare il mio relatore, il professor Ferretti, per l'aiuto, l'as-
sistenza e soprattutto la pazienza. Chi mi conosce, sa che con me ce ne vuole davvero
tanta. Del resto, non è da tutti perdonare la mia pigrizia! Grazie anche al professore
Rubini, un vero mago dei computer.

Un grazie va anche alla St, ed in particolare all'ingegner Gallo, che ha saputo stimolare
il mio interesse, aiutandomi ad entrare nel vivo dell'argomento.

In secondo luogo, desidero ringraziare gli alunni, gli ex-alunni, il personale e il Rettore
del Collegio Ghislieri, nessuno escluso. Questi cinque anni a Pavia non sono stati solo
rose e ori, ma una cosa è certa. Dai primi timidi passi da matricola, ai due anni da
rappresentante degli alunni, dagli scherzoni subiti a quelli organizzati, dalle uscite in
compagnia, alle domeniche da solo: l'esperienza del Collegio la ricorderò per tutta la
vita.

Un ringraziamento speciale va a due amici straordinari che ho conosciuto in Collegio. Che


mi sono stati sempre vicino, che mi hanno sopportato, che mi hanno insultato quando ho
esagerato, che mi hanno incoraggiato nei momenti di dicoltà, che hanno ascoltato le mie
interminabili lamentele, e che hanno nerdato con me no a tarda notte, anche quando io
crollavo dal sonno. Con loro ho parlato in una lingua incomprensibile, ho riso di tutto,
ho litigato su tutto e poi fatto subito la pace, ho discusso di politica, storia, religione e
ogni altro argomento senza dogmatismi e senza preconcetti. Anche se qualche volta mi
sono preso un bel calcione nel di dietro, e mi è stato distrutto più di un paravento, non
posso esimermi: Durex, Imba, grazie di tutto!

Un grazie speciale se lo merita anche Turbi, l'insostituibile quarta componente della


Combriccola. Mi mancano un sacco le sue battute che, di politically correct, non avevano
nemmeno l'ombra.

121
Bibliograa

Un ringraziamento a Chiara, una buona amica ed un'ottima collega e all'insostituibile


Gad che sa tutto per denizione. Alle fake della mansarda, a Margherita e allo schiocco
delle dita, ad entrambe le Giulie e a quelle lontante serate passate a suonare il pianoforte.
Agli ehr di Bove e alle emozioni del conclave, alle fpeatine di Fry e al suo temibile fucile,
alla passione di Sacco, agli urletti di Stero e ai suoi improbabili travestimenti, alle skill
culinarie del Capozzino ed allo sfortunato Julien, nei cui lm è stato bello tornare a
recitare. Un grazie poi alle new entry Gelmini-Berneri-ChenChen che hanno portato una
ventata d'aria fresca in Bruni 2 .

Ringrazio tutte le matricole per l'enorme numero di prelibate tonno e cipolle che mi hanno
fornito, e che, ahimé non mi forniranno più. Menzione particolare, a questo proposito,
per il recordman Pamela. Ringrazio tutti quelli che hanno sempre creduto nella goliardia,
e tutti i nottambuli del Collegio. E, perché no, ringrazio anche tutti i miei kulisti, quelli
più spessi e quelli che mi hanno salvato in più di un'occasione. Ringrazio, poi, tutti quelli
che ho dimenticato di ringraziare perchè so che non se la prenderanno troppo con me!

Sarei ingiusto, a dir poco, se non ringraziassi i miei amici di sempre. Ci siamo visti
pochissimo in questi anni, rispetto a quanto eravamo abituati. Ma ogni volta che l'ab-
biamo fatto, sembrava che il tempo si fosse fermato. Grazie a Roberto, Dave, Elio,
Gianluigi, Caputo; a Roberto e Giovanna e a tutti i biscegliesi in trasferta; ai compagni
della mai dimenticata V B e a tutti quelli che mi ricordano sempre dei bei vecchi tempi.

Inne, il ringraziamento più grande di tutti va alla mia famiglia. A mia sorella a cui
auguro il successo che merita, a miei zii e alle mie nonne, ai miei cugini grandi e piccoli
e a chi, purtroppo, non c'è più.

Ma in particolar modo ringrazio i miei genitori, a cui, per la seconda volta, dedico la mia
tesi. Senza di loro, probabilmente non sarei nemmeno qui.

Grazie. Senza di voi, nulla sarebbe stato possibile.

2
Grazie anche a Spock, cui sono dedicate tutte le note a piè di pagina, specialmente quelle superue.

122