Introduction `aGTK

Fr´ed´eric Devernay [email protected]

8 novembre 1999

R´esum´e

Nous verrons ’abord l’organisation g´en´erale de GTK et de GNOME. Nous d´etaillerons ensuite l’utilisation de la biblio- th`eque de portabilit´e GLib, puis quelques exemples d’utilisa- tion de GTK. Pourquoi GNOME et GTK? – Parce que GTK ne d´epend pas du langage utilis´e (= ), 6 est portable et extensible, et que le source est disponible. – Parce que GNOME est bas´e sur des concepts largement r´epandus dans l’industrie (CORBA, XML), mais peu en- seign´es. – Et en plus ’est beau ! (th`emes, etc.) L’architecture logicielle de GTK/GNOME

La hi´erarchie des biblioth`equesde GNOME

– Les biblioth`eques GNOME sont haut niveau (notion d’applica- tion, fichiers de config...) – GTK+ est compos´e de GTK () et GDK (primitives de dessin bas niveau) – GLib est une biblioth`eque de portabilit´e (types, fonctions stan- dard) et d’utilitaires (listes, tables de hachage, ...)

1 Les biblioth`equesGNOME

– libgnome : utilitaires ind´ependants de la toolkit ; – libgnomeui : ... dependants de la toolkit (combos, ...) ; – libgnorba : utilisation de corba, via ORBit ; – -xmhtml : widget HTML pour GTK ; – xvt : widget d’´emulation de terminal ; – libvfs : file syst`eme virtuel utilis´e dans Midnight Commander ; – libart lgpl : biblioth`eque graphique avec anti-aliasing.

Mais commen¸cons par le d´ebut : GLib, puis GTK, puis GNOME.

Caract´eristique commune de toutes ces biblioth`eques : 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´ees et commencent par G (GHashTable).

Typedefs :

– gint8 : entier sign´e8 bits – guint8 : entier non sign´e8 bits – ... gint16, guint16, gint32, guint32, gint64 et guint64 (dispo si G HAVE GINT64 est d´efini), gchar, guchar, gshort, gushort, glong, gulong, gint, guint, gfloat, gdouble, gboolean (en fait un int, prend les valeurs TRUE ou FALSE), gpointer (= void *), gconstpoin- ter (= const void *)

Portabilit´eet Utilitaires :

– gchar* g strdup (const gchar*) = stdup() – g malloc, g free – void g usleep (gulong count) suspend l’ex´ecutionpendant ’count’ microsecondes – g snprintf = snprintf `autiliser pour raisons ´eviterles ’buffer over- flows’ (s´ecurit´e++) – g new(type,count) (= (type) g malloc(count*sizeof(type))), g new0 id. mais met `az´ero – gchar* g strconcat (const gchar *str, ..., NULL) concat`eneles chaˆınesen param`etres(alloue une nouvelle chaˆıne) – g strdup printf comme un sprintf, mais alloue la chaˆıne – g strstrip coupe les espaces au d´ebutet `ala fin d’une chaˆıne, n’alloue pas, ne d´esallouepas

3 GLib : Les containers

– GList : liste doublement chaˆın´ee – GSList : liste simplement chaˆın´ee – GHashTable : table de hachage – GCache : cache – GTree : arbre binaire ´equilibr´e – GNode : arbre n-aire – GString : chaˆınede caract`eresde 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 `alist. list peut ˆetreNULL (cr´eation) – g list prepend, g list remove, g list find, g list next, g list previous, g list free (ne lib`erepas les data !) Chaˆınesde caract`eres

/* 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 conver- sion portables... mˆemesous MSWindows (/usr/lib/glib/include/glibconfig.h).

4 GTK : introduction

– Il existe des interfaces C++ (GTK–), python (pyGTK), (perlGTK), ..., mais nous allons utiliser l’interface C (les autres lui ressemblent). – GTK+ est ´ecrit en C orient´e-objet : impl´emente les notions de classe, d’h´eritage (simple), de m´ethodes virtuelles, de typage fort (`a l’ex´ecution) et de fonctions de rappel (callbacks).

Premier exemple : affiche une fenˆetre 200x200

#include 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´eeune fen^etreet l’affiche */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_show (window);

/* boucle d’´ev`enements*/ gtk_main ();

