Première pull request

Un ami posait une question sur l'utilisation d'un logiciel libre. C'est un logiciel de dessin i(krita)et un des outils affichait des informations sous sa main lorsqu'il l'utilisait avec un une tablette graphique qui fait aussi écran. Il voulait savoir si on pouvait déplacer cet affichage.

Les sources du logiciel étant disponibles librement, je suis allé y voir si je trouvais la réponse dedans. J'en trouvais une fonctionnelle mais pas très pratique.

Mes contributions au logiciel libre sont assez minces. Je me suis entrainé à une époque à faire du rapport de bug, et je conseil l'exercice à tout le monde. J'ai bien donné deux ou trois coup de mains sur l'utilisation mais celà s'arrêtait là. Je vais essayer de voir si j'arrive à proposer un modification du logiciel, et en profiter pour tracer le parcours.

Un point qui risque d'être délicat, c'est que malgré un certaine expérience en programmation, je n'ai quasiement jamais fait de C++ (pas plus de deix heures il y a plus de vingt ans), et meme utilisé de langage sans garbage collector (c'est à diore géré à la main les allocations ou désalocations de mémoire. Je continue bien à faire un peu d'assembleur pour le plaisir, mais en gérant la mémoire uniquement sur la pile ou en allocation statique.)

L'idée étant d'aller voir dans le code source, il fallait d'abord le récupérer. Une recherche rapide de "krita source code" donne directement un repository github dont j'apprends plus tard qu'il n'est pas le bon mais qui a suffit pour commencer.

Premier probleme : par où démarrer la rechercher. Deux grosses options :

  • chercher à comprendre en gros l'organisation du code et descendre jusqu'au bon endroit
  • faire une recherche pour trouver une méthode ou une classe qui a l'air de parler de mon sujet.

