Multithreading avec GTK en python sur N900

Une application sous linux en python telle que Caritang doit résoudre le problème de réactivité de l’interface utilisateur en prenant en compte les spécificités suivantes:

  1. la thread principale qui execute GTK
  2. l’interpréteur python
  3. le serveur X

Une IHM se doit d’être réactive. Toute action de l’utilisateur doit provoquer une réponse immédiate de l’IHM. Or la mise à jour de l’IHM se fait quand la thread principal qui execute la boocle gtk sort du code appelé par l’évènement de l’interface graphique. Autrement dit ce n’est que lorsque le code créeé par le programmeur pour effectuer l’action est terminé qu’on est sûr que l’IHM sera mis à jour. Donc si le code de l’action n’est pas trés rapide alors on va monopoliser la thread principale de gtk à faire de l’applicatif au lieu de faire de l’IHM.
Quand on veut effectuer un traitement long, il faut lancer une thread dédiée à ce traitement afin de libérer la thread principale. Plusieurs techniques existent: on peut utiliser les fonctions utilitaires de gobject comme timeout_add ou bien une classe Timer ou alors créer soit même une Thread.
Quelque soit la technique il faut néanmoins indiquer à gtk qu’il va s,exécuter en multithreading en invoquant gtk.gdk.threads_init()

Libérer la thread principal permet à GTK de mettre à jour l’IHM. Ainsi si la thread du traitement modifie le texte d’un gtk.Label, la thread de GTK pourra mettre à jour l’IHM. Inversement l’IHM étant disponible, l’utilisateur peut demander la fermeture de l’application. Dans ce cas que se passe-t-il pour la thread de traitement? Soit elle continue en empêchant la fermeture du programme soit elle est brûtalement arrétée si elle est marquée comme deamon. Ce dernier cas n’est pas la meilleur solution car il entraine des erreurs dans la thread de traitement. Ainsi durant l’arrêt de l’interpréteur python, la thread de traitement se retrouve dépourvu des variables locales ou d’instances.
L’idéal est d’envoyer un signal à la tread de traitement pour qu’elle se termine proprement.

Enfin le serveur X (peut?) n’est pas “thread safe”. Malgrès tout ce qui précède il se peut que le thread principale de GTK accède à l’IHM en même temps que la thread de traitement. Une simple modification du texte d’un gtk.Label provoquera de manière aléatoire une erreur dans XLib. La solution est de protéger (synchroniser) les accès aux composants graphiques en encadrant toute modification de l’IHM dans la thread de traitement par gtk.gdk.threads_enter() et gtk.gdk.threads_leave()

Ajout d’un programme dans Hildon

Hildon est le nom de l’interface graphique du N900. Toute application qui veut s’intégrer à l’interface doit avoir une entrée dans la liste des programmes. Pour cela il n’est pas nécessaire de fabriquer une application “packagée” sous forme de paquet debian. Une simple installation de module python fait l’affaire.

La principale chose à faire est del créer un fichier du nom de l’application. Supposons que l’application s’appelle zourite. Il faut alors créer un fichier
/usr/share/applications/hildon/zourite.desktop
dont le contenu minimal sera:
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Name=Zourite
Exec=/usr/bin/zourite

La ligne Exec peut contenir une ligne de commande complète avec argument telle que /usr/bin/caritang -g

Ce fichier suffit pour que Hildon ajoute une entrée dans la liste des programmes.
Liste des applications dans Hildon

Maintenant si on veut que Hildon affiche une jolie icone, il faut la lui fournir. Avec le fichier .desktop minimaliste, hildon va rechercher les icones à l’emplcement par défaut sous le nom par défaut, à savoir:

/usr/share/icons/hicolor/48x48/hildon/zourite.png
/usr/share/icons/hicolor/64x64/hildon/zourite.png

Avec un minimum d’effort il est maintenant possible d’ajouter un raccourci sur le bureau.

Ajout d'un raccourci sur le bureau Hildon

Upload de vidéo sur Picasa en python

L’utilitaire caritang a pour objectif de permettre la sauvegarde des documents du N900 vers google docs. Mais il s’avère que picasa est plus adapté pour les média enregistrés avec la caméra du terminal qu’il s’agisse de photo ou de vidéo.

L’api gdata en version 2.0.9 permet depuis python de manipuler un compte picasa. Malheureusement la version de l’api picasa implémentée est la 1.0 alors que la 2.0 qui n’existe pas en python est la seule qui autorise l’envoi de vidéo.

Une impasse pour les vidéo ? Non, car le mécanisme d’envoi de vidéo est en fait, d’après la documentation de la 2.0, similaire à celui des photos modulo le type mime. Un test en utilisant le binding python officiel et en passant le type mime video/mp4 montre que le module gdata.photos.service vérifie que le type mime est bien une photo.

C’est la que la nature dynamique de python nous sauve. Il suffit de changer la liste (supposée être une constante) des type de fichier autorisés.

gdata.photos.service.SUPPORTED_UPLOAD_TYPES = gdata.photos.service.SUPPORTED_UPLOAD_TYPES + ("mp4",)

Dans la cas particulier du N900 l’obtention du type mime par le module mimetools echoue sur les mp4. Là encore on peut ajouter le type mime video/mp4 au module par une instruction

mimetypes.add_type("video/mp4", ".mp4")

Upload de vidéo sur Picasa en python

L’utilitaire caritang a pour objectif de permettre la sauvegarde des documents du N900 vers google docs. Mais il s’avère que picasa est plus adapté pour les média enregistrés avec la caméra du terminal qu’il s’agisse de photo ou de vidéo.

L’api gdata en version 2.0.9 permet depuis python de manipuler un compte picasa. Malheureusement la version de l’api picasa implémenté est la 1.0 alors que la 2.0 qui n’existe pas en python est la seule qui autorise l’envoi de vidéo.

Une impasse pour les vidéo ? Non, car le mécanisme d’envoi de vidéo est en fait, d’après la documentation de la 2.0, similaire à celui des photos modulo le type mime. Un test en utilisant le binding python officiel et en passant le type mime video/mp4 montre que le module gdata.photos.service vérifie que le type mime est bien une photo.

C’est la que la nature dynamique de python nous sauve. Il suffit de changer la liste (supposée être une constante) des type de fichier autorisés.

gdata.photos.service.SUPPORTED_UPLOAD_TYPES = gdata.photos.service.SUPPORTED_UPLOAD_TYPES + ("mp4",)

Dans la cas particulier du N900 l’obtention du type mime par la module mimetools echoue sur les mp4. Là encore on peut ajouter le type mime video/mp4 au module par une instruction

mimetypes.add_type("video/mp4", ".mp4")

Promouvoir son module python avec Pypi

Zourite est à un stade encore immature mais peut être une vitrine de ce que sera l’application. Comme tout application Maemo, sa place serait dans le dépot extra-dev afin qu’elle puisse être installée depuis le gestionnaire d’application du terminal. Hélas la création de compte sur le site de dev de maemo.org (le garage) semble ne pas fonctionner. De plus, l’intégration d’un développent au processus de build du garage n’est pas trivial.

Heureusemenr que Zourite est écrite en python si bien qu’elle peut bénéficier de l’index central des modules. Le site Pypi est un dépot de module (sorte de repo pour les programmes python). Il suffit de s’inscrire pour disposer d’un couple identifiant/mot de passe et pouvoir rendre publique son module.

Les contraintes sont minimes et vont d’ailleurs dans le bon sens. Pypi oblige en effet d’avoir un setup.py bien écrit avec des attributs standardisés comme la plateforme ou la licence du module. Les bénéfice en terme de visibilité en valent la chandelle.