mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2025-02-20 11:43:27 +08:00
Bluetooth module
This commit is contained in:
parent
e0b2db17c2
commit
25e81b39f9
@ -1,3 +1,8 @@
|
||||
# dev
|
||||
|
||||
Features:
|
||||
* Bluetooth module
|
||||
|
||||
# 1.9.0
|
||||
|
||||
Notable Changes:
|
||||
|
@ -232,6 +232,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/printing.c
|
||||
src/common/properties.c
|
||||
src/common/settings.c
|
||||
src/detection/bluetooth/bluetooth.c
|
||||
src/detection/cpu/cpu.c
|
||||
src/detection/cpuUsage/cpuUsage.c
|
||||
src/detection/datetime.c
|
||||
@ -254,6 +255,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/logo/logo.c
|
||||
src/modules/battery.c
|
||||
src/modules/bios.c
|
||||
src/modules/bluetooth.c
|
||||
src/modules/board.c
|
||||
src/modules/brightness.c
|
||||
src/modules/break.c
|
||||
@ -308,6 +310,7 @@ set(LIBFASTFETCH_SRC
|
||||
|
||||
if(LINUX)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/dbus.c
|
||||
src/common/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_linux.c
|
||||
@ -318,6 +321,7 @@ if(LINUX)
|
||||
src/detection/cpu/cpu_linux.c
|
||||
src/detection/cpuUsage/cpuUsage_linux.c
|
||||
src/detection/cursor/cursor_linux.c
|
||||
src/detection/bluetooth/bluetooth_linux.c
|
||||
src/detection/disk/disk_linux.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/wayland.c
|
||||
|
@ -45,7 +45,7 @@ The following libraries are used if present at runtime:
|
||||
* [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel or kitty graphics protocol.
|
||||
* [`libchafa`](https://github.com/hpjansson/chafa): Image output as ascii art.
|
||||
* [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol.
|
||||
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song.
|
||||
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Bluetooth, Player & Media detection.
|
||||
* [`libEGL`](https://www.khronos.org/registry/EGL/),
|
||||
[`libGLX`](https://dri.freedesktop.org/wiki/GLX/),
|
||||
[`libOSMesa`](https://docs.mesa3d.org/osmesa.html): At least one of them is needed by the OpenGL module for gl context creation.
|
||||
@ -88,7 +88,7 @@ All categories not listed here should work without needing a specific implementa
|
||||
|
||||
##### Available Modules
|
||||
```
|
||||
Battery, Bios, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, GPU, Host, Icons, Kernel, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator OS, Shell, Swap, Terminal, Terminal Font, Theme, Time, Title, Uptime, Vulkan, Wifi, WM, WMTheme
|
||||
Battery, Bios, Bluetooth, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, GPU, Host, Icons, Kernel, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator OS, Shell, Swap, Terminal, Terminal Font, Theme, Time, Title, Uptime, Vulkan, Wifi, WM, WMTheme
|
||||
```
|
||||
|
||||
##### Builtin logos
|
||||
|
@ -42,6 +42,7 @@ __fastfetch_complete_help()
|
||||
"vulkan-format"
|
||||
"opengl-format"
|
||||
"opencl-format"
|
||||
"bluetooth-format"
|
||||
)
|
||||
COMPREPLY=($(compgen -W "${__ff_helps[*]}" -- "$CURRENT_WORD"))
|
||||
}
|
||||
@ -349,6 +350,9 @@ __fastfetch_completion()
|
||||
"--users-key"
|
||||
"--users-format"
|
||||
"--users-error"
|
||||
"--bluetooth-key"
|
||||
"--bluetooth-format"
|
||||
"--bluetooth-error"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_PATH=(
|
||||
|
@ -1 +1 @@
|
||||
--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Weather:Break:Colors
|
||||
--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Bluetooth:Weather:Break:Colors
|
||||
|
@ -28,3 +28,4 @@
|
||||
--vulkan-format driver: {}; Api Version: {}; Conformance Version: {}
|
||||
--opengl-format version: {}; renderer: {}; vendor: {}
|
||||
--opencl-format version: {}; device: {}; vendor: {}
|
||||
--bluetooth-format Name: {}; Address: {}; Type: {}; Battery: {}
|
||||
|
201
src/common/dbus.c
Normal file
201
src/common/dbus.c
Normal file
@ -0,0 +1,201 @@
|
||||
#include "dbus.h"
|
||||
|
||||
#include "common/thread.h"
|
||||
|
||||
static bool loadLibSymbols(const FFinstance* instance, FFDBusLibrary* lib)
|
||||
{
|
||||
FF_LIBRARY_LOAD(dbus, &instance->config.libDBus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4);
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_bus_get, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_new_method_call, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init_append, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_append_basic, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_arg_type, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_basic, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_recurse, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_has_next, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_flush, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_pending_call_block, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_pending_call_steal_reply, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_pending_call_unref, false)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const FFDBusLibrary* loadLib(const FFinstance* instance)
|
||||
{
|
||||
static FFDBusLibrary lib;
|
||||
static bool loaded = false;
|
||||
static bool loadSuccess = false;
|
||||
static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER;
|
||||
|
||||
ffThreadMutexLock(&mutex);
|
||||
|
||||
if(!loaded)
|
||||
{
|
||||
loaded = true;
|
||||
loadSuccess = loadLibSymbols(instance, &lib);
|
||||
}
|
||||
|
||||
ffThreadMutexUnlock(&mutex);
|
||||
return loadSuccess ? &lib : NULL;
|
||||
}
|
||||
|
||||
const char* ffDBusLoadData(const FFinstance* instance, DBusBusType busType, FFDBusData* data)
|
||||
{
|
||||
data->lib = loadLib(instance);
|
||||
if(data->lib == NULL)
|
||||
return "Failed to load DBus library";
|
||||
|
||||
data->connection = data->lib->ffdbus_bus_get(busType, NULL);
|
||||
if(data->connection == NULL)
|
||||
return "Failed to connect to DBus";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffDBusGetValue(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_STRING)
|
||||
{
|
||||
const char* value = NULL;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
|
||||
if(!ffStrSet(value))
|
||||
return false;
|
||||
|
||||
ffStrbufAppendS(result, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY)
|
||||
return false;
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
|
||||
if(argType == DBUS_TYPE_VARIANT)
|
||||
return ffDBusGetValue(dbus, &subIter, result);
|
||||
|
||||
//At this point we have an array
|
||||
|
||||
bool foundAValue = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(ffDBusGetValue(dbus, &subIter, result))
|
||||
{
|
||||
foundAValue = true;
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &subIter);
|
||||
}
|
||||
|
||||
if(foundAValue)
|
||||
ffStrbufSubstrBefore(result, result->length - 2);
|
||||
|
||||
return foundAValue;
|
||||
}
|
||||
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_BOOLEAN)
|
||||
{
|
||||
dbus_bool_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
return false;
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetBool(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
bool ffDBusGetByte(FFDBusData* dbus, DBusMessageIter* iter, uint8_t* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_BYTE)
|
||||
{
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
return false;
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetByte(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method)
|
||||
{
|
||||
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
|
||||
if(message == NULL)
|
||||
return NULL;
|
||||
|
||||
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, FF_DBUS_TIMEOUT_MILLISECONDS, NULL);
|
||||
|
||||
dbus->lib->ffdbus_message_unref(message);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property)
|
||||
{
|
||||
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
|
||||
if(message == NULL)
|
||||
return NULL;
|
||||
|
||||
DBusMessageIter requestIterator;
|
||||
dbus->lib->ffdbus_message_iter_init_append(message, &requestIterator);
|
||||
|
||||
if(!dbus->lib->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface))
|
||||
{
|
||||
dbus->lib->ffdbus_message_unref(message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!dbus->lib->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property))
|
||||
{
|
||||
dbus->lib->ffdbus_message_unref(message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, FF_DBUS_TIMEOUT_MILLISECONDS, NULL);
|
||||
|
||||
dbus->lib->ffdbus_message_unref(message);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result)
|
||||
{
|
||||
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
|
||||
if(reply == NULL)
|
||||
return;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
dbus->lib->ffdbus_message_unref(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
ffDBusGetValue(dbus, &rootIterator, result);
|
||||
|
||||
dbus->lib->ffdbus_message_unref(reply);
|
||||
}
|
57
src/common/dbus.h
Normal file
57
src/common/dbus.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef FF_INCLUDED_common_dbus
|
||||
#define FF_INCLUDED_common_dbus
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "common/library.h"
|
||||
|
||||
#define FF_DBUS_TIMEOUT_MILLISECONDS 35
|
||||
|
||||
#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
|
||||
{ \
|
||||
if(!(dbus)->lib->ffdbus_message_iter_has_next(iterator)) \
|
||||
break; \
|
||||
(dbus)->lib->ffdbus_message_iter_next(iterator); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
typedef struct FFDBusLibrary
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(dbus_bus_get)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_new_method_call)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_init)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_init_append)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_append_basic)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_get_arg_type)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_get_basic)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_recurse)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_has_next)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_next)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_unref)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply_and_block)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_flush)
|
||||
FF_LIBRARY_SYMBOL(dbus_pending_call_block)
|
||||
FF_LIBRARY_SYMBOL(dbus_pending_call_steal_reply)
|
||||
FF_LIBRARY_SYMBOL(dbus_pending_call_unref)
|
||||
} FFDBusLibrary;
|
||||
|
||||
typedef struct FFDBusData
|
||||
{
|
||||
const FFDBusLibrary* lib;
|
||||
DBusConnection* connection;
|
||||
} FFDBusData;
|
||||
|
||||
const char* ffDBusLoadData(const FFinstance* instance, DBusBusType busType, FFDBusData* data); //Returns an error message or NULL on success
|
||||
bool ffDBusGetValue(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
|
||||
bool ffDBusGetByte(FFDBusData* dbus, DBusMessageIter* iter, uint8_t* result);
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method);
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
|
||||
void ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
|
||||
|
||||
#endif // FF_HAVE_DBUS
|
||||
#endif // FF_INCLUDED_common_dbus
|
@ -115,6 +115,7 @@ static void defaultConfig(FFinstance* instance)
|
||||
initModuleArg(&instance->config.openGL);
|
||||
initModuleArg(&instance->config.openCL);
|
||||
initModuleArg(&instance->config.users);
|
||||
initModuleArg(&instance->config.bluetooth);
|
||||
|
||||
ffStrbufInitA(&instance->config.libPCI, 0);
|
||||
ffStrbufInitA(&instance->config.libVulkan, 0);
|
||||
@ -377,6 +378,7 @@ static void destroyConfig(FFinstance* instance)
|
||||
destroyModuleArg(&instance->config.openGL);
|
||||
destroyModuleArg(&instance->config.openCL);
|
||||
destroyModuleArg(&instance->config.users);
|
||||
destroyModuleArg(&instance->config.bluetooth);
|
||||
|
||||
ffStrbufDestroy(&instance->config.libPCI);
|
||||
ffStrbufDestroy(&instance->config.libVulkan);
|
||||
|
@ -295,6 +295,7 @@
|
||||
#--opengl-key OpenGL
|
||||
#--opencl-key OpenCL
|
||||
#--users-key Users
|
||||
#--bluetooth-key Bluetooth
|
||||
|
||||
# Format options:
|
||||
# Sets the format string for module values.
|
||||
@ -339,6 +340,7 @@
|
||||
#--opengl-format
|
||||
#--opencl-format
|
||||
#--users-format
|
||||
#--bluetooth-format
|
||||
|
||||
# Error options:
|
||||
# Sets the format string to use if an error occured
|
||||
@ -383,6 +385,7 @@
|
||||
#--opengl-error
|
||||
#--opencl-error
|
||||
#--users-error
|
||||
#--bluetooth-error
|
||||
|
||||
# Library options:
|
||||
# Sets an user specific path to a library to load.
|
||||
|
@ -1,5 +1,6 @@
|
||||
Battery
|
||||
Bios
|
||||
Bluetooth
|
||||
Board
|
||||
Break
|
||||
Chassis
|
||||
|
21
src/detection/bluetooth/bluetooth.c
Normal file
21
src/detection/bluetooth/bluetooth.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include "bluetooth.h"
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
void ffDetectBluetoothImpl(const FFinstance* instance, FFBluetoothResult* bluetooth);
|
||||
|
||||
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;
|
||||
|
||||
ffDetectBluetoothImpl(instance, &result);
|
||||
|
||||
if(result.error.length == 0 && result.name.length == 0)
|
||||
ffStrbufAppendS(&result.error, "No bluetooth device found");
|
||||
)
|
||||
}
|
19
src/detection/bluetooth/bluetooth.h
Normal file
19
src/detection/bluetooth/bluetooth.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef FF_INCLUDED_detection_bluetooth_bluetooth
|
||||
#define FF_INCLUDED_detection_bluetooth_bluetooth
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef struct FFBluetoothResult
|
||||
{
|
||||
FFstrbuf error;
|
||||
FFstrbuf name;
|
||||
FFstrbuf address;
|
||||
FFstrbuf type;
|
||||
uint8_t battery; // 0-100%
|
||||
} FFBluetoothResult;
|
||||
|
||||
const FFBluetoothResult* ffDetectBluetooth(const FFinstance* instance);
|
||||
|
||||
#endif
|
200
src/detection/bluetooth/bluetooth_linux.c
Normal file
200
src/detection/bluetooth/bluetooth_linux.c
Normal file
@ -0,0 +1,200 @@
|
||||
#include "bluetooth.h"
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
|
||||
/* Example dbus reply, striped to only the relevant parts:
|
||||
array [ //root
|
||||
dict entry( //object
|
||||
object path "/org/bluez/hci0/dev_03_21_8B_91_16_4D"
|
||||
array [
|
||||
dict entry( //property
|
||||
string "org.bluez.Device1"
|
||||
array [
|
||||
dict entry(
|
||||
string "Address"
|
||||
variant string "03:21:8B:91:16:4D"
|
||||
)
|
||||
dict entry(
|
||||
string "Name"
|
||||
variant string "JBL TUNE160BT"
|
||||
)
|
||||
dict entry(
|
||||
string "Connected"
|
||||
variant boolean true
|
||||
)
|
||||
]
|
||||
)
|
||||
dict entry( //property
|
||||
string "org.bluez.Battery1"
|
||||
array [
|
||||
dict entry(
|
||||
string "Percentage"
|
||||
variant byte 100
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
*/
|
||||
|
||||
static void detectBluetoothProperty(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter, bool* connected)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
|
||||
return;
|
||||
|
||||
DBusMessageIter dictIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
|
||||
return;
|
||||
|
||||
const char* propertyType;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &propertyType);
|
||||
|
||||
if(strstr(propertyType, "Device") == NULL && strstr(propertyType, "Battery") == NULL)
|
||||
return; //We don't care about other properties
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
|
||||
return;
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&arrayIter) != DBUS_TYPE_DICT_ENTRY)
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter)
|
||||
|
||||
DBusMessageIter deviceIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(&arrayIter, &deviceIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&deviceIter) != DBUS_TYPE_STRING)
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter)
|
||||
|
||||
const char* deviceProperty;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&deviceIter, &deviceProperty);
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&deviceIter);
|
||||
|
||||
if(strcmp(deviceProperty, "Address") == 0)
|
||||
ffDBusGetValue(dbus, &deviceIter, &bluetooth->address);
|
||||
else if(strcmp(deviceProperty, "Name") == 0)
|
||||
ffDBusGetValue(dbus, &deviceIter, &bluetooth->name);
|
||||
else if(strcmp(deviceProperty, "Icon") == 0)
|
||||
ffDBusGetValue(dbus, &deviceIter, &bluetooth->type);
|
||||
else if(strcmp(deviceProperty, "Percentage") == 0)
|
||||
ffDBusGetByte(dbus, &deviceIter, &bluetooth->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
|
||||
}
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
|
||||
}
|
||||
}
|
||||
|
||||
static bool detectBluetoothObject(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
|
||||
return false;
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
|
||||
|
||||
bool connected = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
detectBluetoothProperty(bluetooth, dbus, &arrayIter, &connected);
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
|
||||
}
|
||||
|
||||
if(!connected || bluetooth->name.length == 0)
|
||||
{
|
||||
ffStrbufClear(&bluetooth->address);
|
||||
ffStrbufClear(&bluetooth->name);
|
||||
ffStrbufClear(&bluetooth->type);
|
||||
bluetooth->battery = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void detectBluetoothRoot(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
|
||||
return;
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &arrayIter);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(detectBluetoothObject(bluetooth, dbus, &arrayIter))
|
||||
return;
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* detectBluetooth(const FFinstance* instance, FFBluetoothResult* bluetooth)
|
||||
{
|
||||
FFDBusData dbus;
|
||||
const char* error = ffDBusLoadData(instance, DBUS_BUS_SYSTEM, &dbus);
|
||||
if(error)
|
||||
return error;
|
||||
|
||||
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
|
||||
if(!managedObjects)
|
||||
return "Failed to call GetManagedObjects";
|
||||
|
||||
DBusMessageIter rootIter;
|
||||
if(!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(managedObjects);
|
||||
return "Failed to get root iterator of GetManagedObjects";
|
||||
}
|
||||
|
||||
detectBluetoothRoot(bluetooth, &dbus, &rootIter);
|
||||
|
||||
dbus.lib->ffdbus_message_unref(managedObjects);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ffDetectBluetoothImpl(const FFinstance* instance, FFBluetoothResult* bluetooth)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
ffStrbufAppendS(&bluetooth->error, detectBluetooth(instance, bluetooth));
|
||||
#else
|
||||
ffStrbufAppendS(&bluetooth->error, "Fastfetch was compiled without DBus support");
|
||||
#endif
|
||||
}
|
@ -8,208 +8,75 @@
|
||||
#define FF_DBUS_TIMEOUT_MILLISECONDS 35
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
#include "common/library.h"
|
||||
#include "common/parsing.h"
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#define FF_DBUS_ITER_CONTINUE(iterator) \
|
||||
{ \
|
||||
if(!data->ffdbus_message_iter_has_next(&iterator)) \
|
||||
break; \
|
||||
data->ffdbus_message_iter_next(&iterator); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
typedef struct DBusData
|
||||
static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result)
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(dbus_message_new_method_call)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_init)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_init_append)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_append_basic)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_get_arg_type)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_get_basic)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_recurse)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_has_next)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_next)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_unref)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_flush)
|
||||
FF_LIBRARY_SYMBOL(dbus_pending_call_block)
|
||||
FF_LIBRARY_SYMBOL(dbus_pending_call_steal_reply)
|
||||
FF_LIBRARY_SYMBOL(dbus_pending_call_unref)
|
||||
|
||||
DBusConnection *connection;
|
||||
} DBusData;
|
||||
|
||||
static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data)
|
||||
{
|
||||
int argType = data->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_STRING)
|
||||
{
|
||||
const char* value = NULL;
|
||||
data->ffdbus_message_iter_get_basic(iter, &value);
|
||||
|
||||
if(!ffStrSet(value))
|
||||
return false;
|
||||
|
||||
ffStrbufAppendS(result, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY)
|
||||
return false;
|
||||
|
||||
DBusMessageIter subIter;
|
||||
data->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
|
||||
if(argType == DBUS_TYPE_VARIANT)
|
||||
return getValue(&subIter, result, data);
|
||||
|
||||
//At this point we have an array
|
||||
|
||||
bool foundAValue = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(getValue(&subIter, result, data))
|
||||
{
|
||||
foundAValue = true;
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(subIter);
|
||||
}
|
||||
|
||||
if(foundAValue)
|
||||
ffStrbufSubstrBefore(result, result->length - 2);
|
||||
|
||||
return foundAValue;
|
||||
}
|
||||
|
||||
static DBusMessage* getReply(DBusMessage* request, DBusData* data)
|
||||
{
|
||||
DBusPendingCall* pendingCall = NULL;
|
||||
dbus_bool_t succesfull = data->ffdbus_connection_send_with_reply(data->connection, request, &pendingCall, FF_DBUS_TIMEOUT_MILLISECONDS);
|
||||
data->ffdbus_message_unref(request);
|
||||
if(!succesfull || pendingCall == NULL)
|
||||
return NULL;
|
||||
|
||||
data->ffdbus_connection_flush(data->connection);
|
||||
data->ffdbus_pending_call_block(pendingCall);
|
||||
|
||||
DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pendingCall);
|
||||
data->ffdbus_pending_call_unref(pendingCall);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage* getProperty(const char* busName, const char* objectPath, const char* interface, const char* property, DBusData* data)
|
||||
{
|
||||
DBusMessage* message = data->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
|
||||
if(message == NULL)
|
||||
return NULL;
|
||||
|
||||
DBusMessageIter requestIterator;
|
||||
data->ffdbus_message_iter_init_append(message, &requestIterator);
|
||||
|
||||
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface))
|
||||
{
|
||||
data->ffdbus_message_unref(message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property))
|
||||
{
|
||||
data->ffdbus_message_unref(message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return getReply(message, data);
|
||||
}
|
||||
|
||||
static void getPropertyString(const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result, DBusData* data)
|
||||
{
|
||||
DBusMessage* reply = getProperty(busName, objectPath, interface, property, data);
|
||||
if(reply == NULL)
|
||||
return;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!data->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
getValue(&rootIterator, result, data);
|
||||
|
||||
data->ffdbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static bool getBusProperties(const char* busName, FFMediaResult* result, DBusData* data)
|
||||
{
|
||||
DBusMessage* reply = getProperty(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata", data);
|
||||
DBusMessage* reply = ffDBusGetProperty(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata");
|
||||
if(reply == NULL)
|
||||
return false;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!data->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
if(!data->lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
data->lib->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT)
|
||||
if(data->lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT)
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
data->lib->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter variantIterator;
|
||||
data->ffdbus_message_iter_recurse(&rootIterator, &variantIterator);
|
||||
if(data->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY)
|
||||
data->lib->ffdbus_message_iter_recurse(&rootIterator, &variantIterator);
|
||||
if(data->lib->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY)
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
data->lib->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter arrayIterator;
|
||||
data->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator);
|
||||
data->lib->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
|
||||
DBusMessageIter dictIterator;
|
||||
data->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
|
||||
data->lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
|
||||
|
||||
if(data->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_STRING)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
if(data->lib->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_STRING)
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
|
||||
if(!data->ffdbus_message_iter_has_next(&dictIterator))
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
if(!data->lib->ffdbus_message_iter_has_next(&dictIterator))
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
|
||||
const char* key;
|
||||
data->ffdbus_message_iter_get_basic(&dictIterator, &key);
|
||||
data->lib->ffdbus_message_iter_get_basic(&dictIterator, &key);
|
||||
|
||||
data->ffdbus_message_iter_next(&dictIterator);
|
||||
data->lib->ffdbus_message_iter_next(&dictIterator);
|
||||
|
||||
if(strcmp(key, "xesam:title") == 0)
|
||||
getValue(&dictIterator, &result->song, data);
|
||||
ffDBusGetValue(data, &dictIterator, &result->song);
|
||||
else if(strcmp(key, "xesam:album") == 0)
|
||||
getValue(&dictIterator, &result->album, data);
|
||||
ffDBusGetValue(data, &dictIterator, &result->album);
|
||||
else if(strcmp(key, "xesam:artist") == 0)
|
||||
getValue(&dictIterator, &result->artist, data);
|
||||
ffDBusGetValue(data, &dictIterator, &result->artist);
|
||||
else if(strcmp(key, "xesam:url") == 0)
|
||||
getValue(&dictIterator, &result->url, data);
|
||||
ffDBusGetValue(data, &dictIterator, &result->url);
|
||||
|
||||
if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0 && result->url.length > 0)
|
||||
break;
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
}
|
||||
|
||||
data->ffdbus_message_unref(reply);
|
||||
data->lib->ffdbus_message_unref(reply);
|
||||
|
||||
if(result->song.length == 0)
|
||||
{
|
||||
@ -223,20 +90,20 @@ static bool getBusProperties(const char* busName, FFMediaResult* result, DBusDat
|
||||
ffStrbufAppendS(&result->busNameShort, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
|
||||
//We found a song, get the player name
|
||||
getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player, data);
|
||||
ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player);
|
||||
if(result->player.length == 0)
|
||||
getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player, data);
|
||||
ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player);
|
||||
if(result->player.length == 0)
|
||||
ffStrbufAppend(&result->player, &result->busNameShort);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void getCustomBus(const FFinstance* instance, FFMediaResult* result, DBusData* data)
|
||||
static void getCustomBus(FFDBusData* data, const FFinstance* instance, FFMediaResult* result)
|
||||
{
|
||||
if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX))
|
||||
{
|
||||
getBusProperties(instance->config.playerName.chars, result, data);
|
||||
getBusProperties(data, instance->config.playerName.chars, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -244,88 +111,61 @@ static void getCustomBus(const FFinstance* instance, FFMediaResult* result, DBus
|
||||
ffStrbufInit(&busName);
|
||||
ffStrbufAppendS(&busName, FF_DBUS_MPRIS_PREFIX);
|
||||
ffStrbufAppend(&busName, &instance->config.playerName);
|
||||
getBusProperties(busName.chars, result, data);
|
||||
getBusProperties(data, busName.chars, result);
|
||||
ffStrbufDestroy(&busName);
|
||||
}
|
||||
|
||||
static void getBestBus(FFMediaResult* result, DBusData* data)
|
||||
static void getBestBus(FFDBusData* data, FFMediaResult* result)
|
||||
{
|
||||
if(
|
||||
getBusProperties(FF_DBUS_MPRIS_PREFIX"spotify", result, data) ||
|
||||
getBusProperties(FF_DBUS_MPRIS_PREFIX"vlc", result, data) ||
|
||||
getBusProperties(FF_DBUS_MPRIS_PREFIX"plasma-browser-integration", result, data)
|
||||
getBusProperties(data, FF_DBUS_MPRIS_PREFIX"spotify", result) ||
|
||||
getBusProperties(data, FF_DBUS_MPRIS_PREFIX"vlc", result) ||
|
||||
getBusProperties(data, FF_DBUS_MPRIS_PREFIX"plasma-browser-integration", result)
|
||||
) return;
|
||||
|
||||
DBusMessage* message = data->ffdbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
|
||||
if(message == NULL)
|
||||
return;
|
||||
|
||||
DBusMessage* reply = getReply(message, data);
|
||||
DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
|
||||
if(reply == NULL)
|
||||
return;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!data->ffdbus_message_iter_init(reply, &rootIterator) || data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY)
|
||||
if(!data->lib->ffdbus_message_iter_init(reply, &rootIterator) || data->lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY)
|
||||
return;
|
||||
|
||||
DBusMessageIter arrayIterator;
|
||||
data->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
|
||||
data->lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING)
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
|
||||
const char* busName;
|
||||
data->ffdbus_message_iter_get_basic(&arrayIterator, &busName);
|
||||
data->lib->ffdbus_message_iter_get_basic(&arrayIterator, &busName);
|
||||
|
||||
if(strncmp(busName, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
|
||||
if(getBusProperties(busName, result, data))
|
||||
if(getBusProperties(data, busName, result))
|
||||
break;
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
}
|
||||
|
||||
data->ffdbus_message_unref(reply);
|
||||
data->lib->ffdbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static const char* getMedia(const FFinstance* instance, FFMediaResult* result)
|
||||
{
|
||||
DBusData data;
|
||||
|
||||
FF_LIBRARY_LOAD(dbus, &instance->config.libDBus, "dlopen dbus failed", "libdbus-1" FF_LIBRARY_EXTENSION, 4);
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dbus, dbus_bus_get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_new_method_call)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_init)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_init_append)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_append_basic)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_get_arg_type)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_get_basic)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_recurse)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_has_next)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_next)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_unref)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_connection_send_with_reply)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_connection_flush)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_pending_call_block)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_pending_call_steal_reply)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_pending_call_unref)
|
||||
|
||||
data.connection = ffdbus_bus_get(DBUS_BUS_SESSION, NULL);
|
||||
if(data.connection == NULL)
|
||||
{
|
||||
dlclose(dbus);
|
||||
return "Failed to connect to session dbus";
|
||||
}
|
||||
FFDBusData data;
|
||||
const char* error = ffDBusLoadData(instance, DBUS_BUS_SESSION, &data);
|
||||
if(error != NULL)
|
||||
return error;
|
||||
|
||||
if(instance->config.playerName.length > 0)
|
||||
getCustomBus(instance, result, &data);
|
||||
getCustomBus(&data, instance, result);
|
||||
else
|
||||
getBestBus(result, &data);
|
||||
getBestBus(&data, result);
|
||||
|
||||
dlclose(dbus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -448,6 +448,15 @@ static inline void printCommandHelp(const char* command)
|
||||
"vendor"
|
||||
);
|
||||
}
|
||||
else if(strcasecmp(command, "bluetooth-format") == 0)
|
||||
{
|
||||
constructAndPrintCommandHelpFormat("bluetooth", "{1} (4%)", 4,
|
||||
"Name",
|
||||
"Address",
|
||||
"Type",
|
||||
"Battery percentage"
|
||||
);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "No specific help for command %s provided\n", command);
|
||||
}
|
||||
@ -1208,6 +1217,7 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
else if(optionParseModuleArgs(key, value, "opengl", &instance->config.openGL)) {}
|
||||
else if(optionParseModuleArgs(key, value, "opencl", &instance->config.openCL)) {}
|
||||
else if(optionParseModuleArgs(key, value, "users", &instance->config.users)) {}
|
||||
else if(optionParseModuleArgs(key, value, "bluetooth", &instance->config.bluetooth)) {}
|
||||
|
||||
///////////////////
|
||||
//Library options//
|
||||
@ -1503,6 +1513,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char
|
||||
ffPrintUsers(instance);
|
||||
else if(strcasecmp(line, "command") == 0)
|
||||
ffPrintCommand(instance);
|
||||
else if(strcasecmp(line, "bluetooth") == 0)
|
||||
ffPrintBluetooth(instance);
|
||||
else
|
||||
ffPrintErrorString(instance, line, 0, NULL, NULL, "<no implementation provided>");
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ typedef struct FFconfig
|
||||
FFModuleArgs openGL;
|
||||
FFModuleArgs openCL;
|
||||
FFModuleArgs users;
|
||||
FFModuleArgs bluetooth;
|
||||
|
||||
FFstrbuf libPCI;
|
||||
FFstrbuf libVulkan;
|
||||
@ -310,5 +311,6 @@ void ffPrintOpenGL(FFinstance* instance);
|
||||
void ffPrintOpenCL(FFinstance* instance);
|
||||
void ffPrintUsers(FFinstance* instance);
|
||||
void ffPrintCommand(FFinstance* instance);
|
||||
void ffPrintBluetooth(FFinstance* instance);
|
||||
|
||||
#endif
|
||||
|
36
src/modules/bluetooth.c
Normal file
36
src/modules/bluetooth.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include "common/printing.h"
|
||||
#include "detection/bluetooth/bluetooth.h"
|
||||
|
||||
#define FF_BLUETOOTH_MODULE_NAME "Bluetooth"
|
||||
#define FF_BLUETOOTH_NUM_FORMAT_ARGS 4
|
||||
|
||||
void ffPrintBluetooth(FFinstance* instance)
|
||||
{
|
||||
const FFBluetoothResult* bluetooth = ffDetectBluetooth(instance);
|
||||
|
||||
if(bluetooth->error.length > 0)
|
||||
{
|
||||
ffPrintError(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth, "%s", bluetooth->error.chars);
|
||||
return;
|
||||
}
|
||||
|
||||
if(instance->config.bluetooth.outputFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth.key);
|
||||
ffStrbufWriteTo(&bluetooth->name, stdout);
|
||||
|
||||
if(bluetooth->battery > 0)
|
||||
printf(" (%d%%)", bluetooth->battery);
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
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}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user