Documentation technique de TKsesh

But de ce document

Ce document détaille le fonctionnement interne de Tksesh. Il décrit la structure des documents, du programme, et un certain nombre d'algorithmes utilisés.

Structure des documents

Le dictionnaire

Les textes

Architecture du programme Tcl

Utilisation du widget graphique sesh

Fonctionnement interne du widget sesh

Le triple buffering

La composition de groupes de hiéroglyphes est une opération longue. En conséquence, sur les machines lentes (mais en reste-t-il ?), il faut optimiser l'algorithme de dessin du texte.

L'algorithme naïf serait :

      POUR TOUS LES CADRATS C VISIBLES
        DESSINER(C)
    
Le but est d'éviter de redessiner les cadrats déjà affichés. On peut envisager des méthodes ad hoc, comme par exemple ne travailler que sur la ligne qui subit une modification :
       SOIT C LE DERNIER CADRAT MODIFIÉ
         EFFACER L'ÉCRAN DEPUIS C JUSQU'À LA FIN DE LA LIGNE
         DESSINER TOUS LES CADRATS DE C JUSQU'À LA FIN DE LA LIGNE
    
Le problème de ces méthodes est qu'elles ne sont pas générales : pour un type donné de modifications du texte, elles fonctionnent correctement, mais elles gèrent mal les autres cas. L'algorithme précédent ne fonctionne pas si le texte subit une modification importante, qui dépasse une ligne. Il ne fonctionne pas très efficacement, de plus, si la fin de la ligne est longue et complexe. Poursuivre sur cette voie conduit à essayer de traiter tous les cas possibles, ce qui est très complexe.

Dans un premier temps, nous avons essayé de réaliser un système qui recopierait chaque cadrat déjà dessiné à l'étape N vers son emplacement correct à l'étape N+1, le tout, sur la même surface de dessin. C'est une tâche ardue, car les copies doivent s'effectuer dans un certain ordre pour éviter qu'un cadrat copié en recouvre un autre qui ne l'a pas encore été.

En sacrifiant de la mémoire, une solution plus simple apparaît : on conserve l'ancien état du pixmap (la surface de dessin en mémoire), ce qui évite les problèmes de recouvrement. D'où l'algorithme :

       e:= ancien_pixmap;
       POUR c:= premier_cadrat_visible JUSQUA fin_de_la_derniere_ligne_visible
         FAIRE
           etat:= visibilité de c (VISIBLE, CACHE, PARTIELLE)
           SI etat <> CACHE ALORS
             SI c.ancien_etat = VISIBLE  ALORS
                COPIER c depuis e jusquà nouveau_pixmap;
              SINON 
                DESSINER le cadrat c
             FINSI;
           FINSI
           c.ancien_etat:= etat;
           c.anciennes_coordonnees:= coordonnees courantes de c;
        FINPOUR;
        ancien_pixmap:= nouveau_pixmap;
    
Conserver les anciennes coordonnées permet une opération de copie simple. Comme la copie de bitmaps est très rapide, cette procédure est très efficace.

Elle comporte cependant une erreur. En effet, elle décide de redessiner ou de recopier un cadrat en fonction de la valeur de ancien_etat. Cette valeur n'est malheureusement pas forcément à jour. Elle n'est à jour que pour un cadrat compris entre le premier cadrat affiché et la fin de la dernière ligne affichée. Pour palier ce problème, nous utilisons un compteur, augmenté de 1 à chaque appel de l'algorithme. La valeur courante du compteur est copiée dans un cadrat lors de la mise à jour de ancien_etat. Il est alors facile de savoir si l'état correspond bien à la réalité. Si l'état d'un cadrat n'est pas à jour, cela signifie qu'il n'est pas affiché.

       e:= ancien_pixmap;
       POUR c:= premier_cadrat_visible JUSQUA fin_de_la_derniere_ligne_visible
         FAIRE
           etat:= visibilité de c (VISIBLE, CACHE ou PARTIELLE)
           SI etat <> CACHE ALORS
             SI c.compteur = compteur ET c.ancien_etat = VISIBLE  ALORS
                COPIER c depuis e jusquà nouvel_pixmap;
              SINON 
                DESSINER le cadrat c
             FINSI;
           FINSI
           c.ancien_etat:= etat;
           c.compteur:= compteur+1;
           c.anciennes_coordonnees:= coordonnees courantes de c;
        FINPOUR;
        compteur:= compteur+1;
        ancien_pixmap:= nouvel_pixmap;
        COPIER nouvel_pixmap sur l'écran de l'ordinateur.
    
Enfin, pour éviter un désagréable effet de scintillement, la surface de dessin nouvel_pixmap n'est pas la surface de dessin affichée. Elle est copiée sur cette dernière uniquement lorsque la mise à jour est terminée.