Add Plugin system

Plugins are used to extend the functionality, without needing to poke around in
the original source code.
This commit is contained in:
scorpion-26 2023-01-28 15:07:07 +01:00
parent 64b35b86c2
commit c27912c8a5
9 changed files with 131 additions and 10 deletions

View file

@ -81,6 +81,15 @@ Bar:
Audio Flyin:
- Audio control
## Plugins
gBar utilizes a plugin system for custom widgets.
Plugins are native shared-libraries, which need to be placed inside ```~/.local/lib/gBar```, ```/usr/lib/gBar``` or ```/usr/local/lib/gBar```.
Inside example/ there is an example plugin setup. To build and run it, run the following commands:
```meson setup build -Dprefix=~/.local``` for the local user or ```meson setup build``` for all users\
```ninja -C build install```\
```gBar gBarHelloWorld``` The second argument is the name of the shared library (without 'lib' and '.so').
## FAQ
### There are already many GTK bars out there, why not use them?
@ -102,9 +111,6 @@ If you have SASS installed: Edit ~/.config/gBar/style.scss and regenerate style.
Else: Edit ~/.config/gBar/style.css directly!
### I want to modify the widgets behaviour/Add my own widgets
Unfortunately, you need to implement it yourself in C++. For inspiration look into src/Bar.cpp or src/AudioFlyin.cpp, or open an issue(Maybe I'll implement it for you).
### The Audio widget doesn't open
Delete /tmp/gBar__audio.
This happens, when you kill the widget before it closes automatically after a few seconds.

12
example/main.cpp Normal file
View file

@ -0,0 +1,12 @@
#include <gBar/Common.h>
#include <gBar/Window.h>
void Create(Window& window, int32_t monitor)
{
auto mainWidget = Widget::Create<Text>();
mainWidget->SetText("Hello, World!");
window = Window(std::move(mainWidget), monitor);
}
DEFINE_PLUGIN(Create);

18
example/meson.build Normal file
View file

@ -0,0 +1,18 @@
project('gBarHelloWorld',
['cpp'],
version: '0.0.1',
license: 'MIT',
meson_version: '>=0.45.1',
default_options: ['c_std=c++17', 'warning_level=3'])
# Important!
gtk = dependency('gtk+-3.0')
gBar = dependency('gBar')
library(
'gBarHelloWorld',
['main.cpp'],
dependencies: [gBar],
install: true,
install_dir: 'lib/gBar/')

View file

@ -2,17 +2,27 @@ project('gBar',
['cpp'],
version: '0.0.1',
license: 'MIT',
meson_version: '>=0.45.1',
meson_version: '>=0.46.0',
default_options: ['c_std=c++17', 'warning_level=3'])
gtk = dependency('gtk+-3.0')
gtk_layer_shell = dependency('gtk-layer-shell-0')
headers = [
'src/Common.h',
'src/System.h',
'src/PulseAudio.h',
'src/Widget.h',
'src/Window.h',
]
if get_option('HasHyprland')
add_global_arguments('-DHAS_HYPRLAND', language: 'cpp')
headers += 'src/NvidiaGPU.h'
endif
if get_option('HasNvidia')
add_global_arguments('-DHAS_NVIDIA', language: 'cpp')
headers += 'src/Hyprland.h'
endif
if get_option('HasBlueZ')
add_global_arguments('-DHAS_BLUEZ', language: 'cpp')
@ -23,16 +33,30 @@ endif
pulse = dependency('libpulse')
executable(
'gBar',
['src/gBar.cpp',
'src/Window.cpp',
libgBar = library('gBar',
['src/Window.cpp',
'src/Widget.cpp',
'src/System.cpp',
'src/Bar.cpp',
'src/AudioFlyin.cpp',
'src/BluetoothDevices.cpp',
'src/Plugin.cpp'
],
dependencies: [gtk, gtk_layer_shell, pulse],
install: true)
pkg = import('pkgconfig')
pkg.generate(libgBar)
executable(
'gBar',
['src/gBar.cpp'],
dependencies: [gtk],
link_with: libgBar,
install: true
)
install_headers(
headers,
subdir: 'gBar'
)

View file

@ -83,3 +83,17 @@ inline Process OpenProcess(Args... args)
return {child};
}
}
// Plugins
#include "Window.h"
#define DL_VERSION 1
#define DEFINE_PLUGIN(fun) \
extern "C" int32_t Plugin_GetVersion() \
{ \
return DL_VERSION; \
}; \
extern "C" void Plugin_InvokeCreateFun(void* window, int32_t monitor) \
{ \
fun(*(Window*)window, monitor); \
}

35
src/Plugin.cpp Normal file
View file

@ -0,0 +1,35 @@
#include "Plugin.h"
#include "Common.h"
#include "Window.h"
#include <dlfcn.h>
void Plugin::LoadWidgetFromPlugin(const std::string& pluginName, Window& window, int32_t monitor)
{
std::string home = std::getenv("HOME");
std::array<std::string, 3> paths = {home + "/.local/lib/gBar", "/usr/local/lib/gBar", "/usr/lib/gBar"};
// 1. Try and load plugin
void* dl;
for (auto& path : paths)
{
std::string soPath = path + "/lib" + pluginName + ".so";
dl = dlopen(soPath.c_str(), RTLD_NOW);
if (dl)
break;
}
ASSERT(dl, "Cannot find plugin library!");
typedef void (*PFN_InvokeCreateFun)(void*, int32_t);
typedef int32_t (*PFN_GetVersion)();
auto getVersion = (PFN_GetVersion)dlsym(dl, "Plugin_GetVersion");
ASSERT(getVersion, "DL is not a valid gBar plugin!");
ASSERT(getVersion() == DL_VERSION, "Mismatching version, please recompile your plugin!");
typedef void (*PFN_InvokeCreateFun)(void*, int32_t);
auto invokeCreateFun = (PFN_InvokeCreateFun)dlsym(dl, "Plugin_InvokeCreateFun");
ASSERT(invokeCreateFun, "DL is not a valid gBar plugin!");
// Execute
invokeCreateFun(&window, monitor);
}

8
src/Plugin.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
#include <string>
#include "Window.h"
namespace Plugin
{
void LoadWidgetFromPlugin(const std::string& pluginName, Window& window, int32_t monitor);
}

View file

@ -1,6 +1,7 @@
#include "Window.h"
#include "Common.h"
#include <gtk/gtk.h>
#include <gtk-layer-shell.h>
Window::Window(std::unique_ptr<Widget>&& mainWidget, int32_t monitor) : m_MainWidget(std::move(mainWidget)), m_Monitor(monitor) {}

View file

@ -4,9 +4,8 @@
#include "Bar.h"
#include "AudioFlyin.h"
#include "BluetoothDevices.h"
#include "Plugin.h"
#include <gtk/gtk.h>
#include <gtk-layer-shell.h>
#include <cmath>
#include <cstdio>
#include <unistd.h>
@ -50,6 +49,10 @@ int main(int argc, char** argv)
BluetoothDevices::Create(window, monitor);
}
#endif
else
{
Plugin::LoadWidgetFromPlugin(argv[1], window, monitor);
}
window.Run(argc, argv);