Aller au contenu

Programmation GTK/Pixmaps

Un livre de Wikilivres.


Les pixmaps sont des structures de données contenant des images. Celles-ci peuvent être utilisées à différents endroits, mais le plus souvent comme icônes dans le bureau X Window. Un bitmap est un pixmap de 2 couleurs.

Pour utiliser des pixmaps avec GTK, on doit d'abord construire une structure GdkPixmap en utilisant les fonctions de la couche GDK. Les pixmaps peuvent soit être créés à partir de données en memoire, ou à partir de données lues dans un fichier. Nous utiliserons chacun des appels pour créer un pixmap.

 GdkPixmap *gdk_bitmap_create_from_data(GdkWindow *window,
                                        gchar     *data,
                                        gint      width,
                                        gint      height );

Cette fonction sert à créer un pixmap mono-plan (2 couleurs) à partir de données en mémoire. Chaque bit de la donnée data. width et height sont exprimés en pixels. Le pointeur vers un GdkWindow pointe sur la fenêtre courante car les ressources d'un pixmap n'ont de signification que dans le contexte de l'écran où il doit s'afficher.

 GdkPixmap* gdk_pixmap_create_from_data(GdkWindow *window,
                                        gchar      *data,
                                        gint        width,
                                        gint        height,
                                        gint        depth,
                                        GdkColor   *fg,
                                        GdkColor   *bg );

Cette fonction est utilisée pour créer un pixmap d'une profondeur donnée (nombre de couleurs) à partir de la donnée spécifiée pas data. fg et bg sont les couleurs à utiliser pour l'avant et l'arrière-plan.

 GdkPixmap* gdk_pixmap_create_from_xpm(GdkWindow *window,
                                       GdkBitmap **mask,
                                       GdkColor   *transparent_color,
                                       const gchar *filename );

Le format XPM est une représentation des pixmaps reconnue par le système X Window. Il est largement utilisé et de nombreux utilitaires pour créer des fichiers d'images à ce format sont disponibles. Le fichier filename doit contenir une image dans ce format qui sera chargée dans la structure pixmap. Le masque mask indique quels sont les bits opaques du pixmap. Tous les autres bits sont colorisés en utilisant la couleur spécifiée par transparent_color. Un exemple d'utilisation est présenté ci-dessous.

 GdkPixmap* gdk_pixmap_create_from_xpm_d(GdkWindow *window,
                                         GdkBitmap **mask,
                                         GdkColor   *transparent_color,
                                         gchar     **data);

De petites images peuvent être intégrées dans un programme sous la forme de données data au format XPM. Un pixmap est créé en utilisant ces données au lieu de les lire dans un fichier. Un exemple de telles données est :

 /* XPM */
 static const char * xpm_data[] = {
 "16 16 3 1",
 " c None",
 ". c #000000000000",
 "X c #FFFFFFFFFFFF",
 " ",
 " ...... ",
 " .XXX.X. ",
 " .XXX.XX. ",
 " .XXX.XXX. ",
 " .XXX..... ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " ......... ",
 " ",
 " "};

 void gdk_pixmap_destroy( GdkPixmap *pixmap );

Lorsqu'on a utilisé un pixmap et que l'on en a plus besoin tout de suite, il est préférable de libérer la ressource en utilisant un appel à gdk_pixmap_destroy. Les pixmaps doivent être considérées comme une ressource précieuse.

Quand le pixmap est créé, on peut l'afficher comme un widget GTK. On doit créer un widget pixmap qui contiendra le pixmap GDK. Ceci est réalisé de la façon suivante :

 GtkWidget* gtk_pixmap_new(GdkPixmap *pixmap,
                           GdkBitmap  *mask );

Les autres fonctions pour les widgets pixmap sont :

 guint gtk_pixmap_get_type( void );
 void gtk_pixmap_set( GtkPixmap *pixmap,
                      GdkPixmap  *val,
                      GdkBitmap  *mask);
 void gtk_pixmap_get( GtkPixmap *pixmap,
                      GdkPixmap **val,
                      GdkBitmap **mask);

gtk_pixmap_set sert à changer le pixmap pris en charge par le widget. val est le pixmap créé par le GDK.

