Rewrite KDE contribution

This commit is contained in:
Florian RICHER 2024-02-18 14:03:33 +01:00
parent f832f5f3e2
commit 3a7762fdba

View file

@ -1,9 +1,9 @@
---
image_path: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Test-Logo.svg/783px-Test-Logo.svg.png?20150906031702"
slug: kde_first_conf
title: Contribuer sur le projet KDE
title: Mes premières contributions à KDE
date: 2023-11-26T00:00:00Z
description: Comment contribuer financièrement, en remontant les bugs ou en aidant au développement de KDE directement
description: Ma première configuration et ma première contribution à l'environnement mobile (Plasma-Mobile).
project_link: none
draft: true
tags:
@ -11,73 +11,47 @@ tags:
- linux
---
# Qu'est-ce que KDE ?
# Mes premières contributions à KDE
## Rapide rappel à propos de KDE
KDE est un projet qui a pour but de développer des logiciels open-source. Le projet comporte plusieurs éléments les plus connus.
- KF5 ou KF6 est un ensemble de librairie utilisé pour le developpement de l'ensemble des logiciels de KDE. Kirigami une librairie qui permet le développement sur toutes plateformes de manière responsive fait partie de KF5/KF6.
- [KF5 ou KF6](https://develop.kde.org/products/frameworks/) est un ensemble de librairies utilisées pour le développement de l'ensemble des logiciels de KDE. Il est basé sur la librairie [QT](https://www.qt.io/).
> Exemple : Kirigami que l'on peut voir comme un "flutter".
>
> Note:
>
> KF5 => Basé sur QT5
> KF6 => Basé sur QT6
- Plasma Shell est l'environnement de bureau développé pour Linux.
- [Plasma Shell](https://kde.org/fr/plasma-desktop/) est l'environnement de bureau développé pour Linux.
# Comment contribuer à KDE
## Ma configuration
1. Financièrement
Pour développer sur KDE, KDE fournis un utilitaire assez puissant `kdesrc-build`.
Il permet de configurer l'IDE, compiler, exécuter et la gestion des dépendances avec l'aide d'une seule ligne de commande.
On peut contribuer de plusieurs manières, d'abord on peut simplement contribuer financièrement au projet avec le lien [Donations](https://kde.org/fr/community/donations/).
Pour le configurer, il suffit de suivre la procédure sur ce lien [Configuration de l'environnement de développement](https://community.kde.org/Get_Involved/development/Set_up_a_development_environment).
2. Rapport de bug
### Mes premières difficultés
N'importe qui peut contribuer en aidant les développeurs de KDE en testant et en remontant les soucis rencontrées avec le lien [KDE Bugs](https://bugs.kde.org/) ou directement sur [Gitlab](https://invent.kde.org).
Les distributions permettent en général également de tester la version instable de KDE pour tester en avant première les nouveautés.
Cette étape est souvent sous-estimé alors que ça permet au développeur de trouver beaucoup de bugs. Plus il y a de beta-testeur, plus il y a de machine et de configuration de machine différente, plus il y a de chance de trouver des bugs. On remontant les bugs, ça permet de corriger et d'améliorer l'expérience utilisateur pour ceux qui installeront la version Final.
Il faut savoir que quand j'ai commencé à vouloir contribuer au projet KDE. Le projet était en train de migrer de QT5 à QT6.
Donc, les configurations nécessaires pour compiler correctement la version 6 était nettement plus compliqué que maintenant.
Aujourd'hui, il suffit juste de suivre le lien ci-dessus et on peut direct travailler sur KDE 6.
Avant, on avait aucune documentation pour la migrer n'ont plus, il fallait fouiller sur Github ou sur les blogs pour réussir
à avoir la configuration.
3. Participation au développement de KDE
Pour le développement sur KDE Plasma 6, j'ai dû faire quelques réajustements sur le fichier `~/.config/kdesrc-buildrc`.
La dernière façon de contribuer et de participer aux développement de KDE.
Pour aider les nouveaux arrivants, KDE trie les bugs qui nécessite peut de connaissance pour apprendre doucement depuis [Bugs KDE](https://bugs.kde.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&keywords=junior-jobs&list_id=1340815) et [Gitlab](https://invent.kde.org/dashboard/issues?sort=created_date&state=opened&label_name%5B%5D=Junior+Job).
J'ai changé la branche par défaut avec l'option `branch-group kf6-qt6`.
Elle permet de cloner les repositories correctement et d'ajouter l'option cmake `-DBUILD_WITH_QT6=on`.
J'ai aussi changé les fichiers de configuration utilisées pour obtenir le résultat ci-dessous.
# Contribuer en aidant au développpement de KDE
Il existe un outil pour faciliter la compilation de l'ensemble des outils de KDE et de l'environnement de KDE. Cet outil c'est `kdesrc-build`, une fois configuré, on peut facilement compiler et lancer un outil spécifique de KDE avec les commandes `kdesrc-build [nom de l'outil]` et `kdesrc-run [nom de l'outil]`. Ça permet de gagner pas mal de temps. L'outil permet également de générer l'ensemble des configurations pour le `LSP` (Language Server Protocol) utilisé par exemple par `Visual Studio Code`. Tout est conçu pour que l'on est juste à lancer notre IDE favoris et commencer directement le développement sur KDE sans ce préocupper du reste.
On peut également installer une session KDE Plasma Shell pour lancer l'environnement Plasma compilé à l'instant directement depuis l'interface de connexion de la distribution Linux.
## Configuration de `kdesrc-buildrc`
Tout d'abord, il faut avoir installé et configuré l'outil `kdesrc-build`. Pour le configurer, il suffit de suivre la procédure sur ce lien [Configuration de l'environnement de développement](https://community.kde.org/Get_Involved/development/Set_up_a_development_environment).
Pour le développement sur KDE Plasma 6, j'ai rajouté `branch-group kf6-qt6` ce qui va automatiquement switcher sur la bonne branche lors du clonage des repository git de KDE mais également rajouté l'option cmake `-DBUILD_WITH_QT6=on` au moment de la configuration des projets avec cmake pour activer la compilation avec QT6.
Pour éviter de s'arreter en plein milieu de la compilation des outils à cause d'un seul outil, j'ai rajouté l'option `stop-on-failure false`, je pars du principe que c'est pas grave si l'un des logiciels ne se compile pas.
Les options `compile-commands-linking true` et `compile-commands-export true` permet d'améliorer le support avec les `LSP` en mettant en cache l'ensemble des librairies nécessaire à la compilation dans un fichier. Et l'option `generate-vscode-project-config true` permet de générer un projet `Visual Studio Code`. Ça évite de devoir le configuré surtout que l'option va rajouter aussi la liste des extensions nécessaires pour que `Visual Studio Code` ce configure directement.
Fichier final sans les commentaires `~/.config/kdesrc-buildrc`
```conf
```
global
branch-group kf6-qt6
install-dir ~/kde/usr
source-dir ~/kde/src
build-dir ~/kde/build
num-cores auto
num-cores-low-mem auto
install-session-driver false
install-environment-driver true
stop-on-failure false
directory-layout flat
cmake-generator Kate - Ninja
compile-commands-linking true
compile-commands-export true
generate-vscode-project-config true
[...]
end global
include ~/kde/src/kdesrc-build/data/build-include/kf6-common-options.ksb
@ -87,11 +61,311 @@ include ~/kde/src/kdesrc-build/data/build-include/kf6-applications.ksb
include ~/kde/src/kdesrc-build/data/build-include/kf6-kdepim.ksb
```
## Utilisation de `kdesrc-build`
### Configurations utiles
Pour lancer la compilation de l'ensemble des outils KDE et de l'environnement Plasma, il suffit d'executer la commande `kdesrc-build`.
Pour compiler uniquement un seul outil, on peut executer la commande `kdesrc-build kate` par exemple pour compiler uniquement `kate` et ces dépendances.
`kdesrc-buikd -D kate` pour compiler sans inclure les dépendances.
`kdesrc-build -S` pour ne pas mettre à jour les sources du projets (Pratique si on est en train de développer une feature).
1. Désactiver l'arrêt de la compilation lors d'une erreur de compilation.
Si on souhaite tester ce que l'on a fait sur un projet, on peut chainer les options `kdesrc-build -S -D [projet]` ce qui permet de compiler uniquement notre code sans les dépendances et ensuite faire `kdesrc-run [projet]` pour le lancer.
En général, `kdesrc-build` s'adapte et retire tous les projets qui dépendent de la dépendance qui n'a pas réussi à compiler.
Le projet était encore en cours de développement donc les erreurs de compilations étaient très régulières.
J'ai tout simplement désactivé avec l'option `stop-on-failure false`.
2. Activer le support des LSP
C'est très pratique si on utilise VSCode ou même n'importe quel outil qui supporte les [LSP](https://microsoft.github.io/language-server-protocol/).
Il suffit d'activer les options:
* `compile-commands-linking` => `true`
* `compile-commands-export` => `true`
3. Générer les projets VSCode
Il va générer automatiquement les workspaces VSCode avec les extensions recommander et le paramètrage par défaut.
Ça permet de travailler dans de très bonne condition avec VSCode.
Il suffit de l'activer avec `generate-vscode-project-config true`
### Options utiles pour la commande kdesrc-build
* `-D` : Pour ne pas inclure les dépendances dans la compilation
> Exemple: kdesrc-build -D kate
* `-S` : Pour ne pas mettre à jour les sources
> Exemple: kdesrc-build -S kate
## Ma contribution
J'ai travaillé sur le support de la lampe torche pour l'environnement Plasma Mobile.
La fonctionnalité fonctionnait uniquement sur les [pinephones](https://pine64.org/devices/pinephone/) en utilisant le fichier en dure `/sys/devices/platform/led-controller/leds/white:flash/brightness`
([Source](https://invent.kde.org/plasma/plasma-mobile/-/blob/f970aa7acf2e9794ab4ed6b75e8f549bece83561/quicksettings/flashlight/flashlightutil.cpp#L17)).
### Rappel sur le fonctionnement du noyau Linux autour des leds
Pour comprendre comment la fonctionnalité, un petit rappel s'impose autour du fonctionnement des leds avec le noyau Linux.
Dès qu'une led est détecté par le noyau, il va mettre à disposition plusieurs fichiers.
On les trouvent dans le dossier correspondant au driver et aussi l'emplacement physique sur le circuit.
Mais on peut aussi les trouver plus simplement dans `/sys/class/leds/`.
> sys => Fichiers système
> class => Trier par class.
> leds => La class `leds`. On peut trouver aussi par appareil `bluetooth`, puce `tpm`, ...
On disposent de plusieurs fichiers importants :
* `brightness` : Permet de changer ou de récupérer l'intensité de la led actuelle.
* `max_brightness` : Permet de connaitre l'intensité max de la led.
* `color` : Ce fichier n'existe pas tout le temps mais permet d'avoir la couleur de la led.
* Le reste des fichiers ne sont pas important pour nous.
### Explication du fonctionnement de mon code petit à petit
Tout d'abord, il faut savoir que j'utilise la libraire udev. Il est prévu que je migre vers la librairie [Solid](https://invent.kde.org/frameworks/solid).
Udev pour faire simple, c'est une librairie qui permet d'interagir avec les appareils assez directement sans intermédiaire.
La librairie permet de lister, filtrer, détecter si un appareil est connecté/déconnecté, ....
Pour commencer, je dois d'abord instancier Udev avec pour l'utiliser par la suite.
```cpp
struct udev *udev = udev_new();
```
Ensuite, je souhaite lister tous les périphériques qui m'intéressent donc ceux appartenant à la class `leds`.
Pour ça, il me suffit de créer un énumerateur qui me permettra de choisir tous mes filtres.
```cpp
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
```
Je choisis de filtrer que ceux qui appartiennent à la class `leds`.
```cpp
#define TORCH_SUBSYSTEM "leds"
...
udev_enumerate_add_match_subsystem(enumerate, TORCH_SUBSYSTEM);
```
Je filtre uniquement ceux qui ont dans le nom `flash` ou `torch`.
```cpp
udev_enumerate_add_match_sysname(enumerate, "*:torch");
udev_enumerate_add_match_sysname(enumerate, "*:flash");
```
Puis je lance le scan avec mes filtres.
```cpp
udev_enumerate_scan_devices(enumerate);
```
Au début, il faut savoir que je prenais le premier appareil avec le code ci-dessous mais certain téléphone ont une torche de couleur jaune et blanche.
Donc, certain utilisateur malheureusement ne pouvait pas utiliser la fonctionnalité.
```cpp
struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry *entry = udev_list_entry_get_next(devices);
```
[Source](https://invent.kde.org/plasma/plasma-mobile/-/blob/5c6a97caa52d549c0cb02b17fc65a3a7d729d237/quicksettings/flashlight/flashlightutil.cpp)
Donc, j'ai changé le code avec ce code ci-dessous qui permet d'itérer sur tous les appareils.
```cpp
struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry *entry = nullptr;
struct udev_device *device = nullptr;
udev_list_entry_foreach(entry, devices)
{
[...]
}
```
Pour chaque appareil, j'ai récuperé le répertoire ou se situe l'appareil avec le code ci-dessous
qui me renvoie par exemple: `/sys/devices/platform/led-controller/leds/white:flash`.
```cpp
const char *path = udev_list_entry_get_name(entry);
```
J'instancie une instance udev_device pour interagir avec lui depuis le répertoire.
```cpp
struct udev_device *device = udev_device_new_from_syspath(udev, path);
```
Et à partir de là, il me suffit de lire les fichiers dont j'ai besoin.
```cpp
const char *maxBrightness = udev_device_get_sysattr_value(device, "[NOM DU FICHIER]");
```
Je lis d'abord le fichier 'color' et je regarde si la couleur est blanche sinon je continue.
Si je ne trouve pas de led de couleur blanche, je prends la dernière valeur récupérée.
Une fois pour appareil trouvé, il me reste plus qu'à récupérer les infos dont j'ai besoin.
Donc, la luminosité maximale `max_brightness` et la luminosité actuelle `brightness` pour correctement initialiser l'interface.
Quand je souhaite changer la valeur, je dois d'abord convertir la valeur entière en chaîne de charactère.
```cpp
const_cast<char *>(m_torchEnabled ? "0" : m_maxBrightness)
```
Ensuite, je change la luminosité
```cpp
udev_device_set_sysattr_value(m_device, "brightness", nouvelle_valeur_en_char_*);
```
### Fichier final
Source : https://invent.kde.org/plasma/plasma-mobile/-/blob/d162f96a63600d5b45bb8294afdb84efd85833f9/quicksettings/flashlight/flashlightutil.cpp
```cpp
/*
* SPDX-FileCopyrightText: 2020 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "flashlightutil.h"
#include <cstring>
#include <fcntl.h>
#include <libudev.h>
#include <unistd.h>
#include <QDebug>
#include <QFileInfo>
#define TORCH_SUBSYSTEM "leds"
FlashlightUtil::FlashlightUtil(QObject *parent)
: QObject{parent}
, m_device{nullptr}
, m_isAvailable{false}
{
findTorchDevice();
}
FlashlightUtil::~FlashlightUtil()
{
if (m_device != nullptr) {
udev_device_unref(m_device);
}
}
void FlashlightUtil::toggleTorch()
{
if (!isAvailable()) {
qWarning() << "Flashlight not available";
return;
}
int ret = udev_device_set_sysattr_value(m_device, "brightness", const_cast<char *>(m_torchEnabled ? "0" : m_maxBrightness));
if (ret < 0) {
qWarning() << "Flashlight can't be toggled";
return;
}
m_torchEnabled = !m_torchEnabled;
Q_EMIT torchChanged(m_torchEnabled);
}
bool FlashlightUtil::torchEnabled() const
{
return m_torchEnabled;
}
bool FlashlightUtil::isAvailable() const
{
return m_isAvailable;
}
void FlashlightUtil::findTorchDevice()
{
if (m_device != nullptr) {
udev_device_unref(m_device);
}
m_device = nullptr;
m_isAvailable = false;
struct udev *udev = udev_new();
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, TORCH_SUBSYSTEM);
udev_enumerate_add_match_sysname(enumerate, "*:torch");
udev_enumerate_add_match_sysname(enumerate, "*:flash");
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry *entry = nullptr;
struct udev_device *device = nullptr;
udev_list_entry_foreach(entry, devices)
{
const char *path = udev_list_entry_get_name(entry);
if (path == nullptr) {
continue;
}
if (device != nullptr) {
udev_device_unref(device); // Use to free memory from previous loop iteration
}
device = udev_device_new_from_syspath(udev, path);
if (device == nullptr) {
continue;
}
qInfo() << "Found flashlight device : " << path;
const char *color = udev_device_get_sysattr_value(device, "color");
if (color == nullptr) {
continue;
}
qInfo() << "Flash color : " << color;
if (std::strcmp(color, "white") == 0) {
break;
}
}
if (device == nullptr) {
qWarning() << "No flashlight device found";
return;
}
const char *maxBrightness = udev_device_get_sysattr_value(device, "max_brightness");
if (maxBrightness == nullptr) {
qWarning() << "Failed to read max_brightness from udev device";
return;
}
qInfo() << "Flash maxBrightness : " << maxBrightness;
const char *brightness = udev_device_get_sysattr_value(device, "brightness");
if (brightness == nullptr) {
qWarning() << "Failed to read brightness from udev device";
return;
}
qInfo() << "Flash brightness : " << brightness;
m_maxBrightness = maxBrightness;
m_device = device;
m_isAvailable = true;
m_torchEnabled = std::strcmp(brightness, "0") != 0;
udev_enumerate_unref(enumerate);
udev_unref(udev);
}
```