return 0; }

5 GTK : Bonjour tout le monde

#include

/* fonction de rappel. Dans cet exemple, les param`etressont ignor´es... * Les fonctions de rappel sont d´etaill´eesplus 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 ´emettrale signal "destroy". Retourner FALSE signifie que l’on * ne veut pas que la fen^etresoit d´etruite. * Utilis´epour faire appara^ıtredes bo^ıtesde dialogue du type * (( Etes-vous^ s^urde vouloir quitter ? )) */

/* Remplacez FALSE par TRUE et la fen^etreprincipale sera d´etruitepar * 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´eclarerles widgets. */

GtkWidget *window; GtkWidget *button;

/* Cette fonction est appel´eedans toutes les applications GTK. * Les param`etrespass´esen ligne de commande sont analys´eset * retourn´es`al’application. */ gtk_init (&argc, &argv);

/* Cr´eationd’une nouvelle fen^etre.*/ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

/* Lorsque la fen^etrere¸coitle signal "delete_event" * (envoy´epar le gestionnaire de fen^etresen utilisant l’option * (( close )) ou la barre de titre), on lui demande d’appeler la * fonction delete_event() d´efinieplus haut. La donn´eepass´eeen * param`etre`ala fonction de rappel est NULL et est ignor´edans le * rappel. */ gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL);

/* Ici, on connecte l’´evenement"destroy" `aun gestionnaire de signal. * Cet ´ev´enementarrive 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´eationd’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´efinieplus haut en lui passant NULL en param`etre.*/

gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (hello), NULL);

/* Ceci provoquera la destruction de la fen^etrepar appel de la * fonction gtk_widget_destroy(window) lors du signal "clicked". * Le signal de destruction pourrait venir de l`a,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’´etapefinale consiste `aafficher 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´eroulementdu programme se termine l`aet attend qu’un * ´ev´enementsurvienne (touche press´eeou ´ev´enementsouris). */

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´eorie des signaux et rappels

GTK est dirig´e par les ´ev´enements : il reste dans gtk main() jusqu’`a ce qu’un ´ev´enement 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 ´emet- teur */ gchar *name, /* nom du signal */ GtkSignalFunc func, /* fctn de rap- pel */ gpointer func_data ); /* donn´ees*/ /* d´econnectele signal */ void gtk_signal_disconnect( GtkObject *object, gint id ); /* d´econnectetous les signaux */ void gtk_signal_handlers_destroy( GtkObject *object );

La fonction de rappel a (en g´en´eral) la forme : void callback_func( GtkWidget *widget, /* widget ´emetteur*/ gpointer callback_data ); /* donn´ees*/

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 : ´ev´enements 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 /* Depre- cated, use filters instead */ }

/* Connection d’un ´ev´enementvers 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´elior´e

#include

/* Notre nouveau rappel am´elior´e.La donn´eepass´ee`acette fonction est * imprim´eesur stdout. */ void rappel (GtkWidget *widget, gpointer *data) { g_print ("Re-Bonjour - %s a ´et´epress´e\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´eclarerles widgets */

GtkWidget *window; GtkWidget *button; GtkWidget *box1;

/* Cette fonction est appel´eedans toutes les applications GTK. * Les param`etrepass´esen ligne de commande sont analys´eset * retourn´es`al’application. */

gtk_init (&argc, &argv);

/* Cr´eationd’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´ediatementGTK. */ 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´eationd’une bo^ıtepour y placer les widgets. * Ceci est d´ecriten d´etailsplus loin dans la section * (( placement )). La bo^ıten’est pas mat´erialis´ee,elle est juste * utilis´eecomme moyen d’arranger les widgets. */ box1 = gtk_hbox_new(FALSE, 0);

/* On met la bo^ıtedans la fen^etreprincipale. */ gtk_container_add (GTK_CONTAINER (window), box1);

/* On cr´eeun nouveau bouton portant le label (( Bouton 1 )). */ button = gtk_button_new_with_label ("Bouton 1");

/* Lorsque le bouton est cliqu´e,on appelle la fonction (( rappel )) * avec un pointeur sur la cha^ıne (( Bouton 1 )) comme param`etre.*/ 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^ıteinvisible qui a ´et´eplac´eedans la fen^etre.*/ gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);

/* N’oubliez jamais cette ´etapequi indique `aGTK que la configuration

12 * de ce bouton est termin´eeet qu’il peut ^etreaffich´e.*/

gtk_widget_show(button);

/* On fait la m^emechose pour cr´eerun deuxi`emebouton. */

button = gtk_button_new_with_label ("Bouton 2");

/* On appelle la m^emefonction de rappel avec un param`etrediff´erent, * 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´ef´erabled’afficher la fen^etreen 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^etecommence ! */

gtk_main ();

return 0; }

