Introduction à la bibliothèque GTK+ - Jean-Matthieu
Transcription
Introduction à la bibliothèque GTK+ - Jean-Matthieu
Introduction à la bibliothèque GTK+ Labo-Unix - http://www.labo-unix.net 2001-2002 1 Introduction à la bibliothèque GTK+ Table des matières Droits de ce document 3 1 Mais... heu... Qu’est-ce que c’est ? ! 4 2 Avant de commencer 4 3 Un petit exemple... 5 4 Explication du programme 4.1 La création de la fenêtre . 4.2 Séparation en boite . . . . 4.3 Les labels . . . . . . . . . 4.4 Les boutons . . . . . . . . 4.5 La fin . . . . . . . . . . . . . . . . 6 6 8 8 9 9 5 Précision 5.1 la boucle principale . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 callback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 10 10 10 6 Annexe 6.1 La hiérarchie des widgets . . . . . . . . . . . . . . . . . . . . . . . . 10 10 . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ Droits de ce document Copyright (c) 2001 labo-unix.org Permission vous est donnée de copier, distribuer et/ou modifier ce document selon les termes de la Licence GNU Free Documentation License, Version 1.1 ou ultérieure publiée par la Free Software Foundation ; avec les sections inaltérables suivantes : - pas de section inaltèrable Une copie de cette Licence est incluse dans la section appelée GNU Free Documentation License de ce document. 3 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ " gtk is good " (Dalaı̈ Lama) Si vous préferez l’anglais, je ne peu que trop vous conseillez d’aller sur le site officiel de gtk (www.gtk.org) et de parcourir le tutorial. Il est surement plus complet que celui-ci. Il est assez bien fait et je m’en suis inspiré (honte). 1 Mais... heu... Qu’est-ce que c’est ? ! GTK+ signifie Gimp ToolKit. Donc Graphic Image Manipulation Program ToolKit. Vous êtes bien avancé, hein ? Un toolkit, c’est un ensemble de fonctions pour manipuler des objets graphiques généralement liée a une IHM (Interface Homme Machine). Ca n’a pas encore l’air très clair. En fait, c’est une bibliothèque qui permet de gérer des fenètres, des boutons, des menus... Et ca marche avec windows, linux, *bsd, beos et pleins d’autres systemes. Si il y a autant de programme qui utilise GTK+, c’est parce que c’est relativement simple à utiliser, assez joli à regarder (bien que *un peu* lent et ne gérant pas encore les polices vectoriels), et que justement deja pleins de monde l’utilise ! A l’origine, GTK+ faisait partie de The Gimp, un logiciel de retouche d’image. Mais comme tout le monde le trouvait très intéressant, les développeurs ont décidés de le séparer et de créer GTK+. Et comme QT était à l’époque fourni avec une license propriétaire, GTK+ est devenu la base du projet gnome. Attention a ne pas mélanger gnome et GTK+ car si gnome est basé sur GTK+, il rajoute aussi tout un tas de fonction qui ne nous intéressent pas. Evidemment, GTK+ a été programmé en C et s’utilise normalement en C mais il existe de nombreux wrappers pour d’autres langages : C++, Perl, Python, PHP... 2 Avant de commencer Tous d’abord, il faut installer GTK+. Pour ça je vous demanderais de vous réferer a la documentation de votre système. Aujourd’hui beaucoup de programme utilise GTK+ (xmms, xchat, gimp..), aussi peut-être l’avez vous deja. Pour vérifier, regardez si vous avez un petit programme appelé gtk-config (ou gtk12-config sur les BSD). Et éxecutez-le comme ceci : # gtk-config --version Normalement, vous devriez voir la version de GTK+ installée sur votre système. GTK+, c’est juste des bibliothèques. Rien de visible pour l’instant. Patience : ”Today is one day, but tomorrow is not yesterday” ( (c) kasskooye.com). GTK+ utilise la Glib. C’est une autre bibliothèque qui permet de gérer la mémoire, les canaux E/S, les logs, les chaı̂nes, les listes, les tableaux, les tables de hash, les threads... C’est très simple et très pratique. Sachez que si vous utilisez correctement cette bibliothèque, le portage et debuggage de votre appli en seront facilités. Parfois vous entendrez parlez de GDK ou alors vous verrez des noms de fonctions qui commencent par gdk *. Ne vous inquietez pas, cela fais partie de GTK+, il s’agit de la couche graphique proprement dite. Elle permet de faire abstraction des fonctions X et de gérer les pixels, lignes, mode de couleur et évenement. 4 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ 3 Un petit exemple... J’expliquerais le code après, pour éviter de le rendre illisible. /* exemple begin: mppeg.c (Mon Premier Programme En Gtk) */ #include <gtk/gtk.h> int main(int argc, char *argv[]) { GtkWidget *fenetre, *boite, *label, *bouton; gtk_init(&argc, &argv); fenetre = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(fenetre), "Viens donc faire un tour a Lambe"); gtk_container_set_border_width(GTK_CONTAINER(fenetre), 10); gtk_signal_connect(GTK_OBJECT(fenetre), "destroy", GTK_SIGNAL_FUNC(gtk_main_quit), NULL); boite = gtk_vbox_new(FALSE, 10); gtk_container_add(GTK_CONTAINER(fenetre), boite); gtk_widget_show(boite); label = gtk_label_new("Oasis is good (enfin presque)"); gtk_box_pack_start(GTK_BOX(boite), label, FALSE, FALSE, 0); gtk_widget_show(label); bouton = gtk_button_new_with_label(" Arvi "); gtk_signal_connect_object(GTK_OBJECT(bouton), "clicked", GTK_SIGNAL_FUNC(gtk_main_quit), GTK_OBJECT(fenetre)); gtk_box_pack_end_defaults(GTK_BOX(boite), bouton); gtk_widget_show(bouton); gtk_widget_show(fenetre); gtk_main(); return 0; } /* exemple end */ Voila. C’est beau, non ? Bon, pour voir à quoi ca ressemble, il faut le compiler. Vous vous rappelez du script gtk-config ? Celui-ci permet d’obtenir le chemin des bibliothèques GTK+ et des en-têtes (gtk.h) ainsi que toutes les bibliothèque nécessaire a la compilation du programme. Donc pour compiler on va faire ca : gcc -Wall -pipe ‘gtk-config --cflags --libs‘ -o mppeg mppeg.c Pour les options de gcc, se réferer au cours sur la compilation. Bref, -Wall signifie qu’il faut afficher tous les warnings et -pipe indique au compilateur d’utiliser la mémoire plutot que le disque pour ses fichiers temporaires (à éviter si vous avez peu de mémoire). Pour que gcc éxecute le script gtk-config avec ses arguments, il faut le placer sur la ligne de comande entre guillement inversé. C’est très important : 5 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ comme les scripts shell, gcc n’éxecute que ce qui se trouve entre guillement inversé. Le -o mppeg n’est pas obligatoire (sinon le programme compilé s’appellera a.out). Le script gtk-config va être remplacé par les chemin des headers (grace a –cflags) et par les chemins et noms des bibliothèque nécessaire (grace a –libs). Chez moi, lorsque j’éxecute ’gtk-config –cflags –libs’, ca donne ca : -I/usr/X11R6/include/gtk12 -I/usr/local/include/glib12 -I/usr/local/include -I/usr/X11R6/include -L/usr/X11R6/lib -L/usr/X11R6/lib -lgtk12 -lgdk12 -L/usr/local/lib -Wl,-E -lgmodule12 -lglib12 lintl -lxpg4 -lXext -lX11 -lm Bref, tout ce qu’il faut pour que le programme se compile normalement. Chez vous ça peut être différent et c’est pour ça qu’on utilise le script gtk-config. Maintenant vous pouvez éxecuter le petit programme : # ./mppeg Et voilà ce que ça donne : Fig. 1 – Réalisation d’un simple bouton GTK+ Vous pouvez redimmensionner la fenêtre, l’iconifier, la fermer. Vous remarquerez que GTK+ ajuste automatiquement la taille du bouton pour qu’il prenne toute la place disponible. 4 Explication du programme GTK+ utilise une approche objet. Oui, on va parler d’objet mais rassurez-vous, rien a voir avec le C++. Ouf. Il y a de nombreux types d’objets : GtkWidget, GtkEntry, GtkButton, GtkWindow... Et tous appartiennent a une classe générique : GtkObject. La plupart appartiennent a une sous-classe de GtkObject : GtkWidget. Par exemple, le type GtkEntry fait partie du type GtkEditable qui lui-même fait partie du type GtkWidget. Donc, on peut utiliser les fonctions propres aux GtkWidget sur les GtkEntry. Cela fait une sorte d’héritage. En annexe vous trouverez l’arbre de tous les widgets. Dans GTK+ ce qu’on manipule le plus souvent ce sont des GtkWidget (widget signifie WIndows gaDGETS). la fonction gtk init() permet d’initialiser GTK+. On lui passe les arguments du programme. Ensuite, on peut toujours traiter nos arguments mais *après* cette fonctions. Les arguments utilisés par GTK+ sont par exemple ’#./mppeg –display autre machine :0.0’ pour spécifier un autre serveur X. Il ne faut pas oublier d’inclure le header ¡gtk.h¿ qui comporte toutes les définitions nécessaire au compilateur. 4.1 La création de la fenêtre gtk window new() crée une nouvelle fenêtre gtk. Elle nous renvoie un pointeur sur cet objet. L’arguments que prend cette fonction peut être : – GTK WINDOW TOPLEVEL : C’est a dire une fenêtre normale pour une application normale. 6 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ – GTK WINDOW DIALOG : Une fenêtre de dialogue avec l’utilisateur. Elle a moins de décoration (ça c’est gérer par le window manager). – GTK WINDOW POPUP : Une fenêtre tres simple, juste pour informer l’utilisateur. Elle n’a aucune décoration. Pour voir ce que ça donne, n’hésitez pas à modifier le programme et voir par vous meme. la fonction gtk window set title() permet comme son nom l’indique de changer le titre de la fenêtre. Le premier argument doit etre une fenêtre (type GtkWindow). Hmmm... Oui mais c’est un widget (type GtkWidget) que l’on a. Donc on utilise une macro GTK WINDOW() qui fait simplement un ’cast’ du type widget vers le type window. En effet le type widget englobe tous les types que peuvent avoir les objets de GTK+. Il y a beaucoup de macros qui permettent de ’caster’ d’un type vers un autre. Vous pouvez voir que toutes les fonctions commencant par gtk widget * n’ont pas besoin de cast (car on a declaré nos variables comme étant du type widget). Mais toutes les fonctions autres (gtk window *, gtk container *, gtk box *...) n’acceptent pas de widget. Il faudra utiliser les macros de cast. Celles-ci (GTK WINDOW(), GTK CONTAINER(), GTK BOX()...) font un cast d’une structure vers une autre et affiche un warning lorsque le type n’est pas le bon. Ces warnings sont retirés avec les symboles de debuguages. C’est très pratique, meme si certains trouvent que ça rends les programmes illisibles. Le deuxième argument de la fonction gtk window set title() est... le titre ! Etonnant. La fonction gtk container set border width() permet de créer une marge autour de la fenêtre de 10 pixels. Presque tous les widgets sont des GTK CONTAINER. On verra ca plus en détails dans la hierarchie des widgets. La fonction gtk signal connect object(). C’est une fonction qui permet d’associer une action à un évenement. La, on décide que pour l’évenement ”destroy” sur la fenêtre, on appellera la fonction gtk main quit() qui arrete la boucle gtk (qu’on expliquera plus loin). Le premier argument de cette fonction est l’objet sur lequel l’action sera effectué. Par exemple un bouton, une fenêtre, une boite de texte... ensuite on indique pour quel évenement nous interrèsse. Exemple si la souris passe au-dessus, qu’on clique dessus, qu’on cache l’objet... il y en a une multitude et ce ne sont pas les mêmes suivant l’objet concerné. (un bouton peut être cliqué mais pas un label). L’argument suivant est la fonction qui sera éxecuté pour cet évenement. Ca peut être une fonction deja existante dans gtk, comme ici, on bien une fonction que vous avez écris vous-meme. Attention la fonction doit correspondre à certains critère : suivant l’évenement elle ne prendra pas les même arguments. Le dernier paramètre est un pointeur que vous pouvez passer a la fonction. C’est d’ailleurs le seul moyen de lui passer des données qui n’ont rien a voir avec gtk. A ce point, on a créé une fenêtre avec un titre qui quitte le programme lorsqu’on la ferme. Mais si vous ne laissez que ces quelques lignes vous ne verrez rien. Pourquoi ? Tout simplement parce qu’on n’a pas indiqué à GTK+ qu’il fallait afficher cette fenêtre ! Et oui, on peut avoir une multitude de widget et ne vouloir en afficher que quelques un. Donc il faut rajouter la fonctions gtk widget show(). Dans cet exemple, la fenêtre n’est affichée qu’à la fin du programme. 7 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ Okay, maintenant on arrive au plus dur : mettre les widgets les uns dans les autres. Ben oui, c’est bien beau d’avoir pleins de fenêtre, bouton, ascenseur et icones, encore faut-il savoir comment on les imbrique. Dans GTK+ il y a des GTK BIN et des GTK BOX. Les GTK BIN ne peuvent contenir qu’un seul widget. A contrario, les boites peuvent en contenir une multitude. Il y a deux types de boites : les boites horizontales qui affichent les widgets horizontalement les uns à cotés des autres et les boites verticales qui affichent les widgets les une au-dessus/dessous des autres. Bien entendu, une boite peut contenir une autre boite. Par exemple si vous voulez affichez une liste de répertoires sur le coté de gauche de votre application et deux fenêtres séparés horizontalement à droites il va d’abord falloir faire une boite horizontale. Dans cette boite vous mettrez la liste de répertoire a gauche et une autres boites, verticale celle-ci, à droite. Cette dernière contiendra vos deux fenêtres. Il existe aussi des tables. Celle-ci permettent de découper la place disponibles en carrés. Ensuite, vous pouvez mettre des widgets dans ces carrés (sachant qu’un widget peut utiliser plusieurs carrés consécutifs). Pour les GTK BIN, Si vous voulez y mettre plus d’un widget, il va falloir d’abord y mettre un boite puis mettre les widgets dans la boite. prenons le cas d’un bouton. Le bouton est un GTK BIN. Il contient juste un label. Si vous prefereriez y ajouter un pixmap (une icone), il faut créé le bouton, y mettre une boite puis, dans cette boite, mettre le label et le pixmap. Vous savez comment mettre les widgets les uns dans les autres. Malheureusement, ça ne correspond jamais a ce que l’on attend : un label sera tout ecrasé alors qu’un autres prendra toute la place, le bouton ne se place pas la ou vous le vouliez...etc. C’est le plus dur de GTK+ : arrivez a présentez les widgets comme l’on veut. Il y a plusieurs paramêtres qui peuvent jouer la-dessus. Lorsque l’on crée une boite tout d’abord. 4.2 Séparation en boite La fonction gtk vbox new() crée une boite verticale. Elle renvoie un pointeur sur une widget. Vous pouvez crée une boite horizontale avec gtk hbox new() qui prend les mêmes paramètres. Le premier argument de la fonction gtk vbox new() indique si les widgets doivent tous avoir une part égale de la boite. Si elle est a FALSE, certains widgets peuvent prendre plus de place que d’autres. Le deuxième paramètres indique le nombre de pixel à mettre entre deux widgets. Ensuite on utilise la fonction gtk container add() pour placer la boite dans la fenêtre car la fenêtre est un GTK BIN... C’est pas tres logique mais on utilise les fonctions gtk container * pour modifier les GTKB IN carcesontdesf onctionsquimarcheindif f éremm Bien sur personne n’a oublié la fonction gtk widget show() qui permet de montrer la boite. Meme si elle n’a rien de visible, le fait d’oublier cette fonction empêchera de voir tous les widgets qu’elle contient ! 4.3 Les labels On a décider de mettre un label mais on aurait pu mettre n’importe quel widget GTK+ : une autre boite, des listes à choix multiples, une fenêtre de textes...etc. Mais revenons à notre label. Pour le créer on a la fonction gtk label new() qui renvoie un 8 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ pointeur sur un widget. L’argument qu’ele prend est le texte du label. Rien de bien sorcier. La fonction gtk box pack start() place un widget dans une boite. Le widget est placé en haut dans le cas d’une boite verticale et a gauche dans le cas d’une boite horizontale. Pour placer le widget en bas/droite on utilise gtk box pack end(). Ces deux fonctions prennent les mêmes paramètres : Tout d’abord la boite. Ensuite le widget que l’on veut incorporer. Apres viennent : un paramètre (TRUE/FALSE) qui indique si le widget doit prendre toutes la place disponibles dans la boite. Si plusieur widgets veulent prendre toutes la place dispo, elle sera divisée entre eux. Un autre paramètre (TRUE/FALSE) indique si la place supplémentaires doit être utilisé par le widget ou bien complétée par un espace vide. Le dernier paramètre est le nombre de pixel (espace vide) à compléter entre le widget et ses copains. Je vous invite a tester tous ces paramètres pour bien comprendre leur fonctionnement. C’est pas évident de faire ce qu’on veut du premier coup. 4.4 Les boutons On va créer le bouton. C’est vite fait avec la fonction gtk button new with label(). Evidemment, le paramètre est le texte du bouton (’arvi’ signifie ’au revoir’ en patois haut-savoyard). Comme d’hab, la fonction renvoie un pointeur sur un GtkWidget. On utilise une fonction gtk box pack end defaults() pour le caser dans la boite. Cette fonction est presque pareil que gtk box pack end() mais avec les trois dernier paramètre à : TRUE, FALSE, 0. Il existe aussi gtk box pack start defaults(). On n’oublie surout pas la fonction gtk widget show() pour chaque widget. Sinon, le widget n’est pas visible (et donc aussi tous ses descendants). Pour éviter d’avoir à appeler gtk widget show() tout le temps, il existe gtk widget show all(petit beurre) qui va montrer tous les widgets contenus par le widgets petit beurre ainsi que le widget petit beurre. 4.5 La fin Ca y est, notre petite fenêtre est complète. Il ne reste plus qu’a donner la main a GTK+. C’est la fonction gtk main() qui s’en occupe. Elle lance la boucle de GTK+. Le programme ne reviendra à cette fonction qu’après l’appel à gtk main quit(). La boucle principale de GTK+ attend les évenements (passage de souris, clique, redimensionnement...) et les traite en conséquence. Pour chaque evenement il a un ’signal’ GTK+ qui est envoyé aux widgets concernés. Et on peut utiliser tous ces signaux pour notre application. En résumé, utiliser GTK+ est très simple : il faut créer les widgets, les placer, puis spécifier quelles fonctions lancer lorsque l’utilisateurs intervient. 5 Précision Voici quelques idées utiles lors du développement d’un programme. 9 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ 5.1 la boucle principale Il y a plusieurs façon d’influencer la boucle d’événemment GTK+ : – En ajoutant des fonctions lors de l’initialisation : gtki nita dd().Lorsdelasortie : gtkq uita dd(). – Lorsque il n’y a rien a faire : gtki dlea dd().oubienaprèsuncertaintemps : gtkt imeouta dd(). – Vous pouvez aussi la faire avancer pas-à-pas : gtki terationd o()ettestersidesévénemmentsontprésenta – On peut aussi lui demander de scruter un descripteur a notre place et de lancer un callback lorsque des données arrivent. C’est très pratique pour ne pas bloquer l’application sur une attente d’entrée/sorties : gtki nputa dd()etgtki nputa ddf ull()(cettedernièrepermettantd 5.2 callback Les fonctions de callbacks (c’est à dire les fonctions lancés lorsqu’un certains événemments a lieu), peuvent être ajoutés après les callbacks GTK+, ou bien avant (gtks ignalc onnect(), gtks ignalc onnecta f ter()).Onpeutaussispécif ierdesf onctionsàlancerlorsquelaf gtks ignalc onnectf ull().Bienentendu, vouspouvezaussiémettrelessignauxàlaplacedel0 utilisateur : gtks ignale mit().Oubiendéconnecterunsignal : gtks ignald isconnect(). 5.3 Widgets La liste des différents widgets est impresionnante. Leurs noms sont suffisamment explicite pour savoir à quoi ils servent. De nombreuses fonctions permettent de les manipuler. Faire une liste exhaustive et une description de toutes ces fonctions sortirait du cadre de cette article. Je vous invite à aller voir du coté de la documentation de l’API. Maintenant que vous savez comment marche GTK+, vous n’avez plus qu’à découvrir toutes ses possibilités. 6 6.1 Annexe La hiérarchie des widgets GtkObject +-- GtkWidget | +-- GtkMisc | | +-- GtkLabel | | | +-- GtkAccelLabel | | | +-- GtkTipsQuery | | +-- GtkArrow | | +-- GtkImage | | +-- GtkPixmap | +-- GtkContainer | | +-- GtkBin | | | +-- GtkAlignment | | | +-- GtkFrame | | | | +-- GtkAspectFrame | | | +-- GtkButton | | | | +-- GtkToggleButton | | | | | +-- GtkCheckButton | | | | | +-- GtkRadioButton | | | | +-- GtkOptionMenu 10 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +-+-| +-| | | +-| | +-| | +-- GtkItem | | +-- GtkMenuItem | | | +-- GtkCheckMenuItem | | | | +-- GtkRadioMenuItem | | | +-- GtkTearoffMenuItem | | +-- GtkListItem | | +-- GtkTreeItem | +-- GtkWindow | | +-- GtkColorSelectionDialog | | +-- GtkDialog | | | +-- GtkInputDialog | | +-- GtkFileSelection | | +-- GtkFontSelectionDialog | | +-- GtkPlug | +-- GtkEventBox | +-- GtkHandleBox | +-- GtkScrolledWindow | +-- GtkViewport +-- GtkBox | +-- GtkButtonBox | | +-- GtkHButtonBox | | +-- GtkVButtonBox | +-- GtkVBox | | +-- GtkColorSelection | | +-- GtkGammaCurve | +-- GtkHBox | +-- GtkCombo | +-- GtkStatusbar +-- GtkCList | +-- GtkCTree +-- GtkFixed +-- GtkNotebook | +-- GtkFontSelection +-- GtkPaned | +-- GtkHPaned | +-- GtkVPaned +-- GtkLayout +-- GtkList +-- GtkMenuShell | +-- GtkMenu | +-- GtkMenuBar +-- GtkPacker +-- GtkSocket +-- GtkTable +-- GtkToolbar +-- GtkTree GtkCalendar GtkDrawingArea +-- GtkCurve GtkEditable +-- GtkEntry | +-- GtkSpinButton +-- GtkText GtkRuler +-- GtkHRuler +-- GtkVRuler GtkRange +-- GtkScale 11 Labo-Unix - Supinfo Paris - 2001/2002 Introduction à la bibliothèque GTK+ | | | | | | | | | | | | +-| | +-- | | | | | +-- | +-- GtkHScale | +-- GtkVScale +-- GtkScrollbar +-- GtkHScrollbar +-- GtkVScrollbar GtkSeparator +-- GtkHSeparator +-- GtkVSeparator GtkInvisible GtkPreview GtkProgress +-- GtkProgressBar GtkData +-- GtkAdjustment +-- GtkTooltips GtkItemFactory 12 Labo-Unix - Supinfo Paris - 2001/2002