375 lines
13 KiB
Markdown
375 lines
13 KiB
Markdown
|
---
|
||
|
title: Ma première contribution à KDE
|
||
|
description: Ma première configuration et ma première contribution à l'environnement mobile (Plasma-Mobile).
|
||
|
slug: kde-first-contrib
|
||
|
date: 2024-01-12 00:00:00+0000
|
||
|
categories:
|
||
|
- Linux
|
||
|
tags:
|
||
|
- KDE
|
||
|
weight: 1 # You can add weight to some posts to override the default sorting (date descending)
|
||
|
---
|
||
|
|
||
|
## 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](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](https://kde.org/fr/plasma-desktop/) est l'environnement de bureau développé pour Linux.
|
||
|
|
||
|
## Ma configuration
|
||
|
|
||
|
Pour développer sur KDE, KDE fournis un utilitaire assez puissant `kdesrc-build`.
|
||
|
Il permet de configurer l'IDE, compiler, exécuter et gérer les dépendances avec l'aide d'une seule ligne de commande.
|
||
|
|
||
|
Pour le configurer, il suffit de suivre la procédure sur ce [lien](https://community.kde.org/Get_Involved/development/Set_up_a_development_environment).
|
||
|
|
||
|
### Mes premières difficultés
|
||
|
|
||
|
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.
|
||
|
Il n'y avait aucune documentation pour migrer la configuration fournie de base, il fallait fouiller sur Github ou sur les blogs pour réussir
|
||
|
à avoir la configuration.
|
||
|
Aujourd'hui, il suffit juste de suivre le lien ci-dessus et on peut directement travailler sur KDE 6.
|
||
|
|
||
|
Pour le développement sur KDE Plasma 6, j'ai dû faire quelques réajustements sur le fichier `~/.config/kdesrc-buildrc`.
|
||
|
|
||
|
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.
|
||
|
|
||
|
```
|
||
|
global
|
||
|
branch-group kf6-qt6
|
||
|
[...]
|
||
|
end global
|
||
|
|
||
|
include ~/kde/src/kdesrc-build/data/build-include/kf6-common-options.ksb
|
||
|
include ~/kde/src/kdesrc-build/data/build-include/kf6-frameworks.ksb
|
||
|
include ~/kde/src/kdesrc-build/data/build-include/kf6-workspace.ksb
|
||
|
include ~/kde/src/kdesrc-build/data/build-include/kf6-applications.ksb
|
||
|
include ~/kde/src/kdesrc-build/data/build-include/kf6-kdepim.ksb
|
||
|
```
|
||
|
|
||
|
### Configurations utiles
|
||
|
|
||
|
#### Désactiver l'arrêt de la compilation lors d'une erreur de compilation.
|
||
|
|
||
|
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`.
|
||
|
|
||
|
#### 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`
|
||
|
|
||
|
#### 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 contribué sur le support de la lampe torche pour l'environnement Plasma Mobile.
|
||
|
La lampe torche 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)).
|
||
|
J'ai réécris le module pour que ça fonctionne de manière générale sur tous les téléphones.
|
||
|
|
||
|
### 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 la carte mère ou sur le SOC.
|
||
|
Mais on peut aussi les trouver plus facilement dans le répertoire `/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) une fois le support des leds ajoutées.
|
||
|
Udev pour faire simple, c'est une librairie qui permet d'interagir avec les appareils assez directement sans intermédiaire.
|
||
|
La librairie permet également 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 liste 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 sur lequel on appliquera tous les filtres.
|
||
|
> On peut voir une class comme une catégorie d'appareils.
|
||
|
|
||
|
```cpp
|
||
|
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
|
||
|
```
|
||
|
|
||
|
J'applique le filtre pour lister uniquement ceux qui appartiennent à la class `leds`.
|
||
|
|
||
|
```cpp
|
||
|
#define TORCH_SUBSYSTEM "leds"
|
||
|
...
|
||
|
udev_enumerate_add_match_subsystem(enumerate, TORCH_SUBSYSTEM);
|
||
|
```
|
||
|
|
||
|
J'applique le filtre pour lister 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.
|
||
|
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 le 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 chaque 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 de Plasma Mobile.
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### Info utile pour débugger KDE Plama Mobile depuis Postmarket OS
|
||
|
|
||
|
Le fichier de log se situe dans `~/.local/state/tinydm.log`
|