diff --git a/README.md b/README.md index 7f23a92..11f606e 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/example/main.cpp b/example/main.cpp new file mode 100644 index 0000000..6be79e9 --- /dev/null +++ b/example/main.cpp @@ -0,0 +1,12 @@ +#include +#include + +void Create(Window& window, int32_t monitor) +{ + auto mainWidget = Widget::Create(); + mainWidget->SetText("Hello, World!"); + + window = Window(std::move(mainWidget), monitor); +} + +DEFINE_PLUGIN(Create); diff --git a/example/meson.build b/example/meson.build new file mode 100644 index 0000000..c641208 --- /dev/null +++ b/example/meson.build @@ -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/') diff --git a/meson.build b/meson.build index f51e520..4db0422 100644 --- a/meson.build +++ b/meson.build @@ -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' +) diff --git a/src/Common.h b/src/Common.h index c3aa941..b3aba74 100644 --- a/src/Common.h +++ b/src/Common.h @@ -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); \ + } diff --git a/src/Plugin.cpp b/src/Plugin.cpp new file mode 100644 index 0000000..477fa14 --- /dev/null +++ b/src/Plugin.cpp @@ -0,0 +1,35 @@ +#include "Plugin.h" +#include "Common.h" +#include "Window.h" + +#include + +void Plugin::LoadWidgetFromPlugin(const std::string& pluginName, Window& window, int32_t monitor) +{ + std::string home = std::getenv("HOME"); + std::array 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); +} + diff --git a/src/Plugin.h b/src/Plugin.h new file mode 100644 index 0000000..314d41d --- /dev/null +++ b/src/Plugin.h @@ -0,0 +1,8 @@ +#pragma once +#include +#include "Window.h" + +namespace Plugin +{ + void LoadWidgetFromPlugin(const std::string& pluginName, Window& window, int32_t monitor); +} diff --git a/src/Window.cpp b/src/Window.cpp index 78a7197..afbb635 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,6 +1,7 @@ #include "Window.h" #include "Common.h" +#include #include Window::Window(std::unique_ptr&& mainWidget, int32_t monitor) : m_MainWidget(std::move(mainWidget)), m_Monitor(monitor) {} diff --git a/src/gBar.cpp b/src/gBar.cpp index 49212f8..ea02e4f 100644 --- a/src/gBar.cpp +++ b/src/gBar.cpp @@ -4,9 +4,8 @@ #include "Bar.h" #include "AudioFlyin.h" #include "BluetoothDevices.h" +#include "Plugin.h" -#include -#include #include #include #include @@ -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);