summaryrefslogtreecommitdiff
path: root/mac/.config/sketchybar.mon/helper
diff options
context:
space:
mode:
Diffstat (limited to 'mac/.config/sketchybar.mon/helper')
-rw-r--r--mac/.config/sketchybar.mon/helper/cpu.h122
-rwxr-xr-xmac/.config/sketchybar.mon/helper/helperbin0 -> 34872 bytes
-rw-r--r--mac/.config/sketchybar.mon/helper/helper.c31
-rw-r--r--mac/.config/sketchybar.mon/helper/makefile3
-rw-r--r--mac/.config/sketchybar.mon/helper/sketchybar.h209
5 files changed, 365 insertions, 0 deletions
diff --git a/mac/.config/sketchybar.mon/helper/cpu.h b/mac/.config/sketchybar.mon/helper/cpu.h
new file mode 100644
index 0000000..c350ae3
--- /dev/null
+++ b/mac/.config/sketchybar.mon/helper/cpu.h
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <stdbool.h>
+#include <time.h>
+
+#define MAX_TOPPROC_LEN 28
+
+static const char TOPPROC[] = { "/bin/ps -Aceo pid,pcpu,comm -r" };
+static const char FILTER_PATTERN[] = { "com.apple." };
+
+struct cpu {
+ host_t host;
+ mach_msg_type_number_t count;
+ host_cpu_load_info_data_t load;
+ host_cpu_load_info_data_t prev_load;
+ bool has_prev_load;
+
+ char command[256];
+};
+
+static inline void cpu_init(struct cpu* cpu) {
+ cpu->host = mach_host_self();
+ cpu->count = HOST_CPU_LOAD_INFO_COUNT;
+ cpu->has_prev_load = false;
+ snprintf(cpu->command, 100, "");
+}
+
+static inline void cpu_update(struct cpu* cpu) {
+ kern_return_t error = host_statistics(cpu->host,
+ HOST_CPU_LOAD_INFO,
+ (host_info_t)&cpu->load,
+ &cpu->count );
+
+ if (error != KERN_SUCCESS) {
+ printf("Error: Could not read cpu host statistics.\n");
+ return;
+ }
+
+ if (cpu->has_prev_load) {
+ uint32_t delta_user = cpu->load.cpu_ticks[CPU_STATE_USER]
+ - cpu->prev_load.cpu_ticks[CPU_STATE_USER];
+
+ uint32_t delta_system = cpu->load.cpu_ticks[CPU_STATE_SYSTEM]
+ - cpu->prev_load.cpu_ticks[CPU_STATE_SYSTEM];
+
+ uint32_t delta_idle = cpu->load.cpu_ticks[CPU_STATE_IDLE]
+ - cpu->prev_load.cpu_ticks[CPU_STATE_IDLE];
+
+ double user_perc = (double)delta_user / (double)(delta_system
+ + delta_user
+ + delta_idle);
+
+ double sys_perc = (double)delta_system / (double)(delta_system
+ + delta_user
+ + delta_idle);
+
+ double total_perc = user_perc + sys_perc;
+
+ FILE* file;
+ char line[1024];
+
+ file = popen(TOPPROC, "r");
+ if (!file) {
+ printf("Error: TOPPROC command errored out...\n" );
+ return;
+ }
+
+ fgets(line, sizeof(line), file);
+ fgets(line, sizeof(line), file);
+
+ char* start = strstr(line, FILTER_PATTERN);
+ char topproc[MAX_TOPPROC_LEN + 4];
+ uint32_t caret = 0;
+ for (int i = 0; i < sizeof(line); i++) {
+ if (start && i == start - line) {
+ i+=9;
+ continue;
+ }
+
+ if (caret >= MAX_TOPPROC_LEN && caret <= MAX_TOPPROC_LEN + 2) {
+ topproc[caret++] = '.';
+ continue;
+ }
+ if (caret > MAX_TOPPROC_LEN + 2) break;
+ topproc[caret++] = line[i];
+ if (line[i] == '\0') break;
+ }
+
+ topproc[MAX_TOPPROC_LEN + 3] = '\0';
+
+ pclose(file);
+
+ char color[16];
+ if (total_perc >= .7) {
+ snprintf(color, 16, "%s", getenv("RED"));
+ } else if (total_perc >= .3) {
+ snprintf(color, 16, "%s", getenv("ORANGE"));
+ } else if (total_perc >= .1) {
+ snprintf(color, 16, "%s", getenv("YELLOW"));
+ } else {
+ snprintf(color, 16, "%s", getenv("LABEL_COLOR"));
+ }
+
+ snprintf(cpu->command, 256, "--push cpu.sys %.2f "
+ "--push cpu.user %.2f "
+ "--set cpu.top label='%s' "
+ "--set cpu.percent label=%.0f%% label.color=%s ",
+ sys_perc,
+ user_perc,
+ topproc,
+ total_perc*100.,
+ color );
+ }
+ else {
+ snprintf(cpu->command, 256, "");
+ }
+
+ cpu->prev_load = cpu->load;
+ cpu->has_prev_load = true;
+}
diff --git a/mac/.config/sketchybar.mon/helper/helper b/mac/.config/sketchybar.mon/helper/helper
new file mode 100755
index 0000000..050cca7
--- /dev/null
+++ b/mac/.config/sketchybar.mon/helper/helper
Binary files differ
diff --git a/mac/.config/sketchybar.mon/helper/helper.c b/mac/.config/sketchybar.mon/helper/helper.c
new file mode 100644
index 0000000..71c3038
--- /dev/null
+++ b/mac/.config/sketchybar.mon/helper/helper.c
@@ -0,0 +1,31 @@
+#include "cpu.h"
+#include "sketchybar.h"
+
+struct cpu g_cpu;
+
+void handler(env env) {
+ // Environment variables passed from sketchybar can be accessed as seen below
+ char* name = env_get_value_for_key(env, "NAME");
+ char* sender = env_get_value_for_key(env, "SENDER");
+ char* info = env_get_value_for_key(env, "INFO");
+ char* selected = env_get_value_for_key(env, "SELECTED");
+
+ if ((strcmp(name, "cpu.percent") == 0)) {
+ // CPU graph updates
+ cpu_update(&g_cpu);
+
+ if (strlen(g_cpu.command) > 0) sketchybar(g_cpu.command);
+ }
+}
+
+int main (int argc, char** argv) {
+ cpu_init(&g_cpu);
+
+ if (argc < 2) {
+ printf("Usage: helper \"<bootstrap name>\"\n");
+ exit(1);
+ }
+
+ event_server_begin(handler, argv[1]);
+ return 0;
+}
diff --git a/mac/.config/sketchybar.mon/helper/makefile b/mac/.config/sketchybar.mon/helper/makefile
new file mode 100644
index 0000000..ac8721a
--- /dev/null
+++ b/mac/.config/sketchybar.mon/helper/makefile
@@ -0,0 +1,3 @@
+
+helper: helper.c cpu.h sketchybar.h
+ clang -std=c99 -O3 helper.c -o helper
diff --git a/mac/.config/sketchybar.mon/helper/sketchybar.h b/mac/.config/sketchybar.mon/helper/sketchybar.h
new file mode 100644
index 0000000..2ab4c39
--- /dev/null
+++ b/mac/.config/sketchybar.mon/helper/sketchybar.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include <mach/mach.h>
+#include <mach/mach_port.h>
+#include <mach/message.h>
+#include <bootstrap.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdio.h>
+
+typedef char* env;
+
+#define MACH_HANDLER(name) void name(env env)
+typedef MACH_HANDLER(mach_handler);
+
+struct mach_message {
+ mach_msg_header_t header;
+ mach_msg_size_t msgh_descriptor_count;
+ mach_msg_ool_descriptor_t descriptor;
+};
+
+struct mach_buffer {
+ struct mach_message message;
+ mach_msg_trailer_t trailer;
+};
+
+struct mach_server {
+ bool is_running;
+ mach_port_name_t task;
+ mach_port_t port;
+ mach_port_t bs_port;
+
+ pthread_t thread;
+ mach_handler* handler;
+};
+
+static struct mach_server g_mach_server;
+static mach_port_t g_mach_port = 0;
+
+static inline char* env_get_value_for_key(env env, char* key) {
+ uint32_t caret = 0;
+ for(;;) {
+ if (!env[caret]) break;
+ if (strcmp(&env[caret], key) == 0)
+ return &env[caret + strlen(&env[caret]) + 1];
+
+ caret += strlen(&env[caret])
+ + strlen(&env[caret + strlen(&env[caret]) + 1])
+ + 2;
+ }
+ return (char*)"";
+}
+
+static inline mach_port_t mach_get_bs_port() {
+ mach_port_name_t task = mach_task_self();
+
+ mach_port_t bs_port;
+ if (task_get_special_port(task,
+ TASK_BOOTSTRAP_PORT,
+ &bs_port ) != KERN_SUCCESS) {
+ return 0;
+ }
+
+ mach_port_t port;
+ if (bootstrap_look_up(bs_port,
+ "git.felix.sketchybar",
+ &port ) != KERN_SUCCESS) {
+ return 0;
+ }
+
+ return port;
+}
+
+static inline void mach_receive_message(mach_port_t port, struct mach_buffer* buffer, bool timeout) {
+ *buffer = (struct mach_buffer) { 0 };
+ mach_msg_return_t msg_return;
+ if (timeout)
+ msg_return = mach_msg(&buffer->message.header,
+ MACH_RCV_MSG | MACH_RCV_TIMEOUT,
+ 0,
+ sizeof(struct mach_buffer),
+ port,
+ 100,
+ MACH_PORT_NULL );
+ else
+ msg_return = mach_msg(&buffer->message.header,
+ MACH_RCV_MSG,
+ 0,
+ sizeof(struct mach_buffer),
+ port,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL );
+
+ if (msg_return != MACH_MSG_SUCCESS) {
+ buffer->message.descriptor.address = NULL;
+ }
+}
+
+static inline char* mach_send_message(mach_port_t port, char* message, uint32_t len) {
+ if (!message || !port) {
+ return NULL;
+ }
+
+ struct mach_message msg = { 0 };
+ msg.header.msgh_remote_port = port;
+ msg.header.msgh_local_port = 0;
+ msg.header.msgh_id = 0;
+ msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSG_TYPE_MAKE_SEND,
+ 0,
+ MACH_MSGH_BITS_COMPLEX );
+
+ msg.header.msgh_size = sizeof(struct mach_message);
+ msg.msgh_descriptor_count = 1;
+ msg.descriptor.address = message;
+ msg.descriptor.size = len * sizeof(char);
+ msg.descriptor.copy = MACH_MSG_VIRTUAL_COPY;
+ msg.descriptor.deallocate = false;
+ msg.descriptor.type = MACH_MSG_OOL_DESCRIPTOR;
+
+ mach_msg(&msg.header,
+ MACH_SEND_MSG,
+ sizeof(struct mach_message),
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL );
+
+ return NULL;
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+static inline bool mach_server_begin(struct mach_server* mach_server, mach_handler handler, char* bootstrap_name) {
+ mach_server->task = mach_task_self();
+
+ if (mach_port_allocate(mach_server->task,
+ MACH_PORT_RIGHT_RECEIVE,
+ &mach_server->port ) != KERN_SUCCESS) {
+ return false;
+ }
+
+ if (mach_port_insert_right(mach_server->task,
+ mach_server->port,
+ mach_server->port,
+ MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) {
+ return false;
+ }
+
+ if (task_get_special_port(mach_server->task,
+ TASK_BOOTSTRAP_PORT,
+ &mach_server->bs_port) != KERN_SUCCESS) {
+ return false;
+ }
+
+ if (bootstrap_register(mach_server->bs_port,
+ bootstrap_name,
+ mach_server->port ) != KERN_SUCCESS) {
+ return false;
+ }
+
+ mach_server->handler = handler;
+ mach_server->is_running = true;
+ struct mach_buffer buffer;
+ while (mach_server->is_running) {
+ mach_receive_message(mach_server->port, &buffer, false);
+ mach_server->handler((env)buffer.message.descriptor.address);
+ mach_msg_destroy(&buffer.message.header);
+ }
+
+ return true;
+}
+#pragma clang diagnostic pop
+
+static inline char* sketchybar(char* message) {
+ uint32_t message_length = strlen(message) + 1;
+ char formatted_message[message_length + 1];
+
+ char quote = '\0';
+ uint32_t caret = 0;
+ for (int i = 0; i < message_length; ++i) {
+ if (message[i] == '"' || message[i] == '\'') {
+ if (quote == message[i]) quote = '\0';
+ else quote = message[i];
+ continue;
+ }
+ formatted_message[caret] = message[i];
+ if (message[i] == ' ' && !quote) formatted_message[caret] = '\0';
+ caret++;
+ }
+
+ if (caret > 0 && formatted_message[caret] == '\0'
+ && formatted_message[caret - 1] == '\0') {
+ caret--;
+ }
+
+ formatted_message[caret] = '\0';
+ if (!g_mach_port) g_mach_port = mach_get_bs_port();
+ char* response = mach_send_message(g_mach_port,
+ formatted_message,
+ caret + 1 );
+
+ if (response) return response;
+ else return (char*)"";
+}
+
+static inline void event_server_begin(mach_handler event_handler, char* bootstrap_name) {
+ mach_server_begin(&g_mach_server, event_handler, bootstrap_name);
+}