modular dwmclocky
This commit is contained in:
commit
f6cba2c8a1
3
dwmclocky/.gitignore
vendored
Normal file
3
dwmclocky/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
modules/*
|
||||
dim
|
||||
|
11
dwmclocky/build.sh
Executable file
11
dwmclocky/build.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
CCARGS="-Isrc/include -Wall -pedantic"
|
||||
|
||||
cc -o dim src/main.c src/plug.c $CCARGS -lX11 -ldl
|
||||
cc -o modules/clocky.dim src/modules/clock.c -rdynamic -shared -fPIC $CCARGS
|
||||
cc -o modules/battery.dim src/modules/battery.c -rdynamic -shared -fPIC $CCARGS
|
||||
|
||||
|
30
dwmclocky/src/include/plug.h
Normal file
30
dwmclocky/src/include/plug.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
#ifndef _H_PLUG
|
||||
#define _H_PLUG
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void (*plug_init_f) ();
|
||||
typedef void (*plug_reload_f) ();
|
||||
typedef void (*plug_poll_f) (char*, size_t);
|
||||
typedef void (*plug_free_f) ();
|
||||
|
||||
typedef struct plug_t {
|
||||
char* name;
|
||||
char* version;
|
||||
} plug_t;
|
||||
|
||||
typedef struct plug_int_t {
|
||||
plug_init_f f_init;
|
||||
plug_reload_f f_reload;
|
||||
plug_poll_f f_poll;
|
||||
plug_free_f f_free;
|
||||
plug_t* s_plug_info;
|
||||
} plug_int_t;
|
||||
|
||||
void setup_plugins(char* plugin_path);
|
||||
char* poll_plugins();
|
||||
void free_plugins();
|
||||
|
||||
#endif
|
||||
|
26
dwmclocky/src/main.c
Normal file
26
dwmclocky/src/main.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "plug.h"
|
||||
|
||||
int main(void) {
|
||||
setup_plugins("./modules");
|
||||
char* buffer;
|
||||
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
Window window = DefaultRootWindow(display);
|
||||
|
||||
while (1) {
|
||||
buffer = poll_plugins("|");
|
||||
XStoreName(display, window, buffer);
|
||||
XFlush(display);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
|
||||
XCloseDisplay(display);
|
||||
free_plugins();
|
||||
return 0;
|
||||
|
||||
}
|
42
dwmclocky/src/modules/battery.c
Normal file
42
dwmclocky/src/modules/battery.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "plug.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
plug_t PLUG = {0};
|
||||
|
||||
static FILE* fp = NULL;
|
||||
|
||||
char* batt_files[] = {
|
||||
"/sys/class/power_supply/BAT0/capacity",
|
||||
"/sys/class/power_supply/BAT1/capacity"
|
||||
};
|
||||
|
||||
void plug_init(void) {
|
||||
PLUG.name = "Battery";
|
||||
PLUG.version = "0.0.1";
|
||||
|
||||
for (size_t i = 0; i < sizeof(batt_files)/sizeof(batt_files[0]); i++) {
|
||||
if (access(batt_files[i], F_OK) == 0) {
|
||||
fp = fopen(batt_files[i], "r");
|
||||
if (fp) {
|
||||
printf("Opened %s\n", batt_files[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
printf("MODULE: ERROR: Unable to find battery\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void plug_reload(void) { /* Unused */ }
|
||||
|
||||
void plug_poll(char* buf, size_t len) {
|
||||
int perc = 0;
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fscanf(fp, "%d", &perc);
|
||||
snprintf(buf, len, "Batt: %d%%", perc);
|
||||
}
|
||||
|
||||
void plug_free(void) {}
|
23
dwmclocky/src/modules/clock.c
Normal file
23
dwmclocky/src/modules/clock.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "plug.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
plug_t PLUG = {0};
|
||||
|
||||
void plug_init(void) {
|
||||
PLUG.name = "time";
|
||||
PLUG.version = "0.0.1";
|
||||
}
|
||||
|
||||
void plug_reload(void) { /* Unused */ }
|
||||
|
||||
void plug_poll(char* buf, size_t len) {
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
strftime(buf, len, "Time: %H:%M (%Y-%m-%d)", timeinfo);
|
||||
}
|
||||
|
||||
void plug_free(void) {}
|
168
dwmclocky/src/plug.c
Normal file
168
dwmclocky/src/plug.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include "plug.h"
|
||||
|
||||
|
||||
#define PLUG_PATH_MAX 255
|
||||
#define PLUG_MAX_COUNT (PLUG_PATH_MAX+255)
|
||||
#define PLUG_POLL_BUF_SZ 1024
|
||||
|
||||
typedef struct PlugMan {
|
||||
plug_int_t* plugs[PLUG_MAX_COUNT];
|
||||
size_t plug_count;
|
||||
void* plug_objs[PLUG_MAX_COUNT];
|
||||
size_t plug_obj_count;
|
||||
} plugman_t;
|
||||
|
||||
|
||||
static plugman_t PLUGMAN = {0};
|
||||
|
||||
void* load_plug_sym(void* plug_f, char* fn_name);
|
||||
plug_int_t* load_plugin(char* path);
|
||||
|
||||
void load_plugins(const char* mod_dir_p) {
|
||||
DIR* dir = {0};
|
||||
|
||||
dir = opendir(mod_dir_p);
|
||||
|
||||
if (!dir) {
|
||||
printf("ERROR: Failed to open dir %s\n", mod_dir_p);
|
||||
}
|
||||
|
||||
struct dirent* dir_entry;
|
||||
|
||||
while ((dir_entry = readdir(dir)) != NULL) {
|
||||
if (!(dir_entry->d_type == DT_REG ||
|
||||
dir_entry->d_type == DT_LNK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(dir_entry->d_name, ".") == 0 ||
|
||||
strcmp(dir_entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char* dot = strchr(dir_entry->d_name, '.');
|
||||
|
||||
if (!dot || dot == dir_entry->d_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char* ext = dot+1;
|
||||
if (strcmp(ext, "dim") != 0) continue;
|
||||
|
||||
printf("INFO: Found plugin: %s/%s\n", mod_dir_p, dir_entry->d_name);
|
||||
|
||||
char full_path[PLUG_MAX_COUNT] = {0};
|
||||
snprintf(full_path, PLUG_MAX_COUNT, "%s/%s", mod_dir_p, dir_entry->d_name);
|
||||
plug_int_t* plug = load_plugin(full_path);
|
||||
|
||||
if (!plug) {
|
||||
printf("ERROR: Failed to load plugin %s, skipping\n", full_path);
|
||||
continue;
|
||||
}
|
||||
PLUGMAN.plugs[PLUGMAN.plug_count++] = plug;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
plug_int_t* load_plugin(char* path) {
|
||||
plug_int_t* plug = malloc(sizeof(plug_int_t));
|
||||
void* plug_f = dlopen(path, RTLD_NOW);
|
||||
|
||||
if (!plug_f) {
|
||||
printf("ERROR: Failed to load plugin %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// "technically" couldnt run on very niche platforms but idc
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
plug->f_init = (plug_init_f)load_plug_sym(plug_f, "plug_init");
|
||||
plug->f_reload = (plug_reload_f)load_plug_sym(plug_f, "plug_reload");
|
||||
plug->f_poll = (plug_poll_f)load_plug_sym(plug_f, "plug_poll");
|
||||
plug->f_free = (plug_free_f)load_plug_sym(plug_f, "plug_free");
|
||||
plug->s_plug_info = (plug_t*)load_plug_sym(plug_f, "PLUG");
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
if (!plug->f_init || !plug->f_reload ||
|
||||
!plug->f_poll || !plug->f_free ||
|
||||
!plug->s_plug_info) {
|
||||
dlclose(plug_f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PLUGMAN.plug_objs[PLUGMAN.plug_obj_count++] = plug_f;
|
||||
return plug;
|
||||
}
|
||||
|
||||
|
||||
void* load_plug_sym(void* plug_f, char* fn_name) {
|
||||
void* f = dlsym(plug_f, fn_name);
|
||||
char* err = dlerror();
|
||||
|
||||
if (err){
|
||||
printf("ERROR: Could not load plug symbol '%s': %s\n", fn_name, err);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void setup_plugins(char* plugin_path) {
|
||||
load_plugins(plugin_path);
|
||||
printf("INFO: Loaded %zu plugins:\n", PLUGMAN.plug_count);
|
||||
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||
|
||||
(plug->f_init)();
|
||||
printf(" - %s (%s)\n", plug->s_plug_info->name, plug->s_plug_info->version);
|
||||
}
|
||||
}
|
||||
|
||||
void free_plugins() {
|
||||
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||
(plug->f_free)();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < PLUGMAN.plug_obj_count; i++) {
|
||||
dlclose(PLUGMAN.plug_objs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
char* poll_plugins(char* sep) {
|
||||
char* buf = malloc(PLUG_POLL_BUF_SZ * sizeof(char));
|
||||
|
||||
if (!buf) {
|
||||
printf("Unable to allocate buffer for polling\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||
|
||||
printf("Polling plug id %zu\n", i);
|
||||
|
||||
size_t len = strlen(buf);
|
||||
(plug->f_poll)(buf + len, PLUG_POLL_BUF_SZ - len);
|
||||
|
||||
if (i < PLUGMAN.plug_count - 1) {
|
||||
size_t len_post = strlen(buf);
|
||||
snprintf(buf + len_post, PLUG_POLL_BUF_SZ - len_post, " %s ", sep);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Setting title: '%s'\n", buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
6
dwmclocky/test.sh
Normal file
6
dwmclocky/test.sh
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
while true; do
|
||||
clear -x
|
||||
xprop -root | grep -Po "WM_NAME\(STRING\) = \"\K.*(?=\")"
|
||||
sleep 0.5
|
||||
done
|
Loading…
Reference in New Issue
Block a user