– Utilise le placement des widgets, cf. gtk box pack start(). – gtk window new(GTK WINDOW ) cr´ee 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 `a nrows, colonnes de 0 `a ncolumns. homogeneous = boˆıtes prennent la taille du plus grand widget. Cr´eation 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 `aplacer */ 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’´elargit pour occuper tte la case), GTK SHRINK (les widgets sont r´eduits plutˆot que descendus lors d’un redimensionnement), GTK EXPAND (la table utilise tout l’espace restant dans la fenˆetre).

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`esune 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

E´tapes de la cr´eation d’un widget GTK :

1. gtk * new() 2. Connexion des signaux voulus avec les gestionnaires ad´equats 3. Placement dans un container/une boˆıte/une table 4. Cr´eer/afficher les widgets fils 5. Affichage : gtk widget show() gtk widget hide() fait disparaˆıtre un widget

Conversions de types (avec v´erification), pour obtenir le type requis par la d´eclaration de la fonction :

– GTK WIDGET(widget) – GTK OBJECT(object) – GTK SIGNAL FUNC(function) – GTK CONTAINER(container) – GTK WINDOW(window) – GTK BOX(box)

17 Hi´erarchie de classes des widgets

GtkObject | | | ‘GtkViewport +GtkWidget | | +GtkBox * | +GtkMisc | | | +GtkButtonBox | | +GtkLabel * | | | | +GtkHButtonBox | | | +GtkAccelLabel | | | | ‘GtkVButtonBox | | | ‘GtkTipsQuery | | | +GtkVBox * | | +GtkArrow * | | | | +GtkColorSelection | | +GtkImage * | | | | ‘GtkGammaCurve | | ‘GtkPixmap * | | | ‘GtkHBox * | +GtkContainer | | | +GtkCombo | | +GtkBin * | | | ‘GtkStatusbar | | | +GtkAlignment * | | +GtkCList | | | +GtkFrame * | | | ‘GtkCTree | | | | ‘GtkAspectFrame * | | +GtkFixed | | | +GtkButton | | +GtkNotebook | | | | +GtkToggleButton | | | ‘GtkFontSelection | | | | | ‘GtkCheckButton | | +GtkPaned | | | | | ‘GtkRadioButton | | | +GtkHPaned | | | | ‘GtkOptionMenu | | | ‘GtkVPaned | | | +GtkItem * | | +GtkLayout | | | | +GtkMenuItem | | +GtkList | | | | | +GtkCheckMenuItem | | +GtkMenuShell | | | | | | ‘GtkRadioMenuItem | | | +GtkMenuBar | | | | | ‘GtkTearoffMenuItem | | | ‘GtkMenu | | | | +GtkListItem | | +GtkPacker | | | | ‘GtkTreeItem | | +GtkSocket | | | +GtkWindow | | +GtkTable * | | | | +GtkColorSelectionDialog | | +GtkToolbar | | | | +GtkDialog | | ‘GtkTree | | | | | ‘GtkInputDialog | +GtkCalendar | | | | +GtkDrawWindow | +GtkDrawingArea | | | | +GtkFileSelection | | ‘GtkCurve | | | | +GtkFontSelectionDialog | +GtkEditable | | | | ‘GtkPlug | | +GtkEntry | | | +GtkEventBox | | | ‘GtkSpinButton | | | +GtkHandleBox | | ‘GtkText | | | +GtkScrolledWindow * | +GtkRuler