Voici un exemple illustrant l'utilisation d'un pixmap dans un bouton :

 #include <gtk/gtk.h>
 
 /* données XPM d'une icône "Ouvrir fichier" */
 static const char * xpm_data[] = {
 "16 16 3 1",
 " c None",
 ". c #000000000000",
 "X c #FFFFFFFFFFFF",
 " ",
 " ...... ",
 " .XXX.X. ",
 " .XXX.XX. ",
 " .XXX.XXX. ",
 " .XXX..... ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " .XXXXXXX. ",
 " ......... ",
 " ",
 " "};

 /* Termine l'application lorsqu'elle est appelée 
  * via le signal "delete_event" */
 
 void close_application( GtkWidget *widget, GdkEvent *event, gpointer *data ) 
 {
    gtk_main_quit();
 }

 /* Invoquée lorsque le bouton est cliqué. Affiche simplement 
  * un message. */

 void button_clicked( GtkWidget *widget, gpointer *data ) 
 {
    printf( "bouton cliqué\n" );
 }

 int main( int argc, char *argv[] )
 {
    /* GtkWidget est le type pour déclarer les widgets */
 
    GtkWidget *window, *pixmapwid, *button;
    GdkPixmap *pixmap;
    GdkBitmap *mask;
    GtkStyle *style;
     
    /* Crée la fenêtre principale et attache le signal "delete_event" pour 
     * terminer l'application */
 
    gtk_init( &argc, &argv );
    window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
    gtk_signal_connect( GTK_OBJECT (window), "delete_event",
                        GTK_SIGNAL_FUNC (close_application), NULL );
    gtk_container_border_width( GTK_CONTAINER (window), 10 );
    gtk_widget_show( window );
 
    /* Utilisation de GDK pour créer le pixmap */
 
    style = gtk_widget_get_style( window );
    pixmap = gdk_pixmap_create_from_xpm_d( window->window,  &mask,
                                           &style->bg[GTK_STATE_NORMAL],
                                           (gchar **)xpm_data );
 
    /* Création d'un widget pixmap GTK pour contenir le pixmap GDK */
 
    pixmapwid = gtk_pixmap_new( pixmap, mask );
    gtk_widget_show( pixmapwid );
 
    /* Création d'un bouton pour contenir le widget pixmap */
 
    button = gtk_button_new();
    gtk_container_add( GTK_CONTAINER(button), pixmapwid );
    gtk_container_add( GTK_CONTAINER(window), button );
    gtk_widget_show( button );
 
    gtk_signal_connect( GTK_OBJECT(button), "clicked",
                        GTK_SIGNAL_FUNC(button_clicked), NULL );
 
    /* Affichage de la fenêtre */
    gtk_main ();
          
    return 0;
 }

Pour charger un fichier à partir d'un fichier XPM appelé icon0.xpm se trouvant dans le répertoire courant, on aurait créé le pixmap ainsi :

    /* Charge un pixmap à partir d'un fichier */
 
    pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
                                         &style->bg[GTK_STATE_NORMAL],
                                         "./icon0.xpm" );
    pixmapwid = gtk_pixmap_new( pixmap, mask );
    gtk_widget_show( pixmapwid );
    gtk_container_add( GTK_CONTAINER(window), pixmapwid );
Utilisation des formes

Un désavantage de l'utilisation des pixmaps est que l'objet affiché est toujours rectangulaire, quelle que soit l'image. On voudrait pouvoir créer des bureaux et des applications avec des icônes ayant des formes plus naturelles. Par exemple, pour une interface de jeu, on aimerait avoir des boutons ronds à pousser. Pour faire cela, on doit utiliser des fenêtres avec des formes.

