Bluetooth: Support multiple devices

This commit is contained in:
Linus Dierheimer
2023-01-24 12:02:20 +01:00
parent 4967d0a222
commit 209d0c98d9
10 changed files with 117 additions and 81 deletions
+1
View File
@@ -199,6 +199,7 @@ __fastfetch_completion()
"--gpu-hide-integrated"
"--gpu-hide-discrete"
"--disk-show-unknown"
"--bluetooth-show-disconnected"
)
local FF_OPTIONS_STRING=(
+2
View File
@@ -160,6 +160,8 @@ static void defaultConfig(FFinstance* instance)
instance->config.diskShowUnknown = false;
instance->config.diskShowSubvolumes = false;
instance->config.bluetoothShowDisconnected = false;
ffStrbufInitA(&instance->config.batteryDir, 0);
ffStrbufInitA(&instance->config.separatorString, 0);
+6
View File
@@ -247,6 +247,12 @@
# Default is "/:/home" ("C:\\;D:\\ ..." on Windows).
#--disk-folders /:/home
# Bluetooth show disconnected option
# Sets if disconnected bluetooth devices should be printed
# Must be either true or false
# Default is false.
#--bluetooth-show-disconnected false
# Percentage output type option
# Applies to all modules that prints percentage values. Currently memory, swap, disk, battery and CPU usage are supported.
# Only works with default format ( without --module-format option ).
+31 -30
View File
@@ -100,36 +100,37 @@ Library options: Set the path of a library to load
--lib-cjson <path>
Module specific options:
--title-fqdn <?value>: Set if the title should use fully qualified domain name. Default is false
--separator-string <str>: Set the string printed by the separator module
--os-file <path>: Set the path to the file containing OS information
--shell-version <?value>: Set if shell version should be detected and printed
--terminal-version <?value>: Set if terminal version should be detected and printed
--disk-folders <folders>: A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows)
--disk-show-removable <?value>: Set if removable volume should be printed. Default is true
--disk-show-hidden <?value>: Set if hidden volumes should be printed. Default is false
--disk-show-subvolumes <?value>: Set if subvolumes should be printed. Default is false
--disk-show-unknown <?value>: Set if unknown (unable to detect sizes) volumes should be printed. Default is false
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
--cpu-temp <?value>: Detect and display CPU temperature if supported. Default is false
--gpu-temp <?value>: Detect and display GPU temperature if supported. Default is false
--gpu-hide-integrated <?value>: Hide integrated GPU if supported. Default is false
--gpu-hide-discrete <?value>: Hide discrete GPU if supported. Default is false
--battery-temp <?value>: Detect and display Battery temperature if supported. Default is false
--localip-show-ipv4 <?value>: Show IPv4 addresses in local ip module. Default is true
--localip-show-ipv6 <?value>: Show IPv6 addresses in local ip module. Default is false
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
--localip-name-prefix <str>: Show IPs with given name prefix only. Default is empty
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
--public-ip-url: The URL of public IP detection server to be used.
--weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0)
--weather-output-format: The output weather format to be used. It must be URI encoded.
--player-name: The name of the player to use
--gl <value>: Set the OpenGL context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
--percent-type <value>: Set the percentage output type. 1 for percentage number, 2 for bar, 3 for both, 6 for bar only. Default is 1
--command-shell <str>: Set the shell program to execute the command text. Default is cmd for Windows, csh for FreeBSD, bash for others
--command-key <str>: Set the module key to display, can be specified mulitple times
--command-text <str>: Set the command text to be executed, can be specified mulitple times
--title-fqdn <?value>: Set if the title should use fully qualified domain name. Default is false
--separator-string <str>: Set the string printed by the separator module
--os-file <path>: Set the path to the file containing OS information
--shell-version <?value>: Set if shell version should be detected and printed
--terminal-version <?value>: Set if terminal version should be detected and printed
--disk-folders <folders>: A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows)
--disk-show-removable <?value>: Set if removable volume should be printed. Default is true
--disk-show-hidden <?value>: Set if hidden volumes should be printed. Default is false
--disk-show-subvolumes <?value>: Set if subvolumes should be printed. Default is false
--disk-show-unknown <?value>: Set if unknown (unable to detect sizes) volumes should be printed. Default is false
--bluetooth-show-disconnected: <?value>: Set if disconnected bluetooth devices should be printed. Default is false
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
--cpu-temp <?value>: Detect and display CPU temperature if supported. Default is false
--gpu-temp <?value>: Detect and display GPU temperature if supported. Default is false
--gpu-hide-integrated <?value>: Hide integrated GPU if supported. Default is false
--gpu-hide-discrete <?value>: Hide discrete GPU if supported. Default is false
--battery-temp <?value>: Detect and display Battery temperature if supported. Default is false
--localip-show-ipv4 <?value>: Show IPv4 addresses in local ip module. Default is true
--localip-show-ipv6 <?value>: Show IPv6 addresses in local ip module. Default is false
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
--localip-name-prefix <str>: Show IPs with given name prefix only. Default is empty
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
--public-ip-url: The URL of public IP detection server to be used.
--weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0)
--weather-output-format: The output weather format to be used. It must be URI encoded.
--player-name: The name of the player to use
--gl <value>: Set the OpenGL context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
--percent-type <value>: Set the percentage output type. 1 for percentage number, 2 for bar, 3 for both, 6 for bar only. Default is 1
--command-shell <str>: Set the shell program to execute the command text. Default is cmd for Windows, csh for FreeBSD, bash for others
--command-key <str>: Set the module key to display, can be specified mulitple times
--command-text <str>: Set the command text to be executed, can be specified mulitple times
Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci"
If a value starts with a ?, it is optional. "true" will be used if not set.
+1 -7
View File
@@ -8,14 +8,8 @@ const FFBluetoothResult* ffDetectBluetooth(const FFinstance* instance)
{
FF_DETECTION_INTERNAL_GUARD(FFBluetoothResult,
ffStrbufInit(&result.error);
ffStrbufInit(&result.name);
ffStrbufInit(&result.address);
ffStrbufInit(&result.type);
result.battery = 0;
ffListInit(&result.devices, sizeof(FFBluetoothDevice));
ffDetectBluetoothImpl(instance, &result);
if(result.error.length == 0 && result.name.length == 0)
ffStrbufAppendS(&result.error, "No bluetooth device found");
)
}
+8 -2
View File
@@ -5,13 +5,19 @@
#include "fastfetch.h"
typedef struct FFBluetoothResult
typedef struct FFBluetoothDevice
{
FFstrbuf error;
FFstrbuf name;
FFstrbuf address;
FFstrbuf type;
uint8_t battery; // 0-100%
bool connected;
} FFBluetoothDevice;
typedef struct FFBluetoothResult
{
FFstrbuf error;
FFlist devices; // List of FFBluetoothDevice
} FFBluetoothResult;
const FFBluetoothResult* ffDetectBluetooth(const FFinstance* instance);
+24 -28
View File
@@ -39,7 +39,7 @@ array [ //root
]
*/
static void detectBluetoothProperty(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter, bool* connected)
static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothDevice* device)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
@@ -81,68 +81,66 @@ static void detectBluetoothProperty(FFBluetoothResult* bluetooth, FFDBusData* db
dbus->lib->ffdbus_message_iter_next(&deviceIter);
if(strcmp(deviceProperty, "Address") == 0)
ffDBusGetValue(dbus, &deviceIter, &bluetooth->address);
ffDBusGetValue(dbus, &deviceIter, &device->address);
else if(strcmp(deviceProperty, "Name") == 0)
ffDBusGetValue(dbus, &deviceIter, &bluetooth->name);
ffDBusGetValue(dbus, &deviceIter, &device->name);
else if(strcmp(deviceProperty, "Icon") == 0)
ffDBusGetValue(dbus, &deviceIter, &bluetooth->type);
ffDBusGetValue(dbus, &deviceIter, &device->type);
else if(strcmp(deviceProperty, "Percentage") == 0)
ffDBusGetByte(dbus, &deviceIter, &bluetooth->battery);
ffDBusGetByte(dbus, &deviceIter, &device->battery);
else if(strcmp(deviceProperty, "Connected") == 0)
{
ffDBusGetBool(dbus, &deviceIter, connected);
if(!*connected)
return; //Just for performance, we don't need to continue if we're not connected
}
ffDBusGetBool(dbus, &deviceIter, &device->connected);
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
}
}
static bool detectBluetoothObject(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter)
static void detectBluetoothObject(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return false;
return;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH)
return false;
return;
const char* objectPath;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath);
//We don't want adapter objects
if(strstr(objectPath, "dev_") == NULL)
return false;
return;
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
return false;
return;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
bool connected = false;
FFBluetoothDevice* device = ffListAdd(&bluetooth->devices);
ffStrbufInit(&device->name);
ffStrbufInit(&device->address);
ffStrbufInit(&device->type);
device->battery = 0;
device->connected = false;
while(true)
{
detectBluetoothProperty(bluetooth, dbus, &arrayIter, &connected);
detectBluetoothProperty(dbus, &arrayIter, device);
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
}
if(!connected || bluetooth->name.length == 0)
if(device->name.length == 0)
{
ffStrbufClear(&bluetooth->address);
ffStrbufClear(&bluetooth->name);
ffStrbufClear(&bluetooth->type);
bluetooth->battery = 0;
return false;
ffStrbufDestroy(&device->name);
ffStrbufDestroy(&device->address);
ffStrbufDestroy(&device->type);
--bluetooth->devices.length;
}
return true;
}
static void detectBluetoothRoot(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter)
@@ -155,9 +153,7 @@ static void detectBluetoothRoot(FFBluetoothResult* bluetooth, FFDBusData* dbus,
while(true)
{
if(detectBluetoothObject(bluetooth, dbus, &arrayIter))
return;
detectBluetoothObject(bluetooth, dbus, &arrayIter);
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
}
+2
View File
@@ -1310,6 +1310,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
instance->config.diskShowSubvolumes = optionParseBoolean(value);
else if(strcasecmp(key, "--disk-show-unknown") == 0)
instance->config.diskShowUnknown = optionParseBoolean(value);
else if(strcasecmp(key, "--bluetooth-show-disconnected") == 0)
instance->config.bluetoothShowDisconnected = optionParseBoolean(value);
else if(strcasecmp(key, "--battery-dir") == 0)
optionParseString(key, value, &instance->config.batteryDir);
else if(strcasecmp(key, "--separator-string") == 0)
+2
View File
@@ -184,6 +184,8 @@ typedef struct FFconfig
bool diskShowUnknown;
bool diskShowSubvolumes;
bool bluetoothShowDisconnected;
FFstrbuf batteryDir;
FFstrbuf separatorString;
+40 -14
View File
@@ -4,6 +4,29 @@
#define FF_BLUETOOTH_MODULE_NAME "Bluetooth"
#define FF_BLUETOOTH_NUM_FORMAT_ARGS 4
static void printDevice(FFinstance* instance, const FFBluetoothDevice* device, uint8_t index)
{
if(instance->config.bluetooth.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_BLUETOOTH_MODULE_NAME, index, &instance->config.bluetooth.key);
ffStrbufWriteTo(&device->name, stdout);
if(device->battery > 0)
printf(" (%d%%)", device->battery);
putchar('\n');
}
else
{
ffPrintFormat(instance, FF_BLUETOOTH_MODULE_NAME, index, &instance->config.bluetooth, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &device->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->address},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->type},
{FF_FORMAT_ARG_TYPE_UINT8, &device->battery}
});
}
}
void ffPrintBluetooth(FFinstance* instance)
{
const FFBluetoothResult* bluetooth = ffDetectBluetooth(instance);
@@ -14,23 +37,26 @@ void ffPrintBluetooth(FFinstance* instance)
return;
}
if(instance->config.bluetooth.outputFormat.length == 0)
FFlist filtered;
ffListInit(&filtered, sizeof(FFBluetoothDevice*));
FF_LIST_FOR_EACH(FFBluetoothDevice, device, bluetooth->devices)
{
ffPrintLogoAndKey(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth.key);
ffStrbufWriteTo(&bluetooth->name, stdout);
if(!device->connected && !instance->config.bluetoothShowDisconnected)
continue;
if(bluetooth->battery > 0)
printf(" (%d%%)", bluetooth->battery);
putchar('\n');
*(FFBluetoothDevice**)ffListAdd(&filtered) = device;
}
else
if(filtered.length == 0)
{
ffPrintFormat(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &bluetooth->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &bluetooth->address},
{FF_FORMAT_ARG_TYPE_STRBUF, &bluetooth->type},
{FF_FORMAT_ARG_TYPE_UINT8, &bluetooth->battery}
});
ffPrintError(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth, "No bluetooth devices found");
return;
}
for(uint32_t i = 0; i < filtered.length; i++)
{
uint8_t index = (uint8_t) (filtered.length == 1 ? 0 : i + 1);
printDevice(instance, *(FFBluetoothDevice**)ffListGet(&filtered, i), index);
}
}