-
-
Notifications
You must be signed in to change notification settings - Fork 732
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2573 from CromFr/cabi_plugins
C ABI plugin system
- Loading branch information
Showing
12 changed files
with
435 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include "AModule.hpp" | ||
#include "util/command.hpp" | ||
#include "util/json.hpp" | ||
#include "util/sleeper_thread.hpp" | ||
|
||
namespace waybar::modules { | ||
|
||
namespace ffi { | ||
extern "C" { | ||
typedef struct wbcffi_module wbcffi_module; | ||
|
||
typedef struct { | ||
wbcffi_module* obj; | ||
const char* waybar_version; | ||
GtkContainer* (*get_root_widget)(wbcffi_module*); | ||
void (*queue_update)(wbcffi_module*); | ||
} wbcffi_init_info; | ||
|
||
struct wbcffi_config_entry { | ||
const char* key; | ||
const char* value; | ||
}; | ||
} | ||
} // namespace ffi | ||
|
||
class CFFI : public AModule { | ||
public: | ||
CFFI(const std::string&, const std::string&, const Json::Value&); | ||
virtual ~CFFI(); | ||
|
||
virtual auto refresh(int signal) -> void override; | ||
virtual auto doAction(const std::string& name) -> void override; | ||
virtual auto update() -> void override; | ||
|
||
private: | ||
/// | ||
void* cffi_instance_ = nullptr; | ||
|
||
typedef void*(InitFn)(const ffi::wbcffi_init_info* init_info, | ||
const ffi::wbcffi_config_entry* config_entries, size_t config_entries_len); | ||
typedef void(DenitFn)(void* instance); | ||
typedef void(RefreshFn)(void* instance, int signal); | ||
typedef void(DoActionFn)(void* instance, const char* name); | ||
typedef void(UpdateFn)(void* instance); | ||
|
||
// FFI hooks | ||
struct { | ||
std::function<InitFn> init = nullptr; | ||
std::function<DenitFn> deinit = nullptr; | ||
std::function<RefreshFn> refresh = [](void*, int) {}; | ||
std::function<DoActionFn> doAction = [](void*, const char*) {}; | ||
std::function<UpdateFn> update = [](void*) {}; | ||
} hooks_; | ||
}; | ||
|
||
} // namespace waybar::modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
waybar-cffi(5) | ||
# NAME | ||
|
||
waybar - cffi module | ||
|
||
# DESCRIPTION | ||
|
||
The *cffi* module gives full control of a GTK widget to a third-party dynamic library, to create more complex modules using different programming languages. | ||
|
||
# CONFIGURATION | ||
|
||
Addressed by *cffi/<name>* | ||
|
||
*module_path*: ++ | ||
typeof: string ++ | ||
The path to the dynamic library to load to control the widget. | ||
|
||
Some additional configuration may be required depending on the cffi dynamic library being used. | ||
|
||
|
||
# EXAMPLES | ||
|
||
## C example: | ||
|
||
An example module written in C can be found at https://github.com/Alexays/Waybar/resources/custom_modules/cffi_example/ | ||
|
||
Waybar config to enable the module: | ||
``` | ||
"cffi/c_example": { | ||
"module_path": ".config/waybar/cffi/wb_cffi_example.so" | ||
} | ||
``` | ||
|
||
|
||
# STYLE | ||
|
||
The classes and IDs are managed by the cffi dynamic library. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# C FFI module | ||
|
||
A C FFI module is a dynamic library that exposes standard C functions and | ||
constants, that Waybar can load and execute to create custom advanced widgets. | ||
|
||
Most language can implement the required functions and constants (C, C++, Rust, | ||
Go, Python, ...), meaning you can develop custom modules using your language of | ||
choice, as long as there's GTK bindings. | ||
|
||
Symbols to implement are documented in the | ||
[waybar_cffi_module.h](waybar_cffi_module.h) file. | ||
|
||
# Usage | ||
|
||
## Building this module | ||
|
||
```bash | ||
meson setup build | ||
meson compile -C build | ||
``` | ||
|
||
## Load the module | ||
|
||
Edit your waybar config: | ||
```json | ||
{ | ||
// ... | ||
"modules-center": [ | ||
// ... | ||
"cffi/c_example" | ||
], | ||
// ... | ||
"cffi/c_example": { | ||
// Path to the compiled dynamic library file | ||
"module_path": "resources/custom_modules/cffi_example/build/wb_cffi_example.so" | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
|
||
#include "waybar_cffi_module.h" | ||
|
||
typedef struct { | ||
wbcffi_module* waybar_module; | ||
GtkBox* container; | ||
GtkButton* button; | ||
} ExampleMod; | ||
|
||
// This static variable is shared between all instances of this module | ||
static int instance_count = 0; | ||
|
||
void onclicked(GtkButton* button) { | ||
char text[256]; | ||
snprintf(text, 256, "Dice throw result: %d", rand() % 6 + 1); | ||
gtk_button_set_label(button, text); | ||
} | ||
|
||
// You must | ||
const size_t wbcffi_version = 1; | ||
|
||
void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* config_entries, | ||
size_t config_entries_len) { | ||
printf("cffi_example: init config:\n"); | ||
for (size_t i = 0; i < config_entries_len; i++) { | ||
printf(" %s = %s\n", config_entries[i].key, config_entries[i].value); | ||
} | ||
|
||
// Allocate the instance object | ||
ExampleMod* inst = malloc(sizeof(ExampleMod)); | ||
inst->waybar_module = init_info->obj; | ||
|
||
GtkContainer* root = init_info->get_root_widget(init_info->obj); | ||
|
||
// Add a container for displaying the next widgets | ||
inst->container = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5)); | ||
gtk_container_add(GTK_CONTAINER(root), GTK_WIDGET(inst->container)); | ||
|
||
// Add a label | ||
GtkLabel* label = GTK_LABEL(gtk_label_new("[Example C FFI Module:")); | ||
gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(label)); | ||
|
||
// Add a button | ||
inst->button = GTK_BUTTON(gtk_button_new_with_label("click me !")); | ||
g_signal_connect(inst->button, "clicked", G_CALLBACK(onclicked), NULL); | ||
gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(inst->button)); | ||
|
||
// Add a label | ||
label = GTK_LABEL(gtk_label_new("]")); | ||
gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(label)); | ||
|
||
// Return instance object | ||
printf("cffi_example inst=%p: init success ! (%d total instances)\n", inst, ++instance_count); | ||
return inst; | ||
} | ||
|
||
void wbcffi_deinit(void* instance) { | ||
printf("cffi_example inst=%p: free memory\n", instance); | ||
free(instance); | ||
} | ||
|
||
void wbcffi_update(void* instance) { printf("cffi_example inst=%p: Update request\n", instance); } | ||
|
||
void wbcffi_refresh(void* instance, int signal) { | ||
printf("cffi_example inst=%p: Received refresh signal %d\n", instance, signal); | ||
} | ||
|
||
void wbcffi_doaction(void* instance, const char* name) { | ||
printf("cffi_example inst=%p: doAction(%s)\n", instance, name); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
project( | ||
'waybar_cffi_example', 'c', | ||
version: '0.1.0', | ||
license: 'MIT', | ||
) | ||
|
||
shared_library('wb_cffi_example', | ||
['main.c'], | ||
dependencies: [ | ||
dependency('gtk+-3.0', version : ['>=3.22.0']) | ||
], | ||
name_prefix: '' | ||
) |
89 changes: 89 additions & 0 deletions
89
resources/custom_modules/cffi_example/waybar_cffi_module.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#pragma once | ||
|
||
#include <gtk/gtk.h> | ||
#include <stdint.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/// Waybar ABI version. 1 is the latest version | ||
extern const size_t wbcffi_version; | ||
|
||
/// Private Waybar CFFI module | ||
typedef struct wbcffi_module wbcffi_module; | ||
|
||
/// Waybar module information | ||
typedef struct { | ||
/// Waybar CFFI object pointer | ||
wbcffi_module* obj; | ||
|
||
/// Waybar version string | ||
const char* waybar_version; | ||
|
||
/// Returns the waybar widget allocated for this module | ||
/// @param obj Waybar CFFI object pointer | ||
GtkContainer* (*get_root_widget)(wbcffi_module* obj); | ||
|
||
/// Queues a request for calling wbcffi_update() on the next GTK main event | ||
/// loop iteration | ||
/// @param obj Waybar CFFI object pointer | ||
void (*queue_update)(wbcffi_module*); | ||
} wbcffi_init_info; | ||
|
||
/// Config key-value pair | ||
typedef struct { | ||
/// Entry key | ||
const char* key; | ||
/// Entry value as string. JSON object and arrays are serialized. | ||
const char* value; | ||
} wbcffi_config_entry; | ||
|
||
/// Module init/new function, called on module instantiation | ||
/// | ||
/// MANDATORY CFFI function | ||
/// | ||
/// @param init_info Waybar module information | ||
/// @param config_entries Flat representation of the module JSON config. The data only available | ||
/// during wbcffi_init call. | ||
/// @param config_entries_len Number of entries in `config_entries` | ||
/// | ||
/// @return A untyped pointer to module data, NULL if the module failed to load. | ||
void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* config_entries, | ||
size_t config_entries_len); | ||
|
||
/// Module deinit/delete function, called when Waybar is closed or when the module is removed | ||
/// | ||
/// MANDATORY CFFI function | ||
/// | ||
/// @param instance Module instance data (as returned by `wbcffi_init`) | ||
void wbcffi_deinit(void* instance); | ||
|
||
/// Called from the GTK main event loop, to update the UI | ||
/// | ||
/// Optional CFFI function | ||
/// | ||
/// @param instance Module instance data (as returned by `wbcffi_init`) | ||
/// @param action_name Action name | ||
void wbcffi_update(void* instance); | ||
|
||
/// Called when Waybar receives a POSIX signal and forwards it to each module | ||
/// | ||
/// Optional CFFI function | ||
/// | ||
/// @param instance Module instance data (as returned by `wbcffi_init`) | ||
/// @param signal Signal ID | ||
void wbcffi_refresh(void* instance, int signal); | ||
|
||
/// Called on module action (see | ||
/// https://github.com/Alexays/Waybar/wiki/Configuration#module-actions-config) | ||
/// | ||
/// Optional CFFI function | ||
/// | ||
/// @param instance Module instance data (as returned by `wbcffi_init`) | ||
/// @param action_name Action name | ||
void wbcffi_doaction(void* instance, const char* action_name); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.