\input macroXinfo
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\stampalicenza
\titolo Glib Object System

\sezione Introduzione

La \!Glib Object System! (pi\`u comunemente chiamata \!GObject!) \`e
una libreria rilasciata sotto \!LGPL! the fornisce la possibilit\`a di
usare in un ambiente C puro una programmazione ad oggetti, senza
contare la facilit\`a di creare ``binding'' tramite altri linguaggi
(quali il python per esempio).

La difficolt\`a di creare a runtime una libreria che permetta di
definire un comportamento \!object oriented! (OO) riguarda 
i metodi relativi alla classe da implementare: in un
sistema OO ogni classe contiene delle propriet\`a (variabili) e dei
metodi (funzioni) per agire su queste (o per alcuni metodi particolari
chiamati costruttori e distruttori di creare e rispettivamente
distruggere l'oggetto); la prima cosa che uno potrebbe fare per
implementare un simile sistema in C, potrebbe essere tramite una
\iniziacodice struct\finecodice\ usando delle normali variabili per le
propriet\`a e dei puntatori a funzione per i metodi, cos\`i facendo si
ha il problema ulteriore di spreco dello spazio in memoria: ogni
istanza della classe (cio\'e ogni ``creazione'' di un elemento di
questo tipo) porta alla riallocazione in memoria a delle funzioni che
fanno le medesime cose rispetto a quello di un qualunque altro suo
``simile''! Per questo si usa una \iniziacodice struct\finecodice\
aggiuntiva in cui viene instanziata una cosidetta \!vtable!, una
tabella cio\`e dei metodi che gli oggetti condividono: questa
struttura verr\`a chiamata la \!class structure! per differenziarla
dalla \!instance structure! che rappresenta l'oggetto vero e proprio.

Solo una ultima parola sui nomi che ci si ritrova a dare agli oggetti
creati: oltre al nome standard da affibiare all'oggetto \`e necessario
prefissarlo con un nome che identifichi il cosidetto \!namespace! che
lo distingua da progetti con nomi di classi analoghi: ecco spiegata la
caratteristica delle funzioni GTK in cui esiste sempre il prefisso
\iniziacodice gtk_\finecodice.

\sezione Implementazione

Per implementare una classe tramite GObject sono necessarie almeno due
strutture: una relativa alla classe vera e propria, l'altra relativa
alla \!istanza! della classe: grazie alla mia eccessiva fantasia
chiamiamo la classe \iniziacodice object\finecodice\ ed il namespace
sar\`a \iniziacodice some\finecodice:
\sourcecode
typedef struct _SomeObject SomeObject;
typedef struct _SomeObjectClass SomeObjectClass;
|endsourcecode
per iniziare questo tutorial implementer\`o un semplice oggetto con una
propriet\`a chiamata \iniziacodice property\finecodice\ ed un metodo
(pubblico) per ottenere il valore di questa propriet\`a.
\sourcecode
struct _SomeObject{
	GObject parent;
	/*variabili pubbliche*/
	int property;
};

struct _SomeObjectClass{
	GObjectClass parent_class;
	int (*get)(SomeObject*);
};
|endsourcecode
Precedentemente a questo, come standard, sono necessarie delle macro 
\sourcecode
#define SOME_OBJECT_TYPE           (some_object_get_type())
#define SOME_OBJECT(obj)           (G_TYPE_CHECH_INSTANCE_CAST((obj),SOME_OBJECT_TYPE,SomeObject))
#define SOME_OBJECT_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),SOME_OBJECT_TYPE,SomeObjectClass))
#define SOME_IS_OBJECT(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),SOME_OBJECT_TYPE))
#define SOME_IS_OBJECT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass),SOME_OBJECT_TYPE))
#define SOME_OBJECT_GET_CLASS(obj) (G_TYPE_GET_CLASS((obj),SOME_OBJECT_TYPE,SomeObjectClass))
|endsourcecode
dove
\bigskip
\item{} \iniziacodice SOME_OBJECT_TYPE\finecodice\ restituisce il
\iniziacodice GType\finecodice
\item{} \iniziacodice SOME_OBJECT\finecodice\ restituisce un puntatore
a \iniziacodice SomeObject\finecodice
\item{} \iniziacodice SOME_OBJECT_CLASS\finecodice\ restituisce un
puntatore a \iniziacodice SomeObjectClass\finecodice
\item{} \iniziacodice SOME_IS_OBJECT\finecodice\ restituisce
\iniziacodice TRUE\finecodice\ nel caso l'oggetto a cui \`e applicato
risulta essere della classe \iniziacodice SomeObject\finecodice
\item{} \iniziacodice SOME_IS_OBJECT_CLASS\finecodice\ restituisce
\iniziacodice TRUE\finecodice\ nel caso l'oggetto a cui \`e applicato
risulta essere della classe \iniziacodice SomeObjectClass\finecodice
\item{} \iniziacodice SOME_OBJECT_GET_CLASS\finecodice\ restituisce
il puntatore alla classe a cui appartiene l'oggetto a cui \`e
applicato.
\bigskip\noindent
ed il tutto va inserito nel file header tra le macro
\iniziacodice G_BEGIN_DECLS\finecodice\ e
\iniziacodice G_END_DECLS\finecodice\ che hanno lo scopo di creare
automaticamente le righe di codice necessarie per la gestione
dell'oggetto.

Passiamo adesso al file sorgente vero e proprio (il \iniziacodice
.c\finecodice\ per capirci) e definiamo l'oggetto su cui vogliamo
lavorare tramite la macro
\sourcecode
G_DEFINE_TYPE(SomeObject,some_object,G_TYPE_OBJECT)
|endsourcecode
dove \iniziacodice SomeObject\finecodice\ definisce il GType
dell'oggetto, \iniziacodice some_object\finecodice\ il prefisso con il
quale chiamare i metodi ed infine l'ultimo argomento della macro
designa da quale classe deve prendere origine il nostro oggetto: in
questo caso il tipo fondamentale.

In seguito bisogna definire i metodi ed in particolare quelli
relativi all'instanziamento della classe e dell'oggetto tramite
le funzioni 
\sourcecode
static void some_object_init(SomeObject* self){
	self->property = 1;
}

static void some_object_class_init(SomeObjectClass* klass){
	klass->get = some_object_get;
}
|endsourcecode
che sono private, la funzione per creare il nuovo oggetto
\sourcecode
SomeObject* some_object_new(){
	return g_object_new(SOME_OBJECT_TYPE,NULL);
}
|endsourcecode
ed infine il metodo per ottenere la propriet\`a settata
\sourcecode
int some_object_get(SomeObject* self){
	return self->property;
}
|endsourcecode
Salvando tutto questo nel file \iniziacodice some_object.c\finecodice\
possiamo compilarlo tramite il comando

\setdisplaycode
gcc -Wall -c some_object.c `pkg-config --cflags glib-2.0`
\unsetdisplaycode
per ottenere il file oggetto \iniziacodice some_object.o\finecodice\
da includere nei vostri programmi. Ricordarsi di includere
\iniziacodice some_object.h\finecodice!

\sezione Codice

Siccome abbiamo detto all'inizio che questa libreria \`e basata sulle
funzionalit\`a del Glib Dynamic Type System per cui prima di poter
definire qualunque funzione \`e necessario chiamare
\iniziacodice void g_type_init(void) \finecodice
che appunto inizializza il tutto.
\sourcecode
#include"some_object.h"
int main(int argc,char* argv[]){
  SomeObject* oggetto_qualsiasi;
  g_type_init();
  oggetto_qualsiasi = some_object_new();
	printf("property: %d\n",some_object_get(oggetto_qualsiasi));	
	return 0;
}
|endsourcecode
Per ultima cosa, ma fondamentale, sono necessari i seguenti passi per
ottenere codice compilabile:
\medskip
\item{$1$ - }includere \iniziacodice <glib-object.h>\finecodice 
\item{$2$ - }includere i file header contenenti le definizioni delle
classi create (\iniziacodice some_object.h\finecodice\ nel nostro
caso).
\item{$3$ - }mettere correttamente le flags al compilatore: nel caso
si usi la versione installata in un sistema avente
\iniziacodice pkg-config\finecodice\ bisogna usare
\iniziacodice `pkg-config --libs --cflags gobject-2.0`\finecodice
\medskip
Cos\`\i se il codice subito sopra lo salviamo nel file \iniziacodice
main.c\finecodice\ dobbiamo compilarlo nella seguente maniera per
ottenere l'eseguibile
\setdisplaycode gcc main.c some_object.o -o main `pkg-config --cflags
--libs gobject-2.0`\unsetdisplaycode
\sezione GObject

Per dovere di cronaca riporto il codice completo della classe base
\sourcecode
typedef struct {
  GTypeClass   g_type_class;

 	/* overridable methods */
 	GObject* (*constructor) (GType type,guint n_construct_properties,GObjectConstructParam *construct_properties);
	void (*set_property) (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
 	void (*get_property) (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 	void (*dispose) (GObject *object);
 	void (*finalize) (GObject *object);
  
 	/* seldomly overidden */
 	void (*dispatch_properties_changed) (GObject *object, guint n_pspecs, GParamSpec **pspecs);

 	/* signals */
 	void (*notify) (GObject	*object, GParamSpec	*pspec);
} GObjectClass;
|endsourcecode

\sezione Approfondimenti

A dire la verit\`a la documentazione non \`e molto esauriente, trovare
informazioni intese come guide \`e molto difficile! personalmente ho
imparato di pi\`u leggendo il codice sorgente di applicazioni che
usano queste librerie per estendere oggetti preesistenti (come per
esempio le \!GTK+!) che dalla documentazione ufficiale che si trova
sul web.

\bigskip
\item{} \!API reference:! \iniziaurl
http://docs.linux.cz/programming/gnome/developer.gnome.org/doc/API\/2.0/gobject/\fineurl
\item{} \!Extending a GtkDrawingArea (using cairo):! \iniziaurl
http://gnomejournal.org/article/34\/\hbox{writing-a-widget-using-cairo-and-gtk28}\fineurl
\item{} \! GTK+ / Gnome Application Development! \iniziaurl
http://developer.gnome.org/doc\/GGAD/ggad.html\fineurl
\item{} \!Revisioni di questo documento e codice:! \iniziaurl
http://www4.autistici.org/packz/\fineurl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\bye