Une fenêtre avec forme est simplement un pixmap dont les pixels du fond sont transparents. Ainsi, lorsque l'image d'arrière-plan est multicolore, on ne la cache pas avec le bord de notre icône. L'exemple suivant affiche une image de brouette sur le bureau.

 #include <gtk/gtk.h>
 
 /* XPM */
 static char * WheelbarrowFull_xpm[] = {
 "48 48 64 1",
 " c None",
 ". c #DF7DCF3CC71B",
 "X c #965875D669A6",
 "o c #71C671C671C6",
 "O c #A699A289A699",
 "+ c #965892489658",
 "@ c #8E38410330C2",
 "# c #D75C7DF769A6",
 "$ c #F7DECF3CC71B",
 "% c #96588A288E38",
 "& c #A69992489E79",
 "* c #8E3886178E38",
 "= c #104008200820",
 "- c #596510401040",
 "; c #C71B30C230C2",
 ": c #C71B9A699658",
 "> c #618561856185",
 ", c #20811C712081",
 "< c #104000000000",
 "1 c #861720812081",
 "2 c #DF7D4D344103",
 "3 c #79E769A671C6",
 "4 c #861782078617",
 "5 c #41033CF34103",
 "6 c #000000000000",
 "7 c #49241C711040",
 "8 c #492445144924",
 "9 c #082008200820",
 "0 c #69A618611861",
 "q c #B6DA71C65144",
 "w c #410330C238E3",
 "e c #CF3CBAEAB6DA",
 "r c #71C6451430C2",
 "t c #EFBEDB6CD75C",
 "y c #28A208200820",
 "u c #186110401040",
 "i c #596528A21861",
 "p c #71C661855965",
 "a c #A69996589658",
 "s c #30C228A230C2",
 "d c #BEFBA289AEBA",
 "f c #596545145144",
 "g c #30C230C230C2",
 "h c #8E3882078617",
 "j c #208118612081",
 "k c #38E30C300820",
 "l c #30C2208128A2",
 "z c #38E328A238E3",
 "x c #514438E34924",
 "c c #618555555965",
 "v c #30C2208130C2",
 "b c #38E328A230C2",
 "n c #28A228A228A2",
 "m c #41032CB228A2",
 "M c #104010401040",
 "N c #492438E34103",
 "B c #28A2208128A2",
 "V c #A699596538E3",
 "C c #30C21C711040",
 "Z c #30C218611040",
 "A c #965865955965",
 "S c #618534D32081",
 "D c #38E31C711040",
 "F c #082000000820",
 " ",
 " .XoO ",
 " +@#$%o& ",
 " *=-;#::o+ ",
 " >,<12#:34 ",
 " 45671#:X3 ",
 " +89<02qwo ",
 "e* >,67;ro ",
 "ty> 459@>+&& ",
 "$2u+ ><ipas8* ",
 "%$;=* *3:.Xa.dfg> ",
 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
 " p;<69BvwwsszslllbBlllllllu<5+ ",
 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
 " c1-699Blvlllllu7k96MMMg4 ",
 " *10y8n6FjvllllB<166668 ",
 " S-kg+>666<M<996-y6n<8* ",
 " p71=4 m69996kD8Z-66698&& ",
 " &i0ycm6n4 ogk17,0<6666g ",
 " N-k-<> >=01-kuu666> ",
 " ,6ky& &46-10ul,66, ",
 " Ou0<> o66y<ulw<66& ",
 " *kk5 >66By7=xu664 ",
 " <<M4 466lj<Mxu66o ",
 " *>> +66uv,zN666* ",
 " 566,xxj669 ",
 " 4666FF666> ",
 " >966666M ",
 " oM6668+ ",
 " *4 ",
 " ",
 " "};

 /* Termine l'application lorsqu'elle est appelée 
  * (via le signal "delete_event"). */
 
 void close_application( GtkWidget *widget, GdkEvent *event, gpointer *data ) 
 {
    gtk_main_quit();
 }

 int main (int argc, char *argv[])
 {
    GtkWidget *window, *pixmap, *fixed;
    GdkPixmap *gdk_pixmap;
    GdkBitmap *mask;
    GtkStyle *style;
    GdkGC *gc;
    
    /* crée la fenêtre principale et attache le signal "delete_event"
     * pour terminer l'application. On notera que la fenêtre principale
     * n'a pas de barre de titre car nous la faisons surgir. */
 
    gtk_init (&argc, &argv);
    window = gtk_window_new( GTK_WINDOW_POPUP );
    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                        GTK_SIGNAL_FUNC (close_application), NULL);
    gtk_widget_show (window);
 
    /* Création du pixmap et du widget pixmap */
 
    style = gtk_widget_get_default_style();
    gc = style->black_gc;
    gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
                                             &style->bg[GTK_STATE_NORMAL],
                                             WheelbarrowFull_xpm );
    pixmap = gtk_pixmap_new( gdk_pixmap, mask );
    gtk_widget_show( pixmap );
 
    /* Pour afficher le pixmap, on utilise un widget fixe pour placer
     * le pixmap */
 
    fixed = gtk_fixed_new();
    gtk_widget_set_usize( fixed, 200, 200 );
    gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
    gtk_container_add( GTK_CONTAINER(window), fixed );
    gtk_widget_show( fixed );
 
    /* On masque tout sauf l'image elle-même */
 
    gtk_widget_shape_combine_mask( window, mask, 0, 0 );
     
    /* Affichage de la fenêtre */
 
    gtk_widget_set_uposition( window, 20, 400 );
    gtk_widget_show( window );
    gtk_main ();
          
    return 0;
 }

Pour rendre l'image de la brouette sensible aux clics, on peut lui attacher le signal "button_press_event" pour lui faire faire quelque chose. Les quelques lignes suivantes font que l'image sera sensible à un clic souris qui provoquera l'arrêt de l'application.

 gtk_widget_set_events(window,
                       gtk_widget_get_events( window ) |
                       GDK_BUTTON_PRESS_MASK );
 
 gtk_signal_connect(GTK_OBJECT(window), "button_press_event",
                    GTK_SIGNAL_FUNC(close_application), NULL );