18 | | +GtkHRuler | ‘GtkProgress | | ‘GtkVRuler | ‘GtkProgressBar | +GtkRange +GtkData | | +GtkScale | +GtkAdjustment | | | +GtkHScale | ‘GtkTooltips | | | ‘GtkVScale ‘GtkItemFactory | | ‘GtkScrollbar | | +GtkHScrollbar | | ‘GtkVScrollbar | +GtkSeparator * (*): Widgets sans fenˆetres,doivent ˆetreenglo- | | +GtkHSeparator * b´esdans une GtkEventBox si on veut capturer | | ‘GtkVSeparator * | +GtkPreview leur ´ev´enements.

Une bonne doc sur les widgets et leur utilisation : le programme testgtk.c

19 Boutons

Boutons normaux : deux possibilit´es pour les cr´eer,

1. gtk button new with label() 2. gtk button new(), mettre l’int´erieur 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 `acocker : (toggle buttons & check buttons) ´emettent le signal“toggled”

GtkWidget* gtk_toggle_button_new (void); GtkWidget* gtk_toggle_button_new_with_label (gchar *label); GtkWidget* gtk_check_button_new (void); GtkWidget* 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´e.*/ } else { /* le bouton est enfonc´e*/ } }

/* configuration du bouton, ´emet"clicked" si changement */ void gtk_toggle_button_set_active (GtkToggleButton *toggle_button, gint state); /*_set_state en GTK 1.0 */

/* change l’´etatet ´emet"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´eele 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´eglage )) (scrollbar, valeur ajustable, bouton de r´eglage)`aun widget utilisant les valeurs correspondantes (zone de text, viewport) pour afficher, par ex., une zone de donn´ees.

GtkAdjustment : Stocke la valeur concern´eeet les intervalles autoris´es,peut ´emettredes signaux lorsque la valeur ou les intervalles sont chang´es.

GtkObject *gtk_adjustment_new( gfloat value, gfloat lower, /* intervalle */ gfloat upper, /* autoris´e*/ gfloat step_increment, /* petit/ */ gfloat page_increment, /* grand incr´ement*/ gfloat page_size ); /* taille zone visible */

Utilisation facile : text = gtk_text_new (NULL, NULL); vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);

