Introduction `a GTK - Frédéric Devernay

Transcription

Introduction `a GTK - Frédéric Devernay
Introduction à GTK
Frédéric Devernay
[email protected]
8 novembre 1999
Résumé
Nous verrons d’abord l’organisation générale de GTK et de
GNOME. Nous détaillerons ensuite l’utilisation de la bibliothèque de portabilité GLib, puis quelques exemples d’utilisation de GTK.
Pourquoi GNOME et GTK?
– Parce que GTK ne dépend pas du langage utilisé (6= Qt),
est portable et extensible, et que le source est disponible.
– Parce que GNOME est basé sur des concepts largement
répandus dans l’industrie (CORBA, XML), mais peu enseignés.
– Et en plus c’est beau ! (thèmes, etc.)
L’architecture logicielle de GTK/GNOME
La hiérarchie des bibliothèques de GNOME
– Les bibliothèques GNOME sont haut niveau (notion d’application, fichiers de config...)
– GTK+ est composé de GTK (widget toolkit) et GDK (primitives
de dessin bas niveau)
– GLib est une bibliothèque de portabilité (types, fonctions standard) et d’utilitaires (listes, tables de hachage, ...)
1
Les bibliothèques GNOME
–
–
–
–
–
–
–
libgnome : utilitaires indépendants de la toolkit ;
libgnomeui : ... dependants de la toolkit (combos, ...) ;
libgnorba : utilisation de corba, via ORBit ;
gtk-xmhtml : widget HTML pour GTK ;
xvt : widget d’émulation de terminal ;
libvfs : file système virtuel utilisé dans Midnight Commander ;
libart lgpl : bibliothèque graphique avec anti-aliasing.
Mais commençons par le début : GLib, puis GTK, puis GNOME.
Caractéristique commune de toutes ces bibliothèques : peu de
documentation. Resources disponibles :
•
•
•
–
www.gtk.org (GTK)
developer.gnome.org/doc (GNOME)
www-mips.unice.fr/ devernay/cours/IHM (le site du cours)
les includes de GTK, GLib, ...
2
GLib
Les noms de fonction commencent par g (g strdup), les types par
g (gint32), les structures sont capitalisées et commencent par G
(GHashTable).
Typedefs :
– gint8 : entier signé 8 bits
– guint8 : entier non signé 8 bits
– ... gint16, guint16, gint32, guint32, gint64 et guint64 (dispo si
G HAVE GINT64 est défini), gchar, guchar, gshort, gushort, glong,
gulong, gint, guint, gfloat, gdouble, gboolean (en fait un int,
prend les valeurs TRUE ou FALSE), gpointer (= void *), gconstpointer (= const void *)
Portabilité et Utilitaires :
– gchar* g strdup (const gchar*) = stdup()
– g malloc, g free
– void g usleep (gulong count) suspend l’exécution pendant ’count’
microsecondes
– g snprintf = snprintf à utiliser pour raisons éviter les ’buffer overflows’ (sécurité++)
– g new(type,count) (= (type) g malloc(count*sizeof(type))), g new0
id. mais met à zéro
– gchar* g strconcat (const gchar *str, ..., NULL) concatène les
chaı̂nes en paramètres (alloue une nouvelle chaı̂ne)
– g strdup printf comme un sprintf, mais alloue la chaı̂ne
– g strstrip coupe les espaces au début et à la fin d’une chaı̂ne, n’alloue
pas, ne désalloue pas
3
GLib : Les containers
–
–
–
–
–
–
–
–
–
–
GList : liste doublement chaı̂née
GSList : liste simplement chaı̂née
GHashTable : table de hachage
GCache : cache
GTree : arbre binaire équilibré
GNode : arbre n-aire
GString : chaı̂ne de caractères de taille dynamique
GArray : tableau de taille dynamique
GPtrArray : tableau de pointeurs de taille dynamique
GByteArray : tableau d’octets (guint8) de taille dynamique
Listes
– GList* g list append (GList *list, gpointer data) ajoute data
à list. list peut être NULL (création)
– g list prepend, g list remove, g list find, g list next, g list previous, g list free
(ne libère pas les data !)
Chaı̂nes de caractères
/* le char* est dans le champ str de GString. */
GString* g_string_new
(const gchar *init);
void
g_string_free
(GString
*string, gint free_segment);
GString* g_string_append
(GString
*string, const gchar *val);
GString* g_string_prepend
(GString
*string, const gchar *val);
void
g_string_sprintf
(GString
*string, const gchar *format,
...) G_GNUC_PRINTF (2, 3);
void
g_string_sprintfa (GString
*string, const gchar *format,
...) G_GNUC_PRINTF (2, 3);
etc... Autres containers (/usr/include/glib.h), constantes et macros de conversion portables... même sous MSWindows (/usr/lib/glib/include/glibconfig.h).
4
GTK : introduction
– Il existe des interfaces C++ (GTK–), python (pyGTK), perl
(perlGTK), ..., mais nous allons utiliser l’interface C (les autres
lui ressemblent).
– GTK+ est écrit en C orienté-objet : implémente les notions de
classe, d’héritage (simple), de méthodes virtuelles, de typage fort
(à l’exécution) et de fonctions de rappel (callbacks).
Premier exemple : affiche une fenêtre 200x200
#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
GtkWidget *window;
/* recherche sur la ligne de commande les arguments --gtk-module
--g-fatal-warnings --display --sync --no-xshm --name --class */
gtk_init (&argc, &argv);
/* crée une fen^
etre et l’affiche */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
/* boucle d’évènements */
gtk_main ();
return 0;
}
5
GTK : Bonjour tout le monde
#include <gtk/gtk.h>
/* fonction de rappel. Dans cet exemple, les paramètres sont ignorés...
* Les fonctions de rappel sont détaillées plus loin. */
void hello (GtkWidget *widget, gpointer data)
{
g_print ("Bonjour tout le monde.\n");
}
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print ("le signal delete_event est survenu.\n");
/*
*
*
*
*
Si l’on renvoit TRUE dans le gestionnaire du signal "delete_event",
GTK émettra le signal "destroy". Retourner FALSE signifie que l’on
ne veut pas que la fen^
etre soit détruite.
Utilisé pour faire appara^
ıtre des bo^
ıtes de dialogue du type
(( ^
Etes-vous s^
ur de vouloir quitter ? )) */
/* Remplacez FALSE par TRUE et la fen^
etre principale sera détruite par
* un signal (( delete_event )). */
return (FALSE);
}
/* Autre fonction de rappel */
void destroy (GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
6
/* GtkWidget est le type pour déclarer les widgets. */
GtkWidget *window;
GtkWidget *button;
/* Cette fonction est appelée dans toutes les applications GTK.
* Les paramètres passés en ligne de commande sont analysés et
* retournés à l’application. */
gtk_init (&argc, &argv);
/* Création d’une nouvelle fen^
etre. */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/*
*
*
*
*
*
Lorsque la fen^
etre reçoit le signal "delete_event"
(envoyé par le gestionnaire de fen^
etres en utilisant l’option
(( close )) ou la barre de titre), on lui demande d’appeler la
fonction delete_event() définie plus haut. La donnée passée en
paramètre à la fonction de rappel est NULL et est ignoré dans le
rappel. */
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (delete_event), NULL);
/* Ici, on connecte l’évenement "destroy" à un gestionnaire de signal.
* Cet événement arrive lorsqu’on appelle gtk_widget_destroy() sur la
* fen^
etre, ou si l’on retourne TRUE dans le rappel "delete_event". */
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (destroy), NULL);
/* Configuration de la largeur du contour de la fen^
etre. */
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* Création d’un nouveau bouton portant le label
* "Bonjour tout le monde". */
button = gtk_button_new_with_label ("Bonjour tout le monde");
/* Quand le bouton recevra le signal "clicked", il appellera la
7
* fonction hello() définie plus haut en lui passant NULL en paramètre. */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (hello), NULL);
/*
*
*
*
Ceci provoquera la destruction de la fen^
etre par appel de la
fonction gtk_widget_destroy(window) lors du signal "clicked".
Le signal de destruction pourrait venir de là, ou du
gestionnaire de fen^
etres. */
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
GTK_OBJECT (window));
/* Insertion du bouton dans la fen^
etre (container gtk). */
gtk_container_add (GTK_CONTAINER (window), button);
/* L’étape finale consiste à afficher ce nouveau widget... */
gtk_widget_show (button);
/* ... et la fen^
etre. */
gtk_widget_show (window);
/* Toutes les applications GTK doivent avoir un gtk_main().
* Le déroulement du programme se termine là et attend qu’un
* événement survienne (touche pressée ou événement souris). */
gtk_main ();
return 0;
}
Compilation
gcc -Wall -g -I/usr/lib/glib/include bonjour.c -o bonjour_monde \
-L/usr/X11R6/lib -lgtk -lgdk -lglib -lXext -lX11 -lm
ou
gcc bonjour.c -o bonjour_monde ‘gtk-config --cflags --libs‘
8
GTK : théorie des signaux et rappels
GTK est dirigé par les événements : il reste dans gtk main()
jusqu’à ce qu’un événement arrive (ex. bouton). Il faut connecter le
gestionnaire de signaux sur la fonction de rappel :
/* retourne un identificateur de la fonction de rappel */
gint gtk_signal_connect( GtkObject
*object, /* widget émetteur */
gchar
*name,
/* nom du signal */
GtkSignalFunc func,
/* fctn de rappel */
gpointer
func_data ); /* données */
/* déconnecte le signal */
void gtk_signal_disconnect( GtkObject *object,
gint id );
/* déconnecte tous les signaux */
void gtk_signal_handlers_destroy( GtkObject *object );
La fonction de rappel a (en général) la forme :
void callback_func( GtkWidget *widget, /* widget émetteur */
gpointer
callback_data ); /* données */
Autre forme (utile pour appeler une fctn GTK prenant un objet) :
gint gtk_signal_connect_object( GtkObject
*object,
gchar
*name,
GtkSignalFunc func,
GtkObject
*slot_object );
void callback_func( GtkObject *object );
9
GTK : événements
event, button press event, button release event, motion notify event, delete event,
destroy event, expose event, key press event, key release event, enter notify event,
leave notify event, configure event, focus in event, focus out event, map event,
unmap event, property notify event, selection clear event, selection request event,
selection notify event, proximity in event, proximity out event, drag begin event,
drag request event, drag end event, drop enter event, drop leave event, drop data available event, other event
/* fonction de rappel */
void callback_func( GtkWidget *widget,
GdkEvent *event,
gpointer
callback_data );
GdkEvent.type : enum { GDK NOTHING, GDK DELETE, GDK DESTROY, GDK EXPOSE, GDK MOTION NOTIFY, GDK BUTTON PRESS, GDK 2BUTTON PRESS,
GDK 3BUTTON PRESS, GDK BUTTON RELEASE, GDK KEY PRESS, GDK KEY RELEASE, GDK ENTER NOTIFY, GDK LEAVE NOTIFY, GDK FOCUS CHANGE,
GDK CONFIGURE, GDK MAP, GDK UNMAP, GDK PROPERTY NOTIFY, GDK SELECTION CLEAR, GDK SELECTION REQUEST, GDK SELECTION NOTIFY, GDK PROXIMITY IN, GDK PROXIMITY OUT, GDK DRAG BEGIN, GDK DRAG REQUEST, GDK DROP ENTER, GDK DROP LEAVE, GDK DROP DATA AVAIL, GDK CLIENT EVENT,
GDK VISIBILITY NOTIFY, GDK NO EXPOSE, GDK OTHER EVENT /* Deprecated, use filters instead */ }
/* Connection d’un événement vers une fonction de rappel */
gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
GTK_SIGNAL_FUNC(button_press_callback),
NULL);
static gint button_press_callback (GtkWidget
*widget,
GdkEventButton *event,
gpointer
data);
10
GTK : Bonjour tout le monde amélioré
#include <gtk/gtk.h>
/* Notre nouveau rappel amélioré. La donnée passée à cette fonction est
* imprimée sur stdout. */
void rappel (GtkWidget *widget, gpointer *data)
{
g_print ("Re-Bonjour - %s a été pressé\n", (char *) data);
}
/* Un autre rappel */
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer *data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
/* GtkWidget est le type pour déclarer les widgets */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
/* Cette fonction est appelée dans toutes les applications GTK.
* Les paramètre passés en ligne de commande sont analysés et
* retournés à l’application. */
gtk_init (&argc, &argv);
/* Création d’une nouvelle fen^
etre. */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* Nouvel appel qui intitule notre nouvelle fen^
etre
11
* "Salut les boutons !" */
gtk_window_set_title (GTK_WINDOW (window), "Salut les boutons !");
/* Configuration d’un gestionnaire pour "delete_event" afin de
* quitter immédiatement GTK. */
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (delete_event), NULL);
/* Configuration de la largeur du contour de la fen^
etre. */
gtk_container_border_width (GTK_CONTAINER (window), 10);
/*
*
*
*
Création d’une bo^
ıte pour y placer les widgets.
Ceci est décrit en détails plus loin dans la section
(( placement )). La bo^
ıte n’est pas matérialisée, elle est juste
utilisée comme moyen d’arranger les widgets. */
box1 = gtk_hbox_new(FALSE, 0);
/* On met la bo^
ıte dans la fen^
etre principale. */
gtk_container_add (GTK_CONTAINER (window), box1);
/* On crée un nouveau bouton portant le label (( Bouton 1 )). */
button = gtk_button_new_with_label ("Bouton 1");
/* Lorsque le bouton est cliqué, on appelle la fonction (( rappel ))
* avec un pointeur sur la cha^
ıne (( Bouton 1 )) comme paramètre. */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (rappel), (gpointer) "Bouton 1");
/* Au lieu d’utiliser gtk_container_add, on place ce bouton dans
* la bo^
ıte invisible qui a été placée dans la fen^
etre. */
gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
/* N’oubliez jamais cette étape qui indique à GTK que la configuration
12
* de ce bouton est terminée et qu’il peut ^
etre affiché. */
gtk_widget_show(button);
/* On fait la m^
eme chose pour créer un deuxième bouton. */
button = gtk_button_new_with_label ("Bouton 2");
/* On appelle la m^
eme fonction de rappel avec un paramètre différent,
* un pointeur sur la cha^
ıne (( Bouton 2 )). */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (rappel), (gpointer) "Bouton 2");
gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
/* L’ordre dans lequel on affiche les boutons n’est pas vraiment
* important, mais il est préférable d’afficher la fen^
etre en dernier
* pour qu’elle surgisse d’un coup. */
gtk_widget_show(button);
gtk_widget_show(box1);
gtk_widget_show (window);
/* Le reste est dans gtk_main et on attend que la f^
ete commence ! */
gtk_main ();
return 0;
}
– Utilise le placement des widgets, cf. gtk box pack start().
– gtk window new(GTK WINDOW DIALOG) crée une boı̂te de
dialogue.
13
Placement des widgets
GtkWidget* gtk_hbox_new
(gboolean homogeneous,
gint spacing);
void gtk_box_pack_[start|end] (GtkBox
*box,
GtkWidget
*child,
gboolean
expand,
gboolean
fill,
guint
padding);
14
Tables
Utilisation d’une grille pour placer les widgets : lignes de 0 à nrows,
colonnes de 0 à ncolumns. homogeneous = boı̂tes prennent la taille
du plus grand widget.
Création avec gtk table new, placement avec gtk table attach
GtkWidget* gtk_table_new (gint rows,
gint columns,
gint homogeneous);
0
1
2
-> colonnes
0+----------+----------+
|
|
|
|
V lignes
1+----------+----------+
|
|
|
2+----------+----------+
void gtk_table_attach (GtkTable
*table, /* table */
GtkWidget
*child, /* widget à placer */
gint
left_attach, /* position */
gint
right_attach,
gint
top_attach,
gint
bottom_attach,
gint
xoptions, /* options */
gint
yoptions,
gint
xpadding, /* marge */
gint
ypadding);
options : OU logique de GTK FILL (le widget s’élargit pour occuper
tte la case), GTK SHRINK (les widgets sont réduits plutôt que
descendus lors d’un redimensionnement), GTK EXPAND (la table
utilise tout l’espace restant dans la fenêtre).
15
Tables : plus simple
/* options = GTK_FILL|GTK_EXPAND, padding=0 */
void gtk_table_attach_defaults (GtkTable
*table,
GtkWidget *widget,
gint
left_attach,
gint
right_attach,
gint
top_attach,
gint
bottom_attach);
/* espaces après une ligne ou une colonne */
void gtk_table_set_row_spacing (GtkTable
*table,
gint
row,
gint
spacing); /* en dessous */
void gtk_table_set_col_spacing (GtkTable
*table,
gint
column,
gint
spacing); /* a droite */
/* gtk_table_set_row_spacings, gtk_table_set_col_spacings = ttes les cols */
button = gtk_button_new_with_label ("button 1"); [...]
gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1); [...]
button = gtk_button_new_with_label ("button 2"); [...]
gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1); [...]
button = gtk_button_new_with_label ("Quit"); [...]
gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2); [...]
16
Vision d’ensemble des widgets
Étapes de la création d’un widget GTK :
1.
2.
3.
4.
5.
gtk * new()
Connexion des signaux voulus avec les gestionnaires adéquats
Placement dans un container/une boı̂te/une table
Créer/afficher les widgets fils
Affichage : gtk widget show()
gtk widget hide() fait disparaı̂tre un widget
Conversions de types (avec vérification), pour obtenir le type
requis par la déclaration de la fonction :
–
–
–
–
–
–
GTK
GTK
GTK
GTK
GTK
GTK
WIDGET(widget)
OBJECT(object)
SIGNAL FUNC(function)
CONTAINER(container)
WINDOW(window)
BOX(box)
17
Hiérarchie de classes des widgets
GtkObject
+GtkWidget
| +GtkMisc
| | +GtkLabel *
| | | +GtkAccelLabel
| | | ‘GtkTipsQuery
| | +GtkArrow *
| | +GtkImage *
| | ‘GtkPixmap *
| +GtkContainer
| | +GtkBin *
| | | +GtkAlignment *
| | | +GtkFrame *
| | | | ‘GtkAspectFrame *
| | | +GtkButton
| | | | +GtkToggleButton
| | | | | ‘GtkCheckButton
| | | | |
‘GtkRadioButton
| | | | ‘GtkOptionMenu
| | | +GtkItem *
| | | | +GtkMenuItem
| | | | | +GtkCheckMenuItem
| | | | | | ‘GtkRadioMenuItem
| | | | | ‘GtkTearoffMenuItem
| | | | +GtkListItem
| | | | ‘GtkTreeItem
| | | +GtkWindow
| | | | +GtkColorSelectionDialog
| | | | +GtkDialog
| | | | | ‘GtkInputDialog
| | | | +GtkDrawWindow
| | | | +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
| | +GtkMenuBar
| | ‘GtkMenu
| +GtkPacker
| +GtkSocket
| +GtkTable *
| +GtkToolbar
| ‘GtkTree
+GtkCalendar
+GtkDrawingArea
| ‘GtkCurve
+GtkEditable
| +GtkEntry
| | ‘GtkSpinButton
| ‘GtkText
+GtkRuler
18
|
|
|
|
|
|
|
|
|
|
|
|
|
| +GtkHRuler
| ‘GtkVRuler
+GtkRange
| +GtkScale
| | +GtkHScale
| | ‘GtkVScale
| ‘GtkScrollbar
|
+GtkHScrollbar
|
‘GtkVScrollbar
+GtkSeparator *
| +GtkHSeparator *
| ‘GtkVSeparator *
+GtkPreview
| ‘GtkProgress
|
‘GtkProgressBar
+GtkData
| +GtkAdjustment
| ‘GtkTooltips
‘GtkItemFactory
(*): Widgets sans fenêtres, doivent être englobés dans une GtkEventBox si on veut capturer
leur événements.
Une bonne doc sur les widgets et leur utilisation : le
programme testgtk.c
19
Boutons
Boutons normaux : deux possibilités pour les créer,
1. gtk button new with label()
2. gtk button new(), mettre l’intérieur du bouton dans une box
(gtk box pack start()) puis l’ajouter au bouton avec gtk container add().
Exemple : boutons.c
Boutons commutateurs et cases à cocker :
(toggle buttons & check buttons) émettent le signal “toggled”
GtkWidget*
GtkWidget*
GtkWidget*
GtkWidget*
gtk_toggle_button_new (void);
gtk_toggle_button_new_with_label (gchar *label);
gtk_check_button_new (void);
gtk_check_button_new_with_label (gchar *label);
/* exemple de fonction de rappel pour le signal "toggled" */
void rappel_bouton_commutateur (GtkWidget *widget, gpointer data)
{
if (GTK_TOGGLE_BUTTON(widget)->active)
{
/* Si l’on est ici, c’est que le bouton est rel^
aché. */
} else {
/* le bouton est enfoncé */
}
}
/* configuration du bouton, émet "clicked" si changement */
void gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
gint state); /*_set_state en GTK 1.0 */
/* change l’état et émet "toggled" */
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
20
Boutons (2)
Boutons radio : (exemple radiobuttons.c)
GtkWidget* gtk_radio_button_new (GSList *group);
GtkWidget* gtk_radio_button_new_with_label (GSList *group,
gchar *label);
/* group = NULL au premier appel, puis on crée le groupe avec : */
GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
/* ou bien */
button2 = gtk_radio_button_new_with_label(
gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
"button2");
/* positionner le bouton actif avec : */
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
gint
state );
21
Ajustements
Permettent de connecter un widget de (( réglage )) (scrollbar, valeur ajustable,
bouton de réglage) à un widget utilisant les valeurs correspondantes (zone de
text, viewport) pour afficher, par ex., une zone de données.
GtkAdjustment : Stocke la valeur concernée et les intervalles autorisés, peut
émettre des signaux lorsque la valeur ou les intervalles sont changés.
GtkObject *gtk_adjustment_new( gfloat
gfloat
gfloat
gfloat
gfloat
gfloat
value,
lower, /* intervalle */
upper, /*
autorisé */
step_increment, /* petit/ */
page_increment, /* grand incrément */
page_size ); /* taille zone visible */
Utilisation facile :
text = gtk_text_new (NULL, NULL);
vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
Changement de valeur (( à la main )) :
void gtk_adjustment_set_value( GtkAdjustment *adjustment,
gfloat
value );
l’ajustement émet le signal “value changed”. Exemple :
void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
{ set_picture_rotation (picture, adj->value); ... } ...
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
de même, lorsque les champs“upper”ou“lower”sont changés, le signal“changed”est émis. S’ils sont changés à la main, utiliser gtk signal emit by name(GTK OBJECT
(adjustment), “changed”).
22
Intervalles
Scale ou ScrollBar :
/* adj=NULL pour en créer un nouveau */
GtkWidget *gtk_[h|v]scrollbar_new( GtkAdjustment *adj );
/* affiche ou non la valeur */
void gtk_scale_set_draw_value(GtkScale *scale, gint draw_value);
/* nombre de décimales à afficher */
void gtk_scale_set_digits(GtkScale *scale, gint digits);
/* endroit où afficher la valeur */
/* pos = GTK_POS_[LEFT|RIGHT|TOP|BOTTOM] */
void gtk_scale_set_value_pos(GtkScale *scale, GtkPositionType
pos);
Fonctionnalités communes :
/* quand faut-il émettre le signal "changed" ? */
/* policy=GTK_UPDATE_POLICY_CONTINUOUS
-à chaque mvmt */
/* policy=GTK_UPDATE_POLICY_DISCONTINUOUS -quand on lache */
/* policy=GTK_UPDATE_POLICY_DELAYED
-quand on s’arr^
ete */
void gtk_range_set_update_policy( GtkRange *range, GtkUpdateType policy);
/* récupérer/changed l’ajustement */
GtkAdjustment* gtk_range_get_adjustment(GtkRange *range);
void gtk_range_set_adjustment(GtkRange *range, GtkAdjustment *adjustment);
Si on change l’ajustement, connecter les bons signaux au nouveau, et appeler gtk range adjustment changed()
Clavier :
–
–
–
–
intervalles verticaux : flèches haut/bas (1 step), PgUp/PgDwn (1page)
intervalles horizontaux : flèches gauche/droite (1 step), Home (début), End (fin)
scale : control-gauche/droite (1 step)
scrollbar : control-Home/End (1 step)
23
Widgets divers
Voir leur utilisation dans le tutorial (chapitre 9, Misc. Widgets) ou
dans testgtk.c.
–
–
–
–
–
–
–
–
–
–
–
–
–
Labels
Flèches
Bulles d’aide
Barres de progression
Dialogues
Pixmaps
Règles
Barres d’état
Entrées de texte
Boutons rotatifs
Boı̂te combo
Sélection de couleurs
Sélection de fichiers
24
Widgets conteneurs
Event Box : permet d’associer des évènements à un widget sans fenêtre, et
de faire le clipping (utile si on retaille un widget, avec gtk widget set usize()).
GtkWidget *gtk_event_box_new( void );
gtk_container_add( GTK_CONTAINER(event_box), child_widget );
/* ce qu’on ne peut pas faire avec un widget sans window : */
gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
GTK_SIGNAL_FUNC (gtk_exit), NULL);
gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
Widget Alignement : permet d’aligner un widget (position et taille, entre
0.0 et 1.0) à l’intérieur de sa fenêtre.
GtkWidget* gtk_alignment_new( gfloat xalign, yalign, xscale, yscale);
void gtk_alignment_set( GtkAlignment *alignment, xa, ya, xs, ys);
Conteneurs fixe et d’arrangement : pour placer un widget à une position
précise en pixels. Le conteneur d’arrangement implémente une zone quasiinfinie, qui peut être scrollée. De plus, il se redessine (se met à jour) tout seul
quand ses valeurs sont changées.
GtkWidget* gtk_[fixed|layout]_new( void );
void gtk_[fixed|layout]_put( [GtkFixed *fixed|GtkLayout *layout],
GtkWidget *widget, gint16 x, y );
void gtk_[fixed|layout]_move( [GtkFixed *fixed|GtkLayout *layout],
GtkWidget *widget, gint16 x, y );
/* fixer la taille : */
void gtk_layout_set_size( GtkLayout *layout, guint width, height );
/* empecher/remettre la mise à jour */
void gtk_layout_freeze( GtkLayout *layout );
void gtk_layout_thaw( GtkLayout *layout );
/* positionner/récupérer les ajustements */
25
GtkAdjustment* gtk_layout_get_[h|v]adjustment( GtkLayout *layout );
void gtk_layout_set_[h|v]adjustment( GtkLayout *layout,
GtkAdjustment *adjustment );
Cadres : (frame) englobe un ou plusieurs widgets avec une boı̂te, éventuellement étiquetée. Les cadres d’aspect (aspect frame) permettent en plus de
conserver l’aspect (largeur/hauteur) du widget fils.
Fenêtres coulissantes : (panned window) Fenêtre divisée en deux zones séparées par une ligne dont la position est règlable.
GtkWidget *gtk_[h|v]paned_new (void);
void gtk_paned_add[1|2] (GtkPaned *paned, GtkWidget *child);
void gtk_paned_set_handle_size(GtkPaned *paned, guint16 size);
void gtk_paned_set_gutter_size(GtkPaned *paned, guint16 size);
Viewport : permet de visualiser une partie d’un widget seulement. On utilise
plutôt scrolled window. Différence avec layout?
Scrolled Windows : Un viewport avec des scrollbars.
Boı̂tes de boutons : (button boxes) pour grouper facilement des boutons.
Barre d’outils : (toolbar) Permet typiquement de ranger ensemble des boutons avec des icones, du texte, et des bulles d’aide, dont l’aspeces t global
peut être changé facilement (barre de navigation netscape).
Bloc-notes : (notebook) Collection de pages superposées, avec des onglets
pour les sélectionner (préférences windows...).
26
Widget CList
Liste multi-colonnes pouvant gérer des milliers de colonnes, avec
un titre éventuellement actif (à la netscape Mail/News). Doit être
placé dans une GtkScrolledWindow si on a besoin de scrollbars.
GtkWidget *gtk_clist_new ( gint columns );
GtkWidget *gtk_clist_new_with_titles( gint
columns,
gchar *titles[] );
/* comportement */
void gtk_clist_set_selection_mode( GtkCList
*clist,
GtkSelectionMode mode );
mode = GTK_SELECTION_[SINGLE|BROWSE|MULTIPLE*|EXTENDED]
/* aspect */
void gtk_clist_set_shadow_type( GtkCList
*clist,
GtkShadowType border );
borde = GTK_SHADOW_[NONE|IN|OUT|ETCHED_IN|ETCHED_OUT]
Les titres peuvent être rendus actifs (comme des boutons) ou passifs (comme
des labels), être montrés ou cachés, et on peut changer le titre ou mettre un
widget quelconque dans un titre :
void gtk_clist_column_title_[active|passive]( GtkCList *clist,
gint
column );
void gtk_clist_column_titles_[active|passive]( GtkCList *clist );
void gtk_clist_column_titles_[show|hide]( GtkCList *clist );
void gtk_clist_set_column_title( GtkCList *clist,
gint
column,
gchar
*title );
void gtk_clist_set_column_widget( GtkCList *clist,
gint
column,
GtkWidget *widget );
Réglages des paramètres de la clist : gtk clist set column justification(), gtk clistset column width(), gtk clist set row height(), gtk clist set foreground(),
gtk clist set background().
27
Tester si une ligne est visible entièrement ou partiellement : gtk clist row is visible().
Aller à une ligne/colonne : gtk clist moveto().
/* Ajouter au début / à la fin / insérer une colonne */
gint gtk_clist_[prepend|append](GtkCList *clist, gchar*text[]);
void gtk_clist_insert(GtkCList *clist, gint row, gchar*text[]);
/* Enlever une/toutes les colonnes */
void gtk_clist_remove( GtkCList *clist, gint row );
void gtk_clist_clear( GtkCList *clist );
/* geler/réactiver les mises à jour de l’affichage */
void gtk_clist_freeze( GtkCList * clist );
void gtk_clist_thaw( GtkCList * clist );
/* mettre du texte/un pixmap/les deux dans une cellule */
void gtk_clist_set_text(clist,row,column, gchar *text);
void gtk_clist_set_pixmap(clist,row,column,
GdkPixmap *pixmap, GdkBitmap *mask );
void gtk_clist_set_pixtext(clist,row,column,gchar *text,
guint8 spacing, GdkPixmap *pixmap, GdkBitmap *mask);
/* pour les récupérer, pareil avec _get_, et aussi... */
GtkCellType gtk_clist_get_cell_type(clist, row, column );
/* associer un pointeur vers des données à une ligne */
void gtk_clist_set_row_data(clist,row, gpointer data);
void gtk_clist_set_row_data_full(clist, row, data,
GtkDestroyNotify destroy );
gpointer gtk_clist_get_row_data(clist, row);
gint gtk_clist_find_row_from_data(clist, data);
/* changer la sélection en cours */
void gtk_clist_select_row(clist, row, column);
void gtk_clist_unselect_row(clist, row, column);
Les signaux (en plus de ceux de GtkContainer) : select row, unselect row,
click column (voir appendice A du tutorial pour le prototype des callbacks).
28
Widget arbre
/* création d’un GtkTree*/
GtkWidget *gtk_tree_new( void );
/* création d’un GtkTreeItem */
GtkWidget *gtk_tree_item_new_with_label( gchar *label );
/* ajout à l’arbre (un par un... eh oui !) */
void gtk_tree_[append|prepend](tree, tree_item);
void gtk_tree_insert(tree, tree_item, gint position);
/* suppression : détruit aussi les sous-arbres ! */
/* sinon, utiliser gtk_container_remove() */
void gtk_tree_remove_items(tree, GList *items);
void gtk_tree_clear_items( tree, gint start, gint end);
/* ajout d’un sous-arbre sous un TreeItem */
void gtk_tree_item_set_subtree(tree_item, GtkWidget *subtree);
/* comportement vs. selection */
void gtk_tree_set_selection_mode(tree, GtkSelectionMode mode);
Signaux de GtkTree : selection changed, select child, unselect child.
Signaux de GtkTreeItem : ceux de GtkItem (select, deselect, toggle)
+ expand, collapse
29
Widget menu
Deux manières de les créer : utiliser l’itemfactory (facile) ou à la
main (cf. Tutorial).
/* This is the GtkItemFactoryEntry structure used to generate new menus.
Item 1: The menu path. The letter after the underscore indicates an
accelerator key once the menu is open.
Item 2: The accelerator key for the entry
Item 3: The callback function.
Item 4: The callback action. This changes the parameters with
which the function is called. The default is 0.
Item 5: The item type, used to define what kind of an item it is.
Here are the possible values:
NULL
""
"<Title>"
"<Item>"
"<CheckItem>"
"<ToggleItem>"
"<RadioItem>"
<path>
"<Separator>"
"<Branch>"
"<LastBranch>"
->
->
->
->
->
->
->
->
->
->
->
"<Item>"
"<Item>"
create a title item
create a simple item
create a check item
create a toggle item
create a radio item
path of a radio item to link against
create a separator
create an item to hold sub items (optional)
create a right justified branch
*/
static GtkItemFactoryEntry menu_items[] = {
{ "/_File",
NULL,
NULL, 0, "<Branch>" },
{ "/File/_New",
"<control>N", print_hello, 0, NULL },
{ "/File/_Open",
"<control>O", print_hello, 0, NULL },
{ "/File/_Save",
"<control>S", print_hello, 0, NULL },
{ "/File/Save _As", NULL,
NULL, 0, NULL },
{ "/File/sep1",
NULL,
NULL, 0, "<Separator>" },
{ "/File/Quit",
"<control>Q", gtk_main_quit, 0, NULL },
{ "/_Options",
NULL,
NULL, 0, "<Branch>" },
30
{ "/Options/Test",
{ "/_Help",
{ "/_Help/About",
};
NULL,
NULL,
NULL,
NULL, 0, NULL },
NULL, 0, "<LastBranch>" },
NULL, 0, NULL },
void get_main_menu( GtkWidget *window,
GtkWidget **menubar )
{
GtkItemFactory *item_factory;
GtkAccelGroup *accel_group;
gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
accel_group = gtk_accel_group_new ();
/* This function initializes the item factory.
Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
or GTK_TYPE_OPTION_MENU.
Param 2: The path of the menu.
Param 3: A pointer to a gtk_accel_group. The item factory sets up
the accelerator table while generating menus.
*/
item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
accel_group);
/* This function generates the menu items. Pass the item factory,
the number of items in the array, the array itself, and any
callback data for the the menu items. */
gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
/* Attach the new accelerator group to the window. */
gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
if (menubar)
/* Finally, return the actual menu bar created by the item factory. */
*menubar = gtk_item_factory_get_widget (item_factory, "<main>");
}
31
Widget Text
GtkWidget *gtk_text_new( GtkAdjustment *hadj,
GtkAdjustment *vadj );
void gtk_text_set_adjustments(text, hadj, vadj);
/* widget text avec scrollbar : */
vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
gtk_widget_show (vscrollbar);
/* texte éditable ou affichage seulement ? */
void gtk_text_set_editable( GtkText *text,
gboolean editable );
/* retour à la ligne auto */
void gtk_text_set_word_wrap( GtkText *text,
gint
word_wrap );
/* position... */
void gtk_text_set_point( GtkText *text, guint index );
guint gtk_text_get_point( GtkText *text );
guint gtk_text_get_length( GtkText *text );
/* insertion... */
void gtk_text_insert( GtkText
GdkFont
GdkColor
GdkColor
const char
gint
*text,
*font, /* ou NULL */
*fore, /* ou NULL */
*back, /* ou NULL */
*chars,
length );
32
/* eviter la mise à jour automatique */
void gtk_text_freeze( GtkText *text );
void gtk_text_thaw( GtkText *text );
/* delete : retourne TRUE ou FALSE */
gint gtk_text_[backward|forward]_delete(text, nchars);
/* retourne caractère à la position index dans widget t */
GTK_TEXT_INDEX(t, index)
/* retourne une chaine de caracteres extraite. faire g_free() */
gchar *gtk_editable_get_chars( GtkEditable *editable,
start_pos, end_pos [-1 = EOT] );
raccourcis clavier :
–
–
–
–
–
–
–
–
–
–
–
–
–
–
–
–
–
Ctrl-A Beginning of line
Ctrl-E End of line
Ctrl-N Next Line
Ctrl-P Previous Line
Ctrl-B Backward one character
Ctrl-F Forward one character
Alt-B Backward one word
Alt-F Forward one word
Ctrl-H Delete Backward Character (Backspace)
Ctrl-D Delete Forward Character (Delete)
Ctrl-W Delete Backward Word
Alt-D Delete Forward Word
Ctrl-K Delete to end of line
Ctrl-U Delete line
Ctrl-X Cut to clipboard
Ctrl-C Copy to clipboard
Ctrl-V Paste from clipboard
33
Les bibliothèques GNOME
– permettent d’uniformiser le (( look & feel )) des applications ⇒
apprentissage plus rapide
– utilisent GTK+, et y ajoutent quelques widgets
– simplifient la programmation (notion d’application, fichiers de
config...)
– communication entre applications (CORBA), notion de composant logiciel (Bonobo)
– compilation : script gnome-config ou automake
Références :
– Gnome-libs tutorial,par George Lebl <[email protected]>(PDF, PS)
– GTK+/Gnome Application Development,par Havoc Pennington
<[email protected]>(PDF, PS)
– www.gnome.org, developer.gnome.org, cvs.gnome.org/lxr,
news.gnome.org...
34
Gnome Hello
(Extrait du livre de Havoc Pennington)
hello.c :
#include <config.h>
#include <gnome.h>
[...]
/*** gnomehello-popttable */
static int greet_mode = FALSE;
static char* message = NULL;
static char* geometry = NULL;
struct poptOption options[] = {
{"greet", ’g’, POPT_ARG_NONE, &greet_mode, 0,
N_("Say hello to specific people listed on the command line"),NULL},
{"message", ’m’, POPT_ARG_STRING, &message, 0,
N_("Specify a message other than \"Hello, World!\""),N_("MESSAGE")},
{"geometry", ’\0’, POPT_ARG_STRING, &geometry, 0,
N_("Specify the geometry of the main window"), N_("GEOMETRY")},
{NULL, ’\0’, 0, NULL, 0, NULL, NULL}
};
/* gnomehello-popttable ***/
int
main(int argc, char* argv[])
{
/*** gnomehello-parsing */
GtkWidget* app;
poptContext pctx;
char** args;
int i;
GSList* greet = NULL;
GnomeClient* client;
bindtextdomain(PACKAGE, GNOMELOCALEDIR);
textdomain(PACKAGE);
gnome_init_with_popt_table(PACKAGE, VERSION, argc, argv,
35
options, 0, &pctx);
/* Argument parsing */
args = poptGetArgs(pctx);
if (greet_mode && args) {
i = 0;
while (args[i] != NULL) {
greet = g_slist_prepend(greet, args[i]);
++i;
}
/* Put them in order */
greet = g_slist_reverse(greet);
} else if (greet_mode && args == NULL) {
g_error(_("You must specify someone to greet."));
} else if (args != NULL) {
g_error(_("Command line arguments are only allowed with --greet."));
} else {
g_assert(!greet_mode && args == NULL);
}
poptFreeContext(pctx);
/* gnomehello-parsing ***/
/* Session Management */
/*** gnomehello-client */
client = gnome_master_client ();
gtk_signal_connect (GTK_OBJECT (client), "save_yourself",
GTK_SIGNAL_FUNC (save_session), argv[0]);
gtk_signal_connect (GTK_OBJECT (client), "die",
GTK_SIGNAL_FUNC (session_die), NULL);
/* gnomehello-client ***/
/* Main app */
app = hello_app_new(message, geometry, greet);
g_slist_free(greet);
/*** gnomehello-main */
gtk_widget_show_all(app);
gtk_main();
return 0;
/* gnomehello-main ***/
}
/*** gnomehello-save-session */
36
static gint
save_session (GnomeClient *client, gint phase, GnomeSaveStyle save_style,
gint is_shutdown, GnomeInteractStyle interact_style,
gint is_fast, gpointer client_data)
{
gchar** argv;
guint argc;
/* allocate 0-filled, so it will be NULL-terminated */
argv = g_malloc0(sizeof(gchar*)*4);
argc = 1;
argv[0] = client_data;
if (message) {
argv[1] = "--message";
argv[2] = message;
argc = 3;
}
gnome_client_set_clone_command (client, argc, argv);
gnome_client_set_restart_command (client, argc, argv);
return TRUE;
}
/* gnomehello-save-session ***/
/*** gnomehello-session-die */
static gint
session_die(GnomeClient* client, gpointer client_data)
{
gtk_main_quit ();
return TRUE;
}
/* gnomehello-session-die ***/
app.c :
/* Keep a list of all open application windows */
static GSList* app_list = NULL;
GtkWidget*
hello_app_new(const gchar* message,
const gchar* geometry,
GSList* greet)
37
{
GtkWidget*
GtkWidget*
GtkWidget*
GtkWidget*
GtkWidget*
app;
button;
label;
status;
frame;
/*** gnomehello-widgets */
app = gnome_app_new(PACKAGE, _("Gnome Hello"));
frame = gtk_frame_new(NULL);
gtk_window_set_policy(GTK_WINDOW(app), FALSE, TRUE, FALSE);
gtk_window_set_default_size(GTK_WINDOW(app), 250, 350);
gtk_window_set_wmclass(GTK_WINDOW(app), "hello", "GnomeHello");
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
[... on remplit le frame ...]
gnome_app_set_contents(GNOME_APP(app), frame);
status = gnome_appbar_new(FALSE, TRUE, GNOME_PREFERENCES_NEVER);
gnome_app_set_statusbar(GNOME_APP(app), status);
gnome_app_create_toolbar_with_data(GNOME_APP(app), toolbar, app);
gnome_app_create_menus_with_data(GNOME_APP(app), menu, app);
gnome_app_install_menu_hints(GNOME_APP(app), menu);
/* gnomehello-widgets ***/
/*** gnomehello-signals */
gtk_signal_connect(GTK_OBJECT(app),
"delete_event",
GTK_SIGNAL_FUNC(delete_event_cb),
NULL);
gtk_signal_connect(GTK_OBJECT(button),
"clicked",
GTK_SIGNAL_FUNC(button_click_cb),
label);
/* gnomehello-signals ***/
/*** gnomehello-geometry */
if (geometry != NULL) {
gint x, y, w, h;
if ( gnome_parse_geometry( geometry, &x, &y, &w, &h ) ) {
if (x != -1) {
gtk_widget_set_uposition(app, x, y);
}
if (w != -1) {
38
gtk_window_set_default_size(GTK_WINDOW(app), w, h);
}
} else {
g_error(_("Could not parse geometry string ‘%s’"), geometry);
}
}
/* gnomehello-geometry ***/
app_list = g_slist_prepend(app_list, app);
return app;
}
void
hello_app_close(GtkWidget* app)
{
g_return_if_fail(GNOME_IS_APP(app));
app_list = g_slist_remove(app_list, app);
gtk_widget_destroy(app);
if (app_list == NULL) {
/* No windows remaining */
gtk_main_quit();
}
}
/*** gnomehello-quit */
static gint
delete_event_cb(GtkWidget* window, GdkEventAny* e, gpointer data)
{
hello_app_close(window);
/* Prevent the window’s destruction, since we destroyed it
* ourselves with hello_app_close()
*/
return TRUE;
}
/* gnomehello-quit ***/
menus.c :
static GnomeUIInfo file_menu [] = {
39
GNOMEUIINFO_MENU_NEW_ITEM(N_("_New Hello"),
N_("Create a new hello"),
new_app_cb, NULL),
[...]
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_CLOSE_ITEM(close_cb, NULL),
GNOMEUIINFO_MENU_EXIT_ITEM(exit_cb, NULL),
GNOMEUIINFO_END
};
static GnomeUIInfo edit_menu [] = {
GNOMEUIINFO_MENU_CUT_ITEM(nothing_cb, NULL),
[...]
GNOMEUIINFO_END
};
static GnomeUIInfo help_menu [] = {
GNOMEUIINFO_HELP ("gnome-hello"),
GNOMEUIINFO_MENU_ABOUT_ITEM(about_cb, NULL),
GNOMEUIINFO_END
};
static GnomeUIInfo menu [] = {
GNOMEUIINFO_MENU_FILE_TREE(file_menu),
GNOMEUIINFO_MENU_EDIT_TREE(edit_menu),
GNOMEUIINFO_MENU_HELP_TREE(help_menu),
GNOMEUIINFO_END
};
static GnomeUIInfo toolbar [] = {
GNOMEUIINFO_ITEM_STOCK (N_("New"), N_("Create a new hello"),
nothing_cb, GNOME_STOCK_PIXMAP_NEW),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_ITEM_STOCK (N_("Prev"), N_("Previous hello"),
nothing_cb, GNOME_STOCK_PIXMAP_BACK),
GNOMEUIINFO_ITEM_STOCK (N_("Next"), N_("Next hello"),
nothing_cb, GNOME_STOCK_PIXMAP_FORWARD),
GNOMEUIINFO_END
};
static void
new_app_cb(GtkWidget* widget, gpointer data)
40
{
GtkWidget* app;
app = hello_app_new(_("Hello, World!"), NULL, NULL);
gtk_widget_show_all(app);
}
static void
close_cb(GtkWidget* widget, gpointer data)
{
GtkWidget* app;
app = (GtkWidget*) data;
hello_app_close(app);
}
41
Bibliothèque libgnome
Partie non-graphique de GNOME : config, fichiers .desktop, emplacements des
fichiers, types mime, meta-data, sons... Peut-être utilisé avec une autre toolkit
que GTK.
Fichiers de config :
/* lecture d’un fichier de config */
int counter;
char *text;
gboolean def;
...
/* valeur stockée dans ~/.gnome/example/section au champ counter */
counter = gnome_config_get_int_with_default("/example/section/counter=1",
&amp;def);
if(def) g_print("Default used for counter!\n");
text = gnome_config_get_string("/example/section/text=TEXT");
...
g_free(text);
...
/* écriture d’un fichier de config */
char *text;
int counter;
...
/*after we have set text and counter to some values we can
write them to our config location*/
gnome_config_set_int("/example/section/counter",counter);
gnome_config_set_string("/example/section/text",text);
gnome_config_sync();
– Les fonctions gnome config private *() ont le même effet, mais écrivent dans /.gnome private,
protégé en lecture.
– Pour utiliser un fichier arbitraire au format gnome-config, précéder le path de“=fichier=”.
– gnome config clean file efface le fichier au prochain gnome config sync.
42
– gnome config drop file pour libérer la mémoire.
Fichiers .desktop : informations sur les programmes, stockés dans
/usr/share/gnome/apps/, fonctions gnome desktop entry *.
Meta-data : Information associée à un nom de fichier.
/* operation sur un fichier deplacant aussi le meta-data */
gnome_metadata_[rename|copy|delete](const char*file);
/* retournent GNOME_METADATA_[OK|IO_ERROR|NOT_FOUND] */
int gnome_metadata_set(file, char* name, int size, char *data);
int gnome_metadata_get(file, char* name, int *size, char **buffer);
char **gnome_metadata_list(file);
43
GnomeApp
Widget de base de toute application : contient le document, le menu, la toolbar
et les status bars, et conserve leurs positions.
Menu et toolbar : utilisent la structure GnomeUIInfo (cf menu.c) qui permet de definir pour chaque chaque menu ou bouton : pixmap, titre, tooltip,
allélérateur, callback.
Status bar (GnomeAppBar) : sert de status bar et éventuellement de progress bar + donne des infos sur le menu sélectionné. fonctions gnome appbar *
pour modifier le status ou le progress.
Messages : gnome app [message|error|warning] = message / erreur / warning avec confirmation, gnome app flash = bref message clignotant. L’aspect
des messages (dialogue ou non) est réglable avec gnomecc (control-center).
Interactions : Permet de poser une question simple (oui/non, ok/cancel,
chaı̂ne de caractère avec prompt, mot de passe) de manière modale (le reste de
l’app. est bloqué) ou non. gnome app question[ modal], gnome app ok cancel[ modal],
gnome app request [string|password].
static void
really_delete_handler(int reply, gpointer data)
{
GtkWidget *some_widget;
some_widget = GTK_WIDGET(data);
if(reply == 0) {
... /* yes was selected */
}
}
...
/* ask a yes no question, passing some_widget as the data
argument to the handler */
gnome_app_question(GNOME_APP(app),_("Really delete object?"),
really_delete_handler,
some widget);
44
Bibliothèque libgnomeui
Icones en stock : macros GNOME STOCK [PIXMAP|MENU|BUTTON] *. Les utiliser au maximum !
Dialogues génériques : création avec gnome dialog new(), et ne
pas oublier de relier le dialogue à la fenêtre mère (pour le gestionnaire de fenêtres) : gnome dialog set parent (GNOME DIALOG
(dialog), GTK WINDOW(app)). Remplir le dialogue en utilisant
GNOME DIALOG(dialog)->vbox. Ensuite on décide si on veut un
dialogue modal (gnome dialog run and close) ou pas (gnome dialog run
puis gnome dialog close).
Autres : Boı̂te de message (message + icone) gnome message *;
Propriétés (gnome property box *), Apropos (gnome about *).
Champs d’entrée : gnome entry * comme GtkEntry mais avec
gestion d’historique, gnome file entry *, gnome pixmap entry *,
gnome icon entry * (pixmap 48x48), gnome numer entry * avec
calculette.
Images : gnome pixmap new from file sait à peu près tout charger.
Gestion de session : cf hello.c.
Lien web : gnome href new, navigateur réglable par gnomecc.
45
Interface multi-document (MDI)
Permet de gérer de multiples documents pour une application, avec
le choix (par gnomecc) de l’interface : Carnet avec onglets, une fenêtre par document, ou un document à la fois sélectionnable par
menu. Remplacer gnome app new par gnome mdi new, puis...
GtkWidget *mdi;
...
mdi = gnome_mdi_new("gnome-hello-7-mdi", "GNOME MDI Hello");
...
/*main_menu and toolbar_info are the menu and tool-bar
descriptions*/
gnome_mdi_set_menubar_template(mdi, main_menu);
gnome_mdi_set_toolbar_template(mdi, toolbar_info);
/* and document menu and document list paths (see
gnome-app-helper menu insertion routines for details) */
gnome_mdi_set_child_menu_path(GNOME_MDI(mdi), "File");
gnome_mdi_set_child_list_path(GNOME_MDI(mdi), "Children/");
Enfants : le plus simple, utiliser GnomeMDIGenericChild, et stocker
les données dedans (gtk object set data).
GnomeMDI *mdi;
...
GnomeMDIGenericChild *child;
...
/*create a new child named ’name’*/
if((child = gnome_mdi_generic_child_new(name)) != NULL) {
/*creator of a view*/
gnome_mdi_generic_child_set_view_creator
(child, my_child_create_view, NULL);
/*set a menu template for child menu*/
gnome_mdi_child_set_menu_template
(GNOME_MDI_CHILD(child), main_child_menu);
/*set function to get config string*/
46
gnome_mdi_generic_child_set_config_func
(child, my_child_get_config_string, NULL);
/*set function that sets or creates a label*/
gnome_mdi_generic_child_set_label_func
(child, my_child_set_label, NULL);
/* add the child to MDI */
gnome_mdi_add_child(mdi, GNOME_MDI_CHILD(child));
/* and add a new view of the child */
gnome_mdi_add_view(mdi, GNOME_MDI_CHILD(child));
47
GnomeCanvas
/* Exemples d’utilisation : gnumeric, gill. */
GtkWidget *canvas;
...
gtk_widget_push_visual(gdk_imlib_get_visual());
gtk_widget_push_colormap(gdk_imlib_get_colormap());
canvas = gnome_canvas_new();
gtk_widget_pop_visual();
gtk_widget_pop_colormap();
gnome_canvas_set_pixels_per_unit(canvas,10);
gnome_canvas_set_scroll_region(canvas,0.0,0.0,50.0,50.0);
GnomeCanvasItem *item;
...
/* arguments : cf libgnomeui/gnome-canvas*.h */
item = gnome_canvas_item_new(gnome_canvas_root(canvas),
GNOME_TYPE_CANVAS_RECT,
"x1", 1.0, "y1", 1.0,
"x2", 23.0, "y2", 20.0,
"fill_color", "black",
NULL);
...
gnome_canvas_item_set(item"fill_color", "red", NULL);
/* canvas avec anti-aliasing, n’utilise pas Xlib */
GtkWidget *canvas;
...
gtk_widget_push_visual (gdk_rgb_get_visual ());
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
canvas = gnome_canvas_new_aa ();
gtk_widget_pop_colormap ();
gtk_widget_pop_visual ();
48