GNOME 3.25.3, la troisième version de développement qui mènera au futur GNOME 3.26, vient de sortir. Et cette fois-ci, les nouveautés visibles par l’utilisateur sont un peu plus nombreuses :
Mutter intègre diverses améliorations concernant l’affichage et la gestion des écrans HiDPI (mais toujours pas de mise à l’échelle fractionnée)
Un certain nombre de projets ont été convertis au système de construction Meson
GJS intègre différents correctifs pour l’intégration à venir de SpiderMonkey 52 (ce dernier étant utilisé aussi bien par l’interface de GNOME que par les extensions)
Machines prend désormais en charge les dossiers partagés et offre la possibilité d’effectuer des captures d’écran
Le Centre de contrôle a droit à diverses améliorations (réorganisation de la configuration réseau, possibilité d’annuler la suppression d’une imprimante, prise en compte des données EXIF pour l’orientation des images en arrière plan…)
Agenda prend désormais en charge les événements récurrents
L’outil de configuration initiale offre désormais la possibilité de configurer les connexions réseau et prend également en charge un fichier de configuration externe, permettant ainsi aux distributions et autres fabricants de PC de pouvoir apporter leur propre personnalisation
Cartes intègre de nouveaux raccourcis clavier (possibilité de basculer entre les différentes vues, chargement d’une couche cartographique…), ajoute la prise en charge de nouveaux tags OpenStreetMap (informations sur les religions, disponibilité des toilettes…) et mémorise le dernier mode de déplacement utilisé
Le service Todoist est ajouté aux Comptes en ligne (ce dernier pouvant servir à des applications comme Recipes ou To Do)
L’outil de numérisation Simple Scan intègre diverses améliorations au niveau de l’interface utilisateur concernant les préférences et prend désormais en charge le format WebP (compression avec pertes)
L’Outil de personnalisation a droit à un certain nombre d’améliorations au niveau de son interface et intègre de nouvelles options, telles que la possibilité de désactiver le pavé tactile lors de la saisie, de permettre l’affichage du niveau de charge de la batterie dans la barre supérieure ou de pouvoir choisir l’emplacement des boutons de la barre de titre. À l’avenir, l’installation ou la suppression d’extensions se fera par contre depuis Logiciels, qui pourra désormais être lancé depuis l’onglet Extensions de l’application.
Sans oublier, bien évidemment, les innombrables corrections de bugs et autres mises à jour de traductions.
Pour plus de détails, vous pouvez consulter l’annonce officielle de Matthias Clasen.
Tout comme les logiciels de son ordinateur, fournir un rapport de bug est une contribution importante dans le logiciel libre. Voici les quelques étapes à mener pour un téléphone sur Android. J’utilise Fedora, mais il n’y a pas de raison que cela fonctionne très différemment sur une autre distribution.
Parfois un plantage m’est égal car c’est mineur ou tellement rare que je ne saurais pas le reproduire, d’autre c’est vraiment gênant ou fréquent, dans ce cas je dois le signaler. Dans mon cas ce sont les applications OpenFoodFacts, OpenBeautyFacts et OpenPetFoodFacts qui m’ont posé problème.
J’utilise rarement ces applications, mais j’aime leur principe et quelques fois par ans je parcours tout ce qui sort de mes sacs de course pour apporter ma petite contribution à leurs projets. Cependant, j’avais des plantages communs à plusieurs applications et triviaux à reproduire, j’ai donc décrit ce que je rencontrais sur le dépôt github du projet
La source du problème, c’est probablement le fait que mon Fairphone utilse une version désormais un peu ancienne d’Android (4.2), et même si les développeurs font attention à ne pas exclure trop rapidement ces terminaux en choisissant correctement les API sur lesquels ils s’appuient (merci !), ils peuvent ne pas avoir le matériel pour produire localement le plantage. Dans ce cas, ils demandent une trace du plantage, globalement c’est l’ensemble de la chaîne explicative, qui permet de dire : « depuis l’interface, ce bouton a appelé telle fonction qui s’appuie sur telle autre qui a provoqué telle erreur ». Les Anglais parlent aussi de backtrace.
Bon, c’est très simple :
Activez l’option « Débogage USB » dans la partie Options pour les développeurs des paramètres de votre téléphone
En cas d’absence de ce menu « Options pour les développeurs" : allez dans les Paramètres généraux, ouvrez « À propos de l’appareil ». Puis tapotez par quatre fois le « Numéro de Build » pour débloquer les « Options pour les développeurs ».
Installer adb via « sudo dnf install adb »
Branchez votre téléphone à votre ordinateur
Lancer la comment « adb devices » devrait le détecter
Si ne montre rien échoue, assurez-vous que votre téléphone détecte bien qu’il est branché en USB, et qu’il marque que la connexion est en mode « Déboguage USB »).
Pour extraire les journaux (logs), rien de plus simple puisqu’il faut saisir « adb logcat » dans son terminal.
Vous découvrirez probablement que votre téléphone est très bavard ! Restreindre la sortie est heureusement possible via la commande : « adb logcat "*: E" ».
Pensez à signaler vos problèmes ! (et à être gentil :))
Framasoft sera évidemment présente lors des RMLL (sans doute en petit comité, car en ce début d’été, nos membres seront un peu dispersés sur différents événements ou … en congés !). N’hésitez donc pas à venir à notre rencontre, ou à assister à l’une de nos conférences :)
Mais l’objet de ce billet, est surtout de vous annoncer que l’organisation des RMLL a proposé de réserver la journée du vendredi 7 à … une réunion de chatons !
Le collectif est toujours en phase de structuration et, tel un logiciel libre, est en développement permanent : on y ajoute des fonctionnalités, on explore des possibles, on corrige des bugs, on essaie de faire communauté, etc.
Les moments de rencontre, que ça soit entre membres du collectif, ou pour échanger avec des personnes connaissant peu ou pas le projet CHATONS, sont donc primordiaux.
L’opportunité offerte par les RMLL de nous proposer un temps long (1 journée complète) est donc à saisir !
Cette journée permettra, le matin, de rappeler (très rapidement) les objectifs, de présenter le fonctionnement actuel, et de travailler ensemble la « roadmap ». L’après-midi sera, lui, consacré à des ateliers thématiques (probablement : « juridique », « technique », « communication » et « organisation/économie ») en mode barcamp (= les personnes présentes choisiront elles-mêmes les thèmes de travail).
Bref, vous pourrez poser toutes les questions que vous avez toujours voulu savoir sur CHATONS, mais surtout nous proposer des patches sur la façon dont nous pourrions améliorer le fonctionnement du collectif.
Merci encore aux organisateur⋅ice⋅s des Rencontres de nous offrir ce temps de partages, d’échanges, de réflexion et de production !
Un panier de CHATONS, parce qu’on sait que vous aimez ça !
Et, en cadeau, deux petites vidéos (qui s’ouvriront au clic dans un nouvel onglet sur Vimeo) qui, nous l’espérons, vous donneront envie de venir aux RMLL :
Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.
Nous allons confier à deux développeurs, Briface et Jobriel, le soin de rédiger le code d’une petite application fort simple, à caractère pédagogique. Elle consiste à faire apparaître des formes générées aléatoirement.
Jobriel va rédiger le code nécessaire à la création de l’environnement graphique, c’est-à-dire les widgets tandis que Briface, de son côté, va rédiger le module permettant de faire apparaître de manière aléatoire, des formes qui sont soit des triangles, soit des cercles soit des carrés. La couleur de ces formes est également définie de manière aléatoire.
Au final, voici ce que nos deux gugusses doivent accomplir :
Le code de Jobriel
Commençons par le code de notre ami Jobriel :
#!/usr/bin/env python3
# -*- coding: utf8 -*-
from tkinter import*
import choice
class MainProg :
"""Création de l'environnement graphique de l'application"""
def __init__(self, main_window, h = 300, w = 300, color = 'white'):
"""Méthode constructeur"""
self.main_window = main_window
self.h = h
self.w = w
self.color = color
def widgets(self):
"""Création des widgets"""
self.main_frame = Frame(self.main_window, height=self.h,\\
width=self.w, bg=self.color)
self.main_frame.pack()
self.canevas = Canvas(self.main_frame, height=400, width=self.w,\\
bg=self.color)
self.canevas.pack(side=TOP)
self.frame_1 = Frame(self.main_frame, height=100, width=self.w,\\
bg=self.color)
self.frame_1.pack(side=BOTTOM)
self.random_choice = choice.RandomObjects(self.canevas)
self.button = Button(self.frame_1, height=1, width=5, text='Afficher',\\
relief='ridge', bd=3, bg='navy', fg='white',\\
font=('Times', 14, 'bold'), padx=20,\\
command = self.random_choice.random_choice)
self.button.pack(padx=20, pady=10)
#===== MAIN ===================================================================
if __name__ == '__main__':
main_window = Tk()
main_window.title('Une forme au hasard')
main_page = MainProg(main_window, 500, 500)
main_page.widgets()
main_window.mainloop()
ligne n° 4 : importation du module tkinter. ligne n° 5 : importation du module choice qui va nous permettre de faire apparaître de manière aléatoire, différentes formes telles que des carrés, des ronds, des triangles. Les couleurs de ces formes sont également définies de manière aléatoire.Pour les deux formes d’importation, je vous renvoie au chapitre sur les modules. Personnellement, je préfère la forme d’importation ci-dessous car il n’y a pas de risques de conflits entre des variables portant le même nom. En outre, elle permet de raccourcir le nom du module. tkinter devient tk :
import tkinter as tk
Pour de plus amples renseignements sur la bibliothèque tkinter, je vous invite à consulter cette documentation en français.
Ligne n° 43 : Nous trouvons une condition introduisant du code qui va s’exécuter uniquement si le programme est lancé de manière indépendante et non pas comme un module. Ici, c’est le cas. Par conséquent, cette partie du code s’exécute.
Ligne n° 45 : Création de l’objet main_window (fenêtre principale) par instanciation de la classe Tk() issue du module tkinter. Si j’avais écrit ceci à la ligne n° 4 : import tkinter as tk, alors la ligne n° 45 aurait été : main_window = tk.Tk().
Ligne n° 46 : application de la méthode title() sur l’objet main_window. Elle donne un titre à la fenêtre.
À ce stade, si on exécute le programme, voici ce qu’on obtient :
Ligne n° 48 : Création de l’objet main_page par instanciation de la classe MainProg(). Nous lui passons trois arguments qui sont main_window (la fenêtre mère), 500 (la hauteur de l’application) et 500 (la largeur). Nous choisissons de ne pas lui passer de paramètre de couleur. Ce sera donc la couleur par défaut qui va s’appliquer. Ligne n° 49 : Application de la méthode widgets() sur l’objet main_page.
Ligne n° 51 : Application de la méthode mainloop() sur l’objet main_window ce qui a pour effet de déclencher le réceptionnaire d’événements et de permettre l’exécution du programme.
Ligne n° 7 : On remonte tout en haut! Définition d’une classe fondamentale baptisée MainProg Ligne n° 10 : Méthode constructeur qui prend quatre paramètres:
self qui correspond à la référence de l’instance, c’est-à-dire l’objet main_page que nous avons instancié à la ligne n° 48. je rappelle qu’une méthode d’instance prend toujours au moins cet argument et que par convention, il est nommé self.
main_window qui correspond à la fenêtre principale et dont nous avons besoin pour instancier les widgets enfants.
h, w et color sont des paramètres qui possèdent une valeur par défaut. Si nous décidons de les ignorer, ce seront donc ces valeurs qui vont s’appliquer. C’est ce que nous avons fait avec color. Nous avons ignoré ce paramètre. Pour ce qui est des autres valeurs par défaut (h=300, w=300), nous avons choisi de les remplacer par 500 (voir ligne n° 48). Si nous décidons de ne pas respecter l’ordre de déclaration, il faut alors préciser le paramètre. Par exemple :
main_page = MainProg(main_window, color = ‘blue’, w=260, h=600)
Ligne n° 11 : Docstring
Lignes n° 13 à 16 : Création des attributs d’instance Ligne n° 18 : Méthode widgets (création de tous les widgets de l’application) Lignes n° 21 et 22 : Création de l’objet self.main_frame par instanciation de la classe Frame. Cette dernière créé un cadre que l’on peut remplir avec d’autres widgets. Nous pouvons lui passer plusieurs arguments. Notez bien la largeur (width) et la hauteur (height). Normalement, vous devez être capables de retrouver leurs valeurs. Notez également la barre oblique (antislash) qui permet d’écrire une instruction sur plusieurs lignes. La fondation Python préconise de ne pas dépasser 79 caractères par ligne, ce qui est assez strict. Dans la mesure du possible, il faut respecter cette convention.
Ligne n° 23 : Application de la méthode pack(). Cette dernière place le widget. Elle peut prendre des paramètres tels que TOP, BOTTOM, LEFT ou RIGHT qui poussent le widget dans la direction donnée.
À ce stade, si nous exécutons le programme, voici ce que nous obtenons. J’ai volontairement et provisoirement coloré en rouge, le fond du widget :
Lignes n° 25 et 26 : Création de l’objet self.canevas par instanciation de la classe Canvas. C’est ce widget qui va nous permettre de placer les formes aléatoires grâce à différentes méthodes qui lui sont liées. Ligne n° 27 : Méthode de placement pack(). Cette fois-ci, elle prend un paramètre (side=TOP) pour pousser le widget vers le haut. Lignes n° 29 à 31: Nous créons un nouvel objet de type Frame que nous plaçons tout en bas de sa fenêtre parente (side=BOTTOM). Dans ce widget, nous placerons le bouton Afficher.
Ligne n° 33: Création de l’objet random_choice par instanciation de la classe RandomObjects du module importé choice. Nous lui passons un paramètre qui est self.canevas. Donc, cela nous donne:
Je rappelle que l’utilisation du point en Python signifie l’appartenance. Ainsi, la classe RandomObjects appartient au module choice.
Lignes n° 35 à 38: Création du bouton afficher par instanciation de la classe Button. Celle-ci prend plusieurs paramètres qui sont :
La hauteur
La largeur
Le texte à afficher
Le relief de la bordure
L’épaisseur de la bordure
La couleur de fond
La couleur du texte
La police et la fonte de caractères
L’espacement horizontal du texte à l’intérieur du widget
La commande que le bouton déclenche.
Pour ce dernier paramètre, nous appliquons la méthode random_choice issue du module importé choice, sur l’objet que nous avons créé (random_choice). Cela nous donne :
command=self.random_choice.random_choice
Alors là, vous allez me dire : « Mais Ordinosor! Tu bé, tu bé-bé, tu bégayes? »
Absolument pas, sombres gougnafiers! Il n’y a aucun risque de collision ou de confusion puisque ces deux noms identiques n’évoluent pas dans les mêmes espaces.
Notez bien que la commande déclenche une méthode lorsque nous cliquons sur le bouton. Il ne faut donc pas mettre les parenthèses () à la fin de la commande car cela aurait pour effet de shunter le bouton et d’activer la méthode dès le lancement du programme! Donc, il ne faut pas écrire :
command=self.random_choice.random_choice()
Ligne n° 39: La méthode pack() place le bouton dans sa fenêtre parente en réservant un espace vertical (pady=20) et horizontal (padx=20).
J’ai coloré provisoirement les différents widgets pour mieux les visualiser. Si nous exécutons le programme à ce stade, voici ce que nous obtenons:
En rouge, le widget self.main_frame
En blanc, le widget self.canevas
En jaune, le widget self.frame_1
En bleu, le widget self.button
Merci pour ce travail, Jobriel! À présent, remettons tous les fonds des widgets en blanc Cliquons sur le bouton et voyons ce que notre ami Briface a codé…
Le code de Briface
#!/usr/bin/env python3
# -*- coding: utf8 -*-
from tkinter import*
import random
class RandomObjects :
"""Instancie aléatoirement les formes (triangles, cercles, carrés).
Les couleurs de ces formes sont également définies de manière aléatoire"""
def __init__(self, canevas):
"""Constructeur"""
self.canevas = canevas
def square(self):
"""Création du carré"""
self.square_object = self.canevas.create_rectangle(200, 150, 300, 250,\\
fill=self.random_color)
def circle(self):
"""Création du cercle"""
self.circle_object = self.canevas.create_oval(200, 150, 300, 250,\\
fill=self.random_color)
def triangle(self):
"""Création du triangle"""
self.polygon = self.canevas.create_polygon(250, 150, 200, 250, 300,\\
250,fill=self.random_color)
def random_choice(self):
"""cf docstring class RandomObjects"""
self.canevas.delete('all')
self.random_color=random.choice(['green','red','yellow','blue','black'])
random.choice([self.square, self.circle, self.triangle])()
Ligne n° 5 : importation du module random qui va nous permettre de faire des choix aléatoires. Ligne n° 7: Création la classe RandomObjects. Ligne n° 11: Méthode constructeur avec deux paramètres, la référence d’instance self et canevas. Ligne n° 13: Déclaration d’une variable d’instance. Ligne n° 16: Définition d’une méthode qui dessine un carré. Ligne n° 19: Pour cela, nous utilisons la méthode create_rectangle qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage. Ligne n° 22: Définition d’une méthode qui dessine un cercle plein. Ligne n° 25: Pour cela, nous utilisons la méthode create_oval qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage. Ligne n° 28: Définition d’une méthode qui dessine un triangle. Ligne n° 31: Pour cela, nous utilisons la méthode create_polygon qui prend six coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 34: Définition de la méthode random_choice. Ligne n° 37: Nous appliquons la méthode delete(‘all’) sur le widget self.canevas pour effacer une éventuelle forme avant que la suivante ne prenne sa place. Ligne n° 38: Déclaration de la variable self.random_color. La valeur qui lui est affectée est une couleur choisie au hasard dans la liste passée en argument à la méthode random.choice.
Là encore, attention de ne pas confondre la méthode random_choice que nous avons nous-même définie et la méthode random.choice, c’est-à-dire la méthode choice du module importé random (ligne n° 5)!
Ligne n° 39: Cette fois-ci, random.choice choisit au hasard la méthode qui va matérialiser la forme. Pour que cette méthode exécute ses instructions, nous rajoutons tout à la fin, deux parenthèses. Sans ces deux parenthèses, rien ne se passerait: random.choice([self.square, self.circle, self.triangle])()
Merci à toi , Briface, pour ce module qui exécute à la perfection la tâche qui lui a été impartie.