Next: , Previous: Utilisation d'adesklets, Up: Top



5 Programmation d'adesklets

5.1 Une introduction à adesklets

Comme expliqué ci-dessus (See A propos d'adesklets.), adesklets est principalement une console interactive d'Imlib2, avec quelques fonctionnalités supplémentaires :

Commençons un session interactive typique pour voir ce qui se passe. Sous X, ouvrez un terminal et tapez :

     adesklets :

Comme dans la section précédente (See 'Utilisation d'adesklets comme un éditeur graphique en ligne de commande'.), vous obtenez une invite. Maintenant entrez la commande 'images_info'. Vous devriez voir en réponse sur la sortie standard :

     2 images
     id 0 width 1 height 1 alpha 1 filename (null)
     id 1 width 1 height 1 alpha 1 filename (null)
     command 0 ok: images_info

Cela signifie que vous avez deux images : image 0 et image 1, et quelles ont une taille de 1x1 pixel. Ceux sont les seules images que vous ne pouvez jamais détruire ni modifier comme vous le souhaitez (les redimensionner indépendamment, les retourner diagonalement, etc. Lisez ce qui suit pour savoir pourquoi.)

Mais ou sont ces fenêtres ? Pour l'instant ce sont seulement des images de 1x1 pixel, et elles ne sont pas montrées1 à l'écran. Ainsi, redimensionnons les à 100x100 pixels : tapez 'window_resize 100 100'. Maintenant, si vous retapez la commande 'images_info', vous obtiendrez :

     2 images
     id 0 width 100 height 100 alpha 1 filename (null)
     id 1 width 100 height 100 alpha 1 filename (null)
     command 2 ok: images_info

Vous voyez ? Les images d'avant-plan et d'arrière-plan ont été redimensionées à 100x100 pixels : de plus, l'arrière-plan a été mis à jour pour contenir la nouvelle image de fond. Maintenant, rendons cette fenêtre visible. Tapez les deux commandes : 'window_reset managed' et enfin 'window_show'.

La première commande demande à adesklets de laisser votre gestionnaire de fenêtre "géré" votre fenêtre (ce qui n'est pas fait par défaut) : cela signifie que la fenêtre va être décorée, et que vous pourrez changer sa visibilité2 de façon interactive. La seconde montre votre fenêtre de 100x100. Rien d'impressionnant : un carré noir de 100x100 avec une barre de titre et des bordures.

Comme dit plus haut, seule l'image 0 (avant-plan) est affichée par défaut. Maintenant, tapons : 'window_set_transparency 1'. Wouah! Nous voyons la fenêtre racine en dessous ! Avec "window transparency" activé, l'image 1 (arrière-plan) est d'abord copiée dans la fenêtre, puis l'image 0 (avant-plan) qui est entièrement noire et transparente, est mise par-dessus3.

Il est temps de parler des couleurs : souvenez-vous qu'adesklets est une console d'Imlib2 : en conséquence, comme Imlib24, les couleurs sont toujours de véritables couleurs 32 bits codées en RVBA - huit bits par canal (de 0 à 255), incluant un canal alpha (transparence). La conversion de palette se fait automatiquement si la profondeur de votre écran est inférieure, vous n'avez pas à vous en occuper. Si vous tapez : 'context_get_color', vous obtiendrez :

     command 0 ok: context color 255 255 255 255

Imlib2 est le roi de l'état de la machine ; ainsi, il vient avec un "contexte" qui garde en mémoire une série d'attributs qui seront utilisés dans des opérations futures. Par exemple, nous savons maintenant que la couleur qui sera utilisée, aussi longtemps que nous ne la modifions pas, sera un blanc opaque (rouge=255, bleue=255, vert=255, alpha=255). Si nous tapons : 'context_get_image', il nous retourne :

     command 0 ok: context image 0

Cela signifie que toute opération que nous effectuons sur une fenêtre est directement fait sur l'image d'avant-plan. Dessinons un rectangle plein semi-transparent de couleur magenta sur l'avant-plan. La commande pourra être : 'context_set_color 255 0 0 200' et 'image_fill_rectangle 25 25 50 50'. Élégant, n'est-ce pas ?

Si vous avez l'habitude de programmer avec Imlib2, vous devriez avoir remarqué que ces dernières commandes vous sont familières. C'est normal : la plupart des fonctions C d'Imlib2 sont présentées de la même façon dans les 'commandes' d'adesklets. Ainsi, la commande d'adesklets 'image_fill_rectangle' suit la même sémantique que la fonction 'imlib_image_fill_rectangle()' d'Imlib2, la commande 'context_set_color' que la fonction 'imlib_context_set_color()', etc. Les deux seules différences significatives (et systématiques) sont que partout où vous utiliserez un objet 'Imlib_Quelquechose' en C, vous utiliserez un entier ID avec adesklets, et dans la sémantique des fonctions 'imlib_free_Quelquechose()' on a besoin de donner un entier ID au lieu d'un objet de ce type permettant de libérer le contexte sélectionné.

Illustrons cela. Chargeons la police "Vera" inclue dans adesklets à la taille 20pt, mettons la en police par défaut, et écrivons dans un bloc blanc opaque 'Hello' en diagonale sur l'image d'avant-plan du coin haut gauche avant de décharger la police. Cela devrait ressembler à :

     6 >>> load_font Vera/20
     command 6 ok: new font 0
     7 >>> context_set_font 0
     command 7 ok: context_set_font 0
     8 >>> context_set_direction text_to_angle
     command 8 ok: context_set_direction text_to_angle
     9 >>> context_set_angle 45
     command 9 ok: context_set_angle 45
     10 >>> context_set_color 255 255 255 255
     command 10 ok: context_set_color 255 255 255 255
     11 >>> text_draw 0 0 Hello
     command 11 ok: text_draw 0 0 Hello
     12 >>> free_font 0
     command 12 ok: free_font 0

Si vous regardez votre documentation d'Imlib2, vous remarquerez immédiatement les deux différences que l'on vient de dire : toutes les références à la police Vera/20 sont faites par un entier ID (0 ici), et la commande 'free_font', contrairement à la fonction correspondante 'imlib_free_font()', est appelée avec l'ID de la police comme argument plutôt que le contexte de la police.

A partir de là, imaginons que vous voulez sauver l'image résultante ; ce n'est pas un problème - tapons : 'save_image out.png', et l'avant-plan est sauvé dans un fichier "out.png" dans le répertoire de travail courant5. Maintenant, juste pour le plaisir, quittons adesklets, et lançons une autre session interactive pour voir si nous pouvons recharger cette image. Tapez juste la commande "quit" ou pressez ^D (Control D: fin de fichier), votre nouvelle session devrait ressembler à ceci :

     0 >>> window_resize 100 100
     command 0 ok: window_resize 100 100
     1 >>> window_reset managed
     command 1 ok: window_reset managed
     2 >>> window_set_transparency 1
     command 2 ok: window_set_transparency 1
     3 >>> load_image out.png
     command 3 ok: new image 2
     4 >>> blend_image_onto_image 2 0 0 0 100 100 0 0 100 100
     command 4 ok: blend_image_onto_image 2 0 0 0 100 100 0 0 100 100
     5 >>> window_show
     command 5 ok: window_show
     6 >>> free_image 2
     command 6 ok: free_image 2

Bien sur, nous voulons visualiser le résultat - c'est pourquoi nous avons utilisez les commandes 'window_reset', 'window_set_transparency' et 'window_show' : elles n'ont pas d'autres utilités. La commande 'blend_image_onto_image' vient droit de Imlib2 aussi ; elle prend la nouvelle image 2 que l'on vient de crée lors de la troisième commande, et la met dans un contexte d'image (image 0 - avant-plan par défaut), à partir de ces coordonnées (0,0) pour une taille de 100x100 pixels, et la met dans un rectangle allant de (0,0) et de taille 100x100 pixels de l'image 0. Il est finalement bon de noter que, avec adesklets, il y a toujours une image dans le contexte d'Imlib2 : dès que vous essayer de libérer l'image courante, le contexte d'image est remis à l'image d'avant-plan.

D'accord, c'est presque la fin de cette introduction. A partir de là vous pouvez jouer avec adesklets - il est vraiment facile de l'utiliser si vous vous êtes déjà familiarisé avec Imlib2. Sinon, votre meilleure ressource est certainement d'avoir la documentation d'Imlib2 pas trop loin. :-)

Quelques dernières astuces :

Voici un exemple :

     #!/usr/bin/env adesklets -f
     
     # Rendre la fenêtre 'géré'
     #
     window_reset managed
     
     # Redimmensioner la fenêtre à 100x100 pixels
     #
     window_resize 100 100
     
     # Montrer la fenêtre, puis la geler pendant 10 secondes avant de sortir
     #
     window_show
     pause 10

Vous aurez juste besoin de rendre ce script exécutable et de le lancer. Comme d'habitude, les sorties seront affichées sur la sortie standard.

5.2 Véritable programmation avec adesklets : écriture d'un script

de desklet

Lorsque vous serez prêt pour un véritable travail7, vous pourrez vouloir utilisé un véritable langage de script plutôt que le rudimentaire interpréteur adesklets que nous avons utilisé dans l'introduction ; vous ne savez jamais quand les variables sont accessibles.

Au moment ou j'écris ces lignes (10 juin 2005), seul le support pour Python est complet8. A partir de python, les choses ne sont pas très différentes qu'à partir de l'interpréteur : les commandes ont été encapsulées dans des fonctions python, et une classe publique Events_handler a été construite pour manipuler les retours asynchrones de l'interpréteur. Jetez un coup d'oeil sur le script test/test.py de l'archive source de la version 0.4.10 :

"""
test_fr.py - S.Fourmanoit <syfou@users.sourceforge.net>,
             Guillaume Boitel <g.boitel@wanadoo.fr>

Petit script de test non-exhaustif pour adesklets :

      - Redimensionne la fenêtre adesklets à 100x100 pixels
      - La met sous le contrôle du gestionnaire de fenêtre
      - La rend pseudo-transparente
      - L'affiche à l'écran
      - Attends ensuite que l'utilisateur la quitte,
        génère une alarme toutes les 10 secondes
        et attrape les événements motion_notify dès qu'ils apparaissent.

Pour l'essayer :
      - Installer adesklets avec le support python activé (par défaut)
      - Lancer python test.py à partir de ce répertoire.
"""
import adesklets

class My_Events(adesklets.Events_handler):
    def __init__(self):
        adesklets.Events_handler.__init__(self)
        
    def __del__(self):
        adesklets.Events_handler.__del__(self)
        
    def ready(self):
        adesklets.window_resize(100,100)
        adesklets.window_reset(adesklets.WINDOW_MANAGED)
        adesklets.window_set_transparency(True)
        adesklets.window_show()

    def quit(self):
        print 'Quitting...'
        
    def alarm(self):
        print 'Alarm. Next in 10 seconds.'
        return 10
    
    def motion_notify(self, delayed, x, y):
        print 'Motion notify:', x, y, delayed

My_Events().pause()
Voilà ! 26 ligne de code python, et nous avons un desklet parfaitement fonctionnel. Je pense que cela s'explique tout seul : jetez un coup d'oeil à l'aide intégrée de python pour adesklets, adesklets.functions et adesklets.Events_handler pour une bonne et complète explication. En deux mots, tout ce que nous avons fait ici c'est :
  1. Importer le paquetage adesklets : cela instancie automatiquement un processus fils adesklets et configure toutes les communications : quand l'initialisation du paquetage ne retourne pas d'exception, cela signifie que l'interpréteur tourne et est prêt à accepter des commandes.
  2. Faire une sous-classe d'adesklets.Events_handler et redéfinir des méthodes invoquées pour les événements qui nous intéresse (tous les autres événements ne sont pas simplement ignorés, ils ne sont pas générés).
  3. Instancier un objet de cette classe, et mettre en boucle infinie 9.

Enfin, mentionnons que vous pouvez regarder dans le code source du desklet weather du site web du projet situé sur sourceforge pour un script python pour adesklets plus conséquent.


Footnotes

[1] "Mappé" dans un patois de X Window

[2] Une fenêtre "non-gérée" est très utile pour les desklets : c'est comme si c'était une partie de la fenêtre racine puisqu'elle peut être construite pour ne jamais être en avant-plan et pour rester affichée lorsque l'on change d'espace de travail.

[3] Bien... Pas tout à fait : il y a un buffer qui est mise en jeu pour la performance, mais l'opération est logiquement équivalente à cette description.

[4] Gardez votre documentation d'Imlib2 à proximité : c'est très utile - http://atmos.org/docs/imlib2/index.html fournit une agréable introduction, bien qu'un peu ancienne.

[5] Pour que ça marche, vous avez besoin d'avoir une installation d'Imlib2 proprement configuré pour utiliser libpng, ou vous risquez de recevoir une erreur "no loader for file format".

[6] Pour que ça marche, vous avez besoin d'avoir GNU history lorsque vous compilez adesklets.

[7] :-)

[8] adesklets a été écrit pour être facile d'usage pour différents langages interprétés ; le futur développement inclue des encapsulations pour Perl et Ruby - n'hésitez pas à proposer votre aide si vous voulez accélérer les choses.

[9] Cette dernière étape n'est pas obligatoire : le script peut très bien continuer, mais il a été écrit ainsi pour supporter les signaux d'interruptions. Regarder `help(adesklets.Events_handler)' pour de plus amples informations.