Changement de valeur (( `ala main )) : void gtk_adjustment_set_value( GtkAdjustment *adjustment, gfloat value ); l’ajustement ´emetle 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ˆeme, lorsque les champs“upper”ou“lower”sont chang´es,le signal“change- d”est ´emis. S’ils sont chang´es`ala main, utiliser gtk signal emit by name(GTK OBJECT (adjustment),“changed”).

22 Intervalles

Scale ou ScrollBar :

/* adj=NULL pour en cr´eerun 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´ecimales`aafficher */ void gtk_scale_set_digits(GtkScale *scale, gint digits);

/* endroit o`uafficher la valeur */ /* pos = GTK_POS_[LEFT|RIGHT|TOP|BOTTOM] */ void gtk_scale_set_value_pos(GtkScale *scale, GtkPositionType pos); Fonctionnalit´escommunes :

/* quand faut-il ´emettrele signal "changed" ? */ /* policy=GTK_UPDATE_POLICY_CONTINUOUS -`achaque 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´ecup´erer/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`echeshaut/bas (1 step), PgUp/PgDwn (1page) – intervalles horizontaux : fl`echesgauche/droite (1 step), Home (d´ebut),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`eches – Bulles d’aide – Barres de progression – Dialogues – Pixmaps – R`egles – Barres d’´etat – Entr´ees de texte – Boutons rotatifs – Boˆıte combo – S´election de couleurs – S´election de fichiers

24 Widgets conteneurs

Event Box : permet d’associer des ´ev`enements`aun widget sans fenˆetre,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) `al’int´erieurde sa fenˆetre.

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 `aune position pr´eciseen pixels. Le conteneur d’arrangement impl´ementeune zone quasi- infinie, qui peut ˆetrescroll´ee.De plus, il se redessine (se met `ajour) tout seul quand ses valeurs sont chang´ees.

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 `ajour */ void gtk_layout_freeze( GtkLayout *layout ); void gtk_layout_thaw( GtkLayout *layout );

/* positionner/r´ecup´ererles 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,´eventuel- lement ´etiquet´ee.Les cadres d’aspect (aspect frame) permettent en plus de conserver l’aspect (largeur/hauteur) du widget fils.

Fenˆetrescoulissantes : (panned window) Fenˆetredivis´eeen deux zones s´e- par´eespar une ligne dont la position est r`eglable.

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ˆotscrolled window. Diff´erenceavec layout?

Scrolled Windows : Un viewport avec des scrollbars.

Boˆıtesde boutons : (button boxes) pour grouper facilement des boutons.

Barre d’outils : (toolbar) Permet typiquement de ranger ensemble des bou- tons avec des icones, du texte, et des bulles d’aide, dont l’aspeces t global peut ˆetrechang´efacilement (barre de navigation netscape).

Bloc-notes : (notebook) Collection de pages superpos´ees,avec des onglets pour les s´electionner(pr´ef´erenceswindows...).

26 Widget CList

Liste multi-colonnes pouvant g´erer des milliers de colonnes, avec un titre ´eventuellement actif (`a la netscape Mail/News). Doit ˆetre plac´e 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 ˆetrerendus actifs (comme des boutons) ou passifs (comme des labels), ˆetremontr´esou cach´es,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´eglagesdes param`etresde la clist : gtk clist set column justification(), gtk clist- set column width(), gtk clist set row height(), gtk clist set foreground(), gtk clist set background().

27 Tester si une ligne est visible enti`erementou partiellement : gtk clist row is visible(). Aller `aune ligne/colonne : gtk clist moveto().

/* Ajouter au d´ebut/ `ala fin / ins´ererune 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´eactiverles mises `ajour 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´ecup´erer,pareil avec _get_, et aussi... */ GtkCellType gtk_clist_get_cell_type(clist, row, column );

/* associer un pointeur vers des donn´ees`aune 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´electionen 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´eationd’un GtkTree*/ GtkWidget *gtk_tree_new( void );

/* cr´eationd’un GtkTreeItem */ GtkWidget *gtk_tree_item_new_with_label( gchar *label );

/* ajout `al’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´etruitaussi 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`eres de les cr´eer : utiliser l’itemfactory (facile) ou `a 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 -> "" "" -> "" "" -> create a title item "<Item>" -> create a simple item "<CheckItem>" -> create a check item "<ToggleItem>" -> create a toggle item "<RadioItem>" -> create a radio item <path> -> path of a radio item to link against "<Separator>" -> create a separator "<Branch>" -> create an item to hold sub items (optional) "<LastBranch>" -> 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>" },</p><p>30 { "/Options/Test", NULL, NULL, 0, NULL }, { "/_Help", NULL, NULL, 0, "<LastBranch>" }, { "/_Help/About", NULL, 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]);</p><p> accel_group = gtk_accel_group_new ();</p><p>/* 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. */</p><p> item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group);</p><p>/* 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);</p><p>/* Attach the new accelerator group to the window. */ gtk_accel_group_attach (accel_group, GTK_OBJECT (window));</p><p> if (menubar) /* Finally, return the actual menu bar created by the item factory. */ *menubar = gtk_item_factory_get_widget (item_factory, "<main>"); }</p><p>31 Widget Text</p><p>GtkWidget *gtk_text_new( GtkAdjustment *hadj, GtkAdjustment *vadj ); void gtk_text_set_adjustments(text, hadj, vadj);</p><p>/* 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);</p><p>/* texte ´editableou affichage seulement ? */ void gtk_text_set_editable( GtkText *text, gboolean editable );</p><p>/* retour `ala ligne auto */ void gtk_text_set_word_wrap( GtkText *text, gint word_wrap );</p><p>/* position... */ void gtk_text_set_point( GtkText *text, guint index ); guint gtk_text_get_point( GtkText *text ); guint gtk_text_get_length( GtkText *text );</p><p>/* insertion... */ void gtk_text_insert( GtkText *text, GdkFont *font, /* ou NULL */ GdkColor *fore, /* ou NULL */ GdkColor *back, /* ou NULL */ const char *chars, gint length );</p><p>32 /* eviter la mise `ajour automatique */ void gtk_text_freeze( GtkText *text ); void gtk_text_thaw( GtkText *text );</p><p>/* delete : retourne TRUE ou FALSE */ gint gtk_text_[backward|forward]_delete(text, nchars);</p><p>/* retourne caract`ere`ala position index dans widget t */ GTK_TEXT_INDEX(t, index)</p><p>/* retourne une chaine de caracteres extraite. faire g_free() */ gchar *gtk_editable_get_chars( GtkEditable *editable, start_pos, end_pos [-1 = EOT] ); raccourcis clavier :</p><p>– 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</p><p>33 Les biblioth`equesGNOME</p><p>– 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 compo- sant logiciel (Bonobo) – compilation : script gnome-config ou automake</p><p>R´ef´erences:</p><p>– Gnome-libs tutorial,par George Lebl <jirka@5z.com>(PDF, PS) – GTK+/Gnome Application Development,par Havoc Pennington <hp@pobox.com>(PDF, PS) – www.gnome.org, developer.gnome.org, cvs.gnome.org/lxr, news.gnome.org...</p><p>34 Gnome Hello</p><p>(Extrait du livre de Havoc Pennington) hello.c :</p><p>#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;</p><p> bindtextdomain(PACKAGE, GNOMELOCALEDIR); textdomain(PACKAGE); gnome_init_with_popt_table(PACKAGE, VERSION, argc, argv,</p><p>35 options, 0, &pctx);</p><p>/* 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 ***/</p><p>/* 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 ***/</p><p>/* 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 ***/ }</p><p>/*** gnomehello-save-session */</p><p>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;</p><p>/* 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);</p><p> return TRUE; } /* gnomehello-save-session ***/</p><p>/*** gnomehello-session-die */ static gint session_die(GnomeClient* client, gpointer client_data) { gtk_main_quit (); return TRUE; } /* gnomehello-session-die ***/ app.c :</p><p>/* Keep a list of all open application windows */ static GSList* app_list = NULL;</p><p>GtkWidget* hello_app_new(const gchar* message, const gchar* geometry, GSList* greet)</p><p>37 { GtkWidget* app; GtkWidget* button; GtkWidget* label; GtkWidget* status; GtkWidget* frame;</p><p>/*** 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 ***/</p><p>/*** 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 ***/</p><p>/*** 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) {</p><p>38 gtk_window_set_default_size(GTK_WINDOW(app), w, h); } } else { g_error(_("Could not parse geometry string ‘%s’"), geometry); } } /* gnomehello-geometry ***/</p><p> app_list = g_slist_prepend(app_list, app);</p><p> 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(); } }</p><p>/*** gnomehello-quit */ static gint delete_event_cb(GtkWidget* window, GdkEventAny* e, gpointer data) { hello_app_close(window);</p><p>/* Prevent the window’s destruction, since we destroyed it * ourselves with hello_app_close() */ return TRUE; } /* gnomehello-quit ***/ menus.c : static GnomeUIInfo file_menu [] = {</p><p>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)</p><p>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); }</p><p>41 Biblioth`equelibgnome</p><p>Partie non-graphique de GNOME : config, fichiers .desktop, emplacements des fichiers, types mime, meta-data, sons... Peut-ˆetreutilis´eavec une autre toolkit que GTK. Fichiers de config :</p><p>/* lecture d’un fichier de config */ int counter; char *text; gboolean def; ... /* valeur stock´eedans ~/.gnome/example/section au champ counter */ counter = gnome_config_get_int_with_default("/example/section/counter=1", &def); if(def) g_print("Default used for counter!\n"); text = gnome_config_get_string("/example/section/text=TEXT"); ... g_free(text);</p><p>... /* ´ecritured’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();</p><p>– Les fonctions gnome config private *() ont le mˆemeeffet, mais ´ecriventdans /.gnome private, prot´eg´een lecture. – Pour utiliser un fichier arbitraire au format gnome-config, pr´ec´ederle path de“=fichier=”. – gnome config clean file efface le fichier au prochain gnome config sync.</p><p>42 – gnome config drop file pour lib´ererla m´emoire.</p><p>Fichiers .desktop : informations sur les programmes, stock´es dans /usr/share/gnome/apps/, fonctions gnome desktop entry *.</p><p>Meta-data : Information associ´ee `a un nom de fichier.</p><p>/* operation sur un fichier deplacant aussi le meta-data */ gnome_metadata_[rename|copy|delete](const char*file);</p><p>/* 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);</p><p> char **gnome_metadata_list(file);</p><p>43 GnomeApp</p><p>Widget de base de toute application : contient le document, le menu, la toolbar et les status bars, et conserve leurs positions.</p><p>Menu et toolbar : utilisent la structure GnomeUIInfo (cf menu.c) qui per- met de definir pour chaque chaque menu ou bouton : pixmap, titre, tooltip, all´el´erateur,callback.</p><p>Status bar (GnomeAppBar) : sert de status bar et ´eventuellementde pro- gress bar + donne des infos sur le menu s´electionn´e.fonctions gnome appbar * pour modifier le status ou le progress.</p><p>Messages : gnome app [message error warning] = message / erreur / war- ning avec confirmation, gnome app| flash| = bref message clignotant. L’aspect des messages (dialogue ou non) est r´eglableavec gnomecc (control-center).</p><p>Interactions : Permet de poser une question simple (oui/non, ok/cancel, chaˆınede caract`ereavec prompt, mot de passe) de mani`eremodale (le reste de l’app. est bloqu´e)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);</p><p>44 Biblioth`equelibgnomeui</p><p>Icones en stock : macros GNOME STOCK [PIXMAP MENU - | | BUTTON] *. Les utiliser au maximum !</p><p>Dialogues g´en´eriques: cr´eation avec gnome dialog new(), et ne pas oublier de relier le dialogue `a la fenˆetre m`ere (pour le gestion- naire de fenˆetres) : gnome dialog set parent (GNOME DIALOG (dialog), GTK WINDOW(app)). Remplir le dialogue en utilisant GNOME DIALOG(dialog)->vbox. Ensuite on d´ecide si on veut un dialogue modal (gnome dialog run and close) ou pas (gnome dialog run puis gnome dialog close).</p><p>Autres : Boˆıte de message (message + icone) gnome message *; Propri´et´es (gnome property box *), Apropos (gnome about *).</p><p>Champs d’entr´ee: 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.</p><p>Images : gnome pixmap new from file sait `a peu pr`es tout char- ger.</p><p>Gestion de session : cf hello.c.</p><p>Lien web : gnome href new, navigateur r´eglable par gnomecc.</p><p>45 Interface multi-document (MDI)</p><p>Permet de g´erer de multiples documents pour une application, avec le choix (par gnomecc) de l’interface : Carnet avec onglets, une fe- nˆetre par document, ou un document `a la fois s´electionnable par menu. Remplacer gnome app new par gnome mdi new, puis...</p><p>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);</p><p>/* 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/");</p><p>Enfants : le plus simple, utiliser GnomeMDIGenericChild, et stocker les donn´ees dedans (gtk object set data).</p><p>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*/</p><p>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);</p><p>/* add the child to MDI */ gnome_mdi_add_child(mdi, GNOME_MDI_CHILD(child));</p><p>/* and add a new view of the child */ gnome_mdi_add_view(mdi, GNOME_MDI_CHILD(child));</p><p>47 GnomeCanvas</p><p>/* 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);</p><p>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);</p><p>/* canvas avec anti-aliasing, n’utilise pas <a href="/tags/Xlib/" rel="tag">Xlib</a> */ 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 ();</p><p>48</p> </div> </article> </div> </div> </div> <script type="text/javascript" async crossorigin="anonymous" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8519364510543070"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> var docId = '7e08912047cddd96609648ab5a4fab23'; var endPage = 1; var totalPage = 49; var pfLoading = false; window.addEventListener('scroll', function () { if (pfLoading) return; var $now = $('.article-imgview .pf').eq(endPage - 1); if (document.documentElement.scrollTop + $(window).height() > $now.offset().top) { pfLoading = true; endPage++; if (endPage > totalPage) return; var imgEle = new Image(); var imgsrc = "//data.docslib.org/img/7e08912047cddd96609648ab5a4fab23-" + endPage + (endPage > 3 ? ".jpg" : ".webp"); imgEle.src = imgsrc; var $imgLoad = $('<div class="pf" id="pf' + endPage + '"><img src="/loading.gif"></div>'); $('.article-imgview').append($imgLoad); imgEle.addEventListener('load', function () { $imgLoad.find('img').attr('src', imgsrc); pfLoading = false }); if (endPage < 7) { adcall('pf' + endPage); } } }, { passive: true }); </script> <script> var sc_project = 11552861; var sc_invisible = 1; var sc_security = "b956b151"; </script> <script src="https://www.statcounter.com/counter/counter.js" async></script> </html><script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>