mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-21 18:52:49 +00:00
Added a bluetooth widget
I think it looks really slick. Probably still many bugs
This commit is contained in:
parent
7b91486441
commit
ed32d70916
11 changed files with 245 additions and 25 deletions
|
@ -41,6 +41,10 @@ gBar bar 0
|
|||
```
|
||||
gBar audio [monitor]
|
||||
```
|
||||
*Open bluetooth widget*
|
||||
```
|
||||
gBar bluetooth [monitor]
|
||||
```
|
||||
|
||||
## Gallery
|
||||
![The bar with default css](/assets/bar.png)
|
||||
|
@ -51,6 +55,10 @@ gBar audio [monitor]
|
|||
|
||||
*Audio widget with default css*
|
||||
|
||||
![The bluetooth widget with default css](/assets/bt.png)
|
||||
|
||||
*Bluetooth widget with default css*
|
||||
|
||||
## Features / Widgets
|
||||
Bar:
|
||||
- Workspaces (Hyprland only)
|
||||
|
|
|
@ -25,7 +25,14 @@ pulse = dependency('libpulse')
|
|||
|
||||
executable(
|
||||
'gBar',
|
||||
['src/gBar.cpp', 'src/Window.cpp', 'src/Widget.cpp', 'src/System.cpp', 'src/Bar.cpp', 'src/AudioFlyin.cpp'],
|
||||
['src/gBar.cpp',
|
||||
'src/Window.cpp',
|
||||
'src/Widget.cpp',
|
||||
'src/System.cpp',
|
||||
'src/Bar.cpp',
|
||||
'src/AudioFlyin.cpp',
|
||||
'src/BluetoothDevices.cpp',
|
||||
],
|
||||
dependencies: [gtk, gtk_layer_shell, pulse],
|
||||
install: true
|
||||
)
|
||||
|
|
12
src/Bar.cpp
12
src/Bar.cpp
|
@ -77,7 +77,7 @@ namespace Bar
|
|||
}
|
||||
|
||||
#ifdef HAS_BLUEZ
|
||||
static Text* btIconText;
|
||||
static Button* btIconText;
|
||||
static Text* btDevText;
|
||||
static TimerResult UpdateBluetooth(Box&)
|
||||
{
|
||||
|
@ -102,6 +102,8 @@ namespace Bar
|
|||
std::string tooltip;
|
||||
for (auto& dev : info.devices)
|
||||
{
|
||||
if (!dev.connected)
|
||||
continue;
|
||||
std::string ico = " ";
|
||||
if (dev.type == "input-keyboard")
|
||||
{
|
||||
|
@ -126,6 +128,11 @@ namespace Bar
|
|||
}
|
||||
return TimerResult::Ok;
|
||||
}
|
||||
|
||||
void OnBTClick(Button&)
|
||||
{
|
||||
System::OpenBTWidget();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OnChangeVolume(Slider&, double value)
|
||||
|
@ -265,7 +272,8 @@ namespace Bar
|
|||
DynCtx::btDevText = devText.get();
|
||||
devText->SetClass("bt-num");
|
||||
|
||||
auto iconText = Widget::Create<Text>();
|
||||
auto iconText = Widget::Create<Button>();
|
||||
iconText->OnClick(DynCtx::OnBTClick);
|
||||
DynCtx::btIconText = iconText.get();
|
||||
|
||||
box->AddChild(std::move(devText));
|
||||
|
|
23
src/Common.h
23
src/Common.h
|
@ -60,3 +60,26 @@ namespace Utils
|
|||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
struct Process
|
||||
{
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
inline Process OpenProcess(Args... args)
|
||||
{
|
||||
pid_t child = fork();
|
||||
ASSERT(child != -1, "fork error");
|
||||
|
||||
if (child == 0)
|
||||
{
|
||||
// Child
|
||||
execl(args...);
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return {child};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
|
@ -16,6 +17,7 @@
|
|||
|
||||
#include <dlfcn.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace System
|
||||
{
|
||||
|
@ -207,16 +209,24 @@ namespace System
|
|||
}
|
||||
else if (strstr(type, "org.bluez.Device1"))
|
||||
{
|
||||
std::string deviceMac;
|
||||
std::string deviceName;
|
||||
std::string deviceType;
|
||||
bool connected = false;
|
||||
bool paired = false;
|
||||
|
||||
// This is a device -> One "client"
|
||||
char* str = nullptr;
|
||||
GVariant* var = nullptr;
|
||||
while (g_variant_iter_next(propIter, "{sv}", &str, &var))
|
||||
{
|
||||
if (strstr(str, "Name"))
|
||||
if (strcmp(str, "Address") == 0)
|
||||
{
|
||||
const char* mac = g_variant_get_string(var, nullptr);
|
||||
// Copy it for us
|
||||
deviceMac = mac;
|
||||
}
|
||||
else if (strstr(str, "Name"))
|
||||
{
|
||||
const char* name = g_variant_get_string(var, nullptr);
|
||||
// Copy it for us
|
||||
|
@ -232,13 +242,14 @@ namespace System
|
|||
{
|
||||
connected = g_variant_get_boolean(var);
|
||||
}
|
||||
else if (strstr(str, "Paired"))
|
||||
{
|
||||
paired = g_variant_get_boolean(var);
|
||||
}
|
||||
g_free(str);
|
||||
g_variant_unref(var);
|
||||
}
|
||||
if (connected)
|
||||
{
|
||||
out.devices.push_back(BluetoothDevice{std::move(deviceName), std::move(deviceType)});
|
||||
}
|
||||
out.devices.push_back(BluetoothDevice{connected, paired, std::move(deviceMac), std::move(deviceName), std::move(deviceType)});
|
||||
}
|
||||
g_variant_iter_free(propIter);
|
||||
g_free(type);
|
||||
|
@ -251,6 +262,76 @@ namespace System
|
|||
|
||||
return out;
|
||||
}
|
||||
|
||||
static Process btctlProcess{-1};
|
||||
void StartScan()
|
||||
{
|
||||
StopScan();
|
||||
btctlProcess = OpenProcess("/bin/sh", "/bin/sh", "-c", "bluetoothctl scan on", NULL);
|
||||
}
|
||||
void StopScan()
|
||||
{
|
||||
if (btctlProcess.pid != -1)
|
||||
{
|
||||
// Ctrl-C stops bluetoothctl
|
||||
kill(btctlProcess.pid, SIGINT);
|
||||
btctlProcess = {-1};
|
||||
}
|
||||
}
|
||||
|
||||
void Connect(BluetoothDevice& device, std::function<void(bool, BluetoothDevice&)> onFinish)
|
||||
{
|
||||
auto thread = [&, mac = device.mac, onFinish]()
|
||||
{
|
||||
// 1. Pair
|
||||
if (!device.paired)
|
||||
{
|
||||
int success = system(("bluetoothctl pair " + mac).c_str());
|
||||
if (success != 0)
|
||||
{
|
||||
onFinish(false, device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 2. Connect
|
||||
if (!device.connected)
|
||||
{
|
||||
int success = system(("bluetoothctl connect " + mac).c_str());
|
||||
if (success != 0)
|
||||
{
|
||||
onFinish(false, device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
onFinish(true, device);
|
||||
};
|
||||
std::thread worker(thread);
|
||||
worker.detach();
|
||||
}
|
||||
void Disconnect(BluetoothDevice& device, std::function<void(bool, BluetoothDevice&)> onFinish)
|
||||
{
|
||||
auto thread = [&, mac = device.mac, onFinish]()
|
||||
{
|
||||
// 1. Disconnect
|
||||
if (device.connected)
|
||||
{
|
||||
int success = system(("bluetoothctl disconnect " + mac).c_str());
|
||||
if (success != 0)
|
||||
{
|
||||
onFinish(false, device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
onFinish(true, device);
|
||||
};
|
||||
std::thread worker(thread);
|
||||
worker.detach();
|
||||
}
|
||||
|
||||
void OpenBTWidget()
|
||||
{
|
||||
OpenProcess("/bin/sh", "/bin/sh", "-c", "gBar bluetooth");
|
||||
}
|
||||
#endif
|
||||
|
||||
AudioInfo GetAudioInfo()
|
||||
|
@ -322,7 +403,6 @@ namespace System
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Init()
|
||||
{
|
||||
#ifdef HAS_NVIDIA
|
||||
|
@ -336,5 +416,8 @@ namespace System
|
|||
NvidiaGPU::Shutdown();
|
||||
#endif
|
||||
PulseAudio::Shutdown();
|
||||
#ifdef HAS_BLUEZ
|
||||
StopScan();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
12
src/System.h
12
src/System.h
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -42,6 +43,9 @@ namespace System
|
|||
#ifdef HAS_BLUEZ
|
||||
struct BluetoothDevice
|
||||
{
|
||||
bool connected;
|
||||
bool paired;
|
||||
std::string mac;
|
||||
std::string name;
|
||||
// Known types: input-[keyboard,mouse]; audio-headset
|
||||
std::string type;
|
||||
|
@ -53,6 +57,14 @@ namespace System
|
|||
std::vector<BluetoothDevice> devices;
|
||||
};
|
||||
BluetoothInfo GetBluetoothInfo();
|
||||
void StartScan();
|
||||
void StopScan();
|
||||
|
||||
// MT functions, callback, is from different thread
|
||||
void Connect(BluetoothDevice& device, std::function<void(bool, BluetoothDevice&)> onFinish);
|
||||
void Disconnect(BluetoothDevice& device, std::function<void(bool, BluetoothDevice&)> onFinish);
|
||||
|
||||
void OpenBTWidget();
|
||||
#endif
|
||||
|
||||
struct AudioInfo
|
||||
|
|
|
@ -45,6 +45,21 @@ Widget::~Widget()
|
|||
gtk_widget_destroy(m_Widget);
|
||||
}
|
||||
|
||||
void Widget::CreateAndAddWidget(Widget* widget, GtkWidget* parentWidget)
|
||||
{
|
||||
// Create this widget
|
||||
widget->Create();
|
||||
// Add
|
||||
gtk_container_add((GtkContainer*)parentWidget, widget->Get());
|
||||
|
||||
gtk_widget_show(widget->m_Widget);
|
||||
|
||||
for (auto& child : widget->GetChilds())
|
||||
{
|
||||
CreateAndAddWidget(child.get(), widget->Get());
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::SetClass(const std::string& cssClass)
|
||||
{
|
||||
if (m_Widget)
|
||||
|
@ -55,6 +70,22 @@ void Widget::SetClass(const std::string& cssClass)
|
|||
}
|
||||
m_CssClass = cssClass;
|
||||
}
|
||||
void Widget::AddClass(const std::string& cssClass)
|
||||
{
|
||||
if (m_Widget)
|
||||
{
|
||||
auto style = gtk_widget_get_style_context(m_Widget);
|
||||
gtk_style_context_add_class(style, cssClass.c_str());
|
||||
}
|
||||
}
|
||||
void Widget::RemoveClass(const std::string& cssClass)
|
||||
{
|
||||
if (m_Widget)
|
||||
{
|
||||
auto style = gtk_widget_get_style_context(m_Widget);
|
||||
gtk_style_context_remove_class(style, cssClass.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::SetVerticalTransform(const Transform& transform)
|
||||
{
|
||||
|
@ -77,9 +108,24 @@ void Widget::SetTooltip(const std::string& tooltip)
|
|||
|
||||
void Widget::AddChild(std::unique_ptr<Widget>&& widget)
|
||||
{
|
||||
if (m_Widget)
|
||||
{
|
||||
CreateAndAddWidget(widget.get(), m_Widget);
|
||||
}
|
||||
m_Childs.push_back(std::move(widget));
|
||||
}
|
||||
|
||||
void Widget::RemoveChild(size_t idx)
|
||||
{
|
||||
ASSERT(idx < m_Childs.size(), "RemoveChild: Invalid index");
|
||||
if (m_Widget)
|
||||
{
|
||||
auto& child = *m_Childs[idx];
|
||||
gtk_container_remove((GtkContainer*)child.m_Widget, m_Widget);
|
||||
}
|
||||
m_Childs.erase(m_Childs.begin() + idx);
|
||||
}
|
||||
|
||||
void Widget::SetVisible(bool visible)
|
||||
{
|
||||
gtk_widget_set_visible(m_Widget, visible);
|
||||
|
@ -281,7 +327,8 @@ void Button::Create()
|
|||
auto clickFn = [](UNUSED GtkButton* gtkButton, void* data)
|
||||
{
|
||||
Button* button = (Button*)data;
|
||||
button->m_OnClick(*button);
|
||||
if (button->m_OnClick)
|
||||
button->m_OnClick(*button);
|
||||
};
|
||||
g_signal_connect(m_Widget, "clicked", G_CALLBACK(+clickFn), this);
|
||||
ApplyPropertiesToWidget();
|
||||
|
|
10
src/Widget.h
10
src/Widget.h
|
@ -41,7 +41,7 @@ enum class TransitionType
|
|||
SlideDown
|
||||
};
|
||||
|
||||
struct Transition
|
||||
struct Transition
|
||||
{
|
||||
TransitionType type;
|
||||
uint32_t durationMS;
|
||||
|
@ -81,7 +81,11 @@ public:
|
|||
return std::make_unique<TWidget>();
|
||||
}
|
||||
|
||||
static void CreateAndAddWidget(Widget* widget, GtkWidget* parentWidget);
|
||||
|
||||
void SetClass(const std::string& cssClass);
|
||||
void AddClass(const std::string& cssClass);
|
||||
void RemoveClass(const std::string& cssClass);
|
||||
void SetVerticalTransform(const Transform& transform);
|
||||
void SetHorizontalTransform(const Transform& transform);
|
||||
void SetTooltip(const std::string& tooltip);
|
||||
|
@ -89,6 +93,10 @@ public:
|
|||
virtual void Create() = 0;
|
||||
|
||||
void AddChild(std::unique_ptr<Widget>&& widget);
|
||||
void RemoveChild(size_t idx);
|
||||
|
||||
std::vector<std::unique_ptr<Widget>>& GetWidgets() {return m_Childs;}
|
||||
|
||||
template<typename TWidget>
|
||||
void AddTimer(TimerCallback<TWidget>&& callback, uint32_t timeoutMS)
|
||||
{
|
||||
|
|
|
@ -72,9 +72,10 @@ void Window::Run(int argc, char** argv)
|
|||
{
|
||||
gtk_layer_set_anchor(m_Window, GTK_LAYER_SHELL_EDGE_BOTTOM, true);
|
||||
}
|
||||
UpdateMargin();
|
||||
|
||||
// Create widgets
|
||||
CreateAndAddWidget(m_MainWidget.get(), (GtkWidget*)m_Window);
|
||||
Widget::CreateAndAddWidget(m_MainWidget.get(), (GtkWidget*)m_Window);
|
||||
|
||||
gtk_widget_show_all((GtkWidget*)m_Window);
|
||||
|
||||
|
@ -87,16 +88,26 @@ void Window::Close()
|
|||
gtk_main_quit();
|
||||
}
|
||||
|
||||
void Window::CreateAndAddWidget(Widget* widget, GtkWidget* parentWidget)
|
||||
void Window::UpdateMargin()
|
||||
{
|
||||
// Create this widget
|
||||
widget->Create();
|
||||
// Add
|
||||
gtk_container_add((GtkContainer*)parentWidget, widget->Get());
|
||||
|
||||
for (auto& child : widget->GetChilds())
|
||||
for (auto [anchor, margin] : m_Margin)
|
||||
{
|
||||
CreateAndAddWidget(child.get(), widget->Get());
|
||||
if (FLAG_CHECK(anchor, Anchor::Left))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_LEFT, margin);
|
||||
}
|
||||
if (FLAG_CHECK(anchor, Anchor::Right))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_RIGHT, margin);
|
||||
}
|
||||
if (FLAG_CHECK(anchor, Anchor::Top))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_TOP, margin);
|
||||
}
|
||||
if (FLAG_CHECK(anchor, Anchor::Bottom))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_BOTTOM, margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,18 +115,23 @@ void Window::SetMargin(Anchor anchor, int32_t margin)
|
|||
{
|
||||
if (FLAG_CHECK(anchor, Anchor::Left))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_LEFT, margin);
|
||||
m_Margin[0] = {Anchor::Left, margin};
|
||||
}
|
||||
if (FLAG_CHECK(anchor, Anchor::Right))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_RIGHT, margin);
|
||||
m_Margin[1] = {Anchor::Right, margin};
|
||||
}
|
||||
if (FLAG_CHECK(anchor, Anchor::Top))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_TOP, margin);
|
||||
m_Margin[2] = {Anchor::Top, margin};
|
||||
}
|
||||
if (FLAG_CHECK(anchor, Anchor::Bottom))
|
||||
{
|
||||
gtk_layer_set_margin(m_Window, GTK_LAYER_SHELL_EDGE_BOTTOM, margin);
|
||||
m_Margin[2] = {Anchor::Bottom, margin};
|
||||
}
|
||||
|
||||
if (m_Window)
|
||||
{
|
||||
UpdateMargin();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
void SetExclusive(bool exclusive) { m_Exclusive = exclusive; }
|
||||
|
||||
private:
|
||||
void CreateAndAddWidget(Widget* widget, GtkWidget* parentWidget);
|
||||
void UpdateMargin();
|
||||
|
||||
GtkWindow* m_Window;
|
||||
GtkApplication* m_App = nullptr;
|
||||
|
@ -38,6 +38,7 @@ private:
|
|||
std::unique_ptr<Widget> m_MainWidget;
|
||||
|
||||
Anchor m_Anchor;
|
||||
std::array<std::pair<Anchor, int32_t>, 4> m_Margin;
|
||||
bool m_Exclusive = true;
|
||||
|
||||
int32_t m_Monitor;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "System.h"
|
||||
#include "Bar.h"
|
||||
#include "AudioFlyin.h"
|
||||
#include "BluetoothDevices.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtk-layer-shell.h>
|
||||
|
@ -43,6 +44,12 @@ int main(int argc, char** argv)
|
|||
exit(0);
|
||||
}
|
||||
}
|
||||
#ifdef HAS_BLUEZ
|
||||
else if (strcmp(argv[1], "bluetooth") == 0)
|
||||
{
|
||||
BluetoothDevices::Create(window, monitor);
|
||||
}
|
||||
#endif
|
||||
|
||||
window.Run(argc, argv);
|
||||
|
||||
|
|
Loading…
Reference in a new issue