Je tente la seconde, et cherche le terme qui était dans la question d'origine ("color picker"). Je ne trouve pas grand chose (un seul résultat, dans un fichie d'entête KisScreenColorSampler.h). Ce ne doit pas être le bon mot. Je vais chercher dans la doc de Krita, et le second résultat me confirme que l'outil en question s'appele le Color Sampler. (C'est la référence à la touche control qui est aussi dans le twitt qui me rassure).

Bref, je retrouve rapidement le pendant de mon header et commence à regarder si le nom d'une des méthodes m'inspire. sampleScreenColor semble pas trop mal, c'est peut etre à ce moment que l'information mal placée est afichée ou mise à jour ? Ca n'a pas l'air. grabScreenColor ? Non plus, même si ca commence à parler de coordonnées. Je vois d'une part des mise à jour de label text (l'outil n'affiche pas de texte, donc a moins que le code de l'outil affiché sur la feuille ne soit mélangé avec ud code de l'affichage des pallettes de couleurs sur le coté, il y a un probleme), d'autre part j'ai clairement trouvé une fonction nommée setCurrentColor mais ni elle, ni le code qui ne l'appele ne semble faire de mise à jour de l'IHM.

Un truc important quand on navigue dans une base de code inconnue, c'est de savoir jusqu'où on pense devoir s'entêter. Là c'est probablement le moment de me dire que j'ai fais fausse route et de vérifier des choses. Le fichier que j'ai ouverts s'appèle KisScreenColorSampler.cpp, est-ce qu'il y a d'autres candidats ? Je refais la recherche dans Github et trouve un kis_tool_colorsampler.cc référencé dans CMakeList.txt, puis un kis_tool_colorsampler.h. En fait il y a un bouton "go to file" dans github plus pratique. Je tape ColorSampler je trouve le bon fichier.

Je reprends le meme genre de scrutage que dans le fichier précédant, et je trouve une méthode KisToolColorSampler::activatePrimaryAction(), qui elle même fait un m_helper.updateCursor(!m_config->sampleMerged, m_config->toForegroundColor);

J'essaie de trouver ce qu'est ce m_helper qui semble être définit ou référencé en début de fichier :

KisToolColorSampler::KisToolColorSampler(KoCanvasBase *canvas)
    : KisTool(canvas, KisCursor::samplerCursor()),
      m_config(new KisToolUtils::ColorSamplerConfig),
      m_helper(dynamic_cast<KisCanvas2*>(canvas))

Je ne comprends pas trop la notation. Pas trop grave, le but là est de trouver où est l'info, et de la comprendre après. Pas de comprendre tout le code. Je cherche ce m_helper dans toute la base de code... avant de comprendre que bien sur, il est défini dans le fichier .h correspondant à mon fichier .cpp. Je trouve son type, et donc dans le fichier correspondant me dit que la methode updateCursor fait peut être un truc louche en utilisant le curseur pour afficher l'info. Je parcours un peu le code, arrive à une réfrence à la classe kis_cursor qui a l'air de fournir les representations de curseurs, et à ce code :

QCursor KisCursor::samplerLayerForegroundCursor()
{
    return load("color-sampler_layer_foreground.xpm", 8, 23);
}

qui fait référence au fichier .xpm que je ne trouve pas dans github... Je clone le repository en local (270Mo!) et la trouve le fichier... qui ne contient qu'un bête curseur de souris sans rien pour afficher la couleur selectionnée au mauvais endroit... fausse route !

Allez, pas grave, on revient un peu plus haut, et dans le SamplerHelper cette fois je trouve quelque chose qui a l'air beaucoup plus prometteur : colorPreviewDocRectImpl.

Je n'ai toujours rien compris au code, qui semble lisible mais sans commentaire pour dire à qui servent les classes, je n'ai pas cherche de document de vue d'ensemble, j'essaie juste de trouver où est le code qui dit ou est affiché cette information mal placée, à partir de quoi j'essaierai de comprendre des choses. Je ne suis pas certain de comprendre la première ligne, mais la deuxième commence à carrément ressembler à ce que je cherche :

    KisConfig cfg(true);
    const QRectF colorPreviewViewRect = cfg.colorPreviewRect();

Il existe un fichier KisConfig.cpp, je reprends ma lecture des signatures. J'apperçois au possage un m_cfg, je suppose que c'est hérité ou importé ailleurs ? Ou alors c'est la variable privée et le KisConfig cfg(true) plus haut déclare une variable cfg en appelant le constructeur de KisConfig ? Bref, j'y connais rien en C++, faudra que je lise un peu de doc...

Et là, dans activateDelayedPreview, les choses commencent à se préciser !

m_d->showPreview = true;

Bon, je commence à m'éparpiller et a essayer de comprendre des choses trop tôt. Revenons à la ligne la seconde ligne, celle qui semblait simple et évidente : const QRectF colorPreviewViewRect = cfg.colorPreviewRect();

Si je cherche ce colorPreviewRect() dans KisConfig.cpp, l'implémentation est courte :

QRect KisConfig::colorPreviewRect() const
{
    return m_cfg.readEntry("colorPreviewRect", QVariant(QRect(32, 32, 48, 48))).toRect();
}

Il semble qu'il aille chercher une valeur nommée colorPreviewRect dans un truc de configuration, et prenne une valeur par defaut s'il ne la trouve pas. Je pourrais aller vérifier cette hypothese en regardant le code de readEntry, mais je pense commencer à être suffisemment proche de la solution pour commencer à avoir envie de comprendre un peu le contexte locale. Je fais une recherche sur internet pour voir où est-ce que Krita sauve sa configuration (j'ai pas trovué de fichier ~/.krita), et découvre le fichier ~/.config/kritarc (et kritadisaplyrc).

J'essai à tout hasard d'ajouter dedans le nom de ma variable de configuration. Apparemment on peut mettre plusieurs valeurs séparées par des virgules, et je tente donc d'ajouter :

colorPreviewRect=100,200,100,200

Je relance Krita et... Victoire ! La preview de la couleur s'affiche n'importe où et avec une taille différente. J'essaie des valeurs négatives, j'arrive à positionner à un endroit ou Kholo arrivera à voir la couleur, je lui donne le truc sur Discord, et c'est deja une première contribution au logiciel libre : j'ai dépanné un utilisateur :)

Dans sa question sur Twitter, Kholo avait pingué l'équipe de Krita. Je donne ma réponse pour voir s'ils la valident ou s'ils ont mieux. J'efface le twitt et le re-redige de façon un peu mieux construite, au cas où ca puisse servir à quelqu'un d'autre :

Looking at the code, I found you can add :
colorPreviewRect=-100,-100,50,50
in ~/.config/kritarc

you probably want to add it as last line of the file, since the last section is [tool_color_sampler]

On discute un peu avec Kholo de l'utilité de ce changement de position, on vérifie qu'on ne trouve pas l'option dans l'IHM, de si c'est un endroit ou ce serait "rentable" pour l'équipe de dev de Krita de mettre des efforts (a mettre dans en balance avec tout le boulot qu'il y a à faire sur le logiciel, même s'il est deja très très utilisable). Comme Kholo m'a dit qu'il avait essayé de lire le code mais avait abandonné finalement très prêt de la solution, et comme j'essaie d'enjoindre les utilisateurs de logiciels libre à apprendre à contribuer en faisant des bugs reports et que j'ai moi meme trouvé l'exercice intéressant... je commence à me dire que je pourrais essayer d'ajouter l'option dans l'IHM.