Initial commit
This commit is contained in:
153
modules/battery.c
Normal file
153
modules/battery.c
Normal file
@ -0,0 +1,153 @@
|
||||
#include "battery.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ADAPTER_BASE_PATH "/sys/class/power_supply/"
|
||||
#define BATTERY_PATH "/sys/class/power_supply/BAT0"
|
||||
|
||||
static const char *adapter_search_names[] = {"AC0", "ADP1"};
|
||||
static size_t adapter_search_names_count =
|
||||
sizeof(adapter_search_names) / sizeof(char *);
|
||||
static char *adapter_status_path;
|
||||
static int max_batery_charge;
|
||||
static int show_notifiaction = TRUE;
|
||||
|
||||
static void find_max_battery_charge() {
|
||||
FILE *max_file = fopen(BATTERY_PATH "/charge_full", "r");
|
||||
fseeko(max_file, 0, SEEK_END);
|
||||
off_t len = ftello(max_file);
|
||||
rewind(max_file);
|
||||
char text[len + 1];
|
||||
text[len] = '\0';
|
||||
fread(text, 1, len, max_file);
|
||||
max_batery_charge = strtoul(text, NULL, 10);
|
||||
fclose(max_file);
|
||||
}
|
||||
|
||||
static int is_battery_full() {
|
||||
FILE *status_file = fopen(BATTERY_PATH "/status", "r");
|
||||
if (!status_file) {
|
||||
return FALSE;
|
||||
}
|
||||
fseeko(status_file, 0, SEEK_END);
|
||||
off_t len = ftello(status_file);
|
||||
rewind(status_file);
|
||||
char status_text[len + 1];
|
||||
status_text[len] = '\0';
|
||||
fread(status_text, 1, len, status_file);
|
||||
fclose(status_file);
|
||||
return strcmp(status_text, "Full\n") == 0;
|
||||
}
|
||||
|
||||
static int get_battery_percent() {
|
||||
if (is_battery_full()) {
|
||||
return 100;
|
||||
}
|
||||
FILE *battery_file = fopen(BATTERY_PATH "/charge_now", "r");
|
||||
if (!battery_file) {
|
||||
return -1;
|
||||
}
|
||||
fseeko(battery_file, 0, SEEK_END);
|
||||
off_t len = ftello(battery_file);
|
||||
rewind(battery_file);
|
||||
char charge_text[len + 1];
|
||||
charge_text[len] = '\0';
|
||||
fread(charge_text, 1, len, battery_file);
|
||||
fclose(battery_file);
|
||||
long charge = strtoul(charge_text, NULL, 10);
|
||||
float scale = (float)charge / (float)max_batery_charge;
|
||||
return round(scale * 100.0f);
|
||||
}
|
||||
|
||||
static int is_adapter_connected() {
|
||||
FILE *adapter_file = fopen(adapter_status_path, "r");
|
||||
if (!adapter_file) {
|
||||
return -1;
|
||||
}
|
||||
char text[2] = {'\0', '\0'};
|
||||
fread(text, 1, 1, adapter_file);
|
||||
fclose(adapter_file);
|
||||
return text[0] == '1'; /* 1 means connected, anything else is not */
|
||||
}
|
||||
|
||||
static void find_adapter_status_path() {
|
||||
size_t i;
|
||||
for (i = 0; i < adapter_search_names_count; ++i) {
|
||||
size_t name_len = strlen(adapter_search_names[i]);
|
||||
/* -1 is to compensate for '\0' at end of "/online" */
|
||||
char *name = qtb_malloc(sizeof(ADAPTER_BASE_PATH) + name_len + sizeof("/online") - 1);
|
||||
sprintf(name, "%s%s/online", ADAPTER_BASE_PATH, adapter_search_names[i]);
|
||||
FILE *file = fopen(name, "r");
|
||||
if (file) {
|
||||
adapter_status_path = name;
|
||||
} else {
|
||||
qtb_free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void battery_module_init(void) {
|
||||
find_max_battery_charge();
|
||||
find_adapter_status_path();
|
||||
}
|
||||
|
||||
static const char *get_battery_icon(int percent, int adapter) {
|
||||
if (adapter) {
|
||||
return "";
|
||||
} else if (percent <= 10) {
|
||||
return "";
|
||||
} else if (percent <= 20) {
|
||||
return "";
|
||||
} else if (percent <= 30) {
|
||||
return "";
|
||||
} else if (percent <= 40) {
|
||||
return "";
|
||||
} else if (percent <= 50) {
|
||||
return "";
|
||||
} else if (percent <= 60) {
|
||||
return "";
|
||||
} else if (percent <= 70) {
|
||||
return "";
|
||||
} else if (percent <= 90) {
|
||||
return "";
|
||||
} else if (percent < 100) {
|
||||
return "";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static void warn_low_battery() {
|
||||
#ifdef HAS_X11
|
||||
if (qtb_get_x_display()) { /* if x is running */
|
||||
system("notify-send -t 0 'Battery is less than 10%!'");
|
||||
} else {
|
||||
#endif
|
||||
system("wall -t 0 'Battery is less than 10%!'");
|
||||
#ifdef HAS_X11
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
char *battery_module_poll() {
|
||||
char *output = qtb_calloc(16, 1);
|
||||
int percent = get_battery_percent();
|
||||
int adapter = is_adapter_connected();
|
||||
if (percent == -1 || adapter == -1) {
|
||||
sprintf(output, "?N/A%%");
|
||||
} else {
|
||||
const char *icon = get_battery_icon(percent, adapter);
|
||||
sprintf(output, "%s%3d%%", icon, percent);
|
||||
if (show_notifiaction && percent <= 10) {
|
||||
warn_low_battery();
|
||||
show_notifiaction = FALSE;
|
||||
} else if (percent > 10) {
|
||||
show_notifiaction = TRUE;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
2
modules/battery.h
Normal file
2
modules/battery.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern void battery_module_init(void);
|
||||
extern char *battery_module_poll(void);
|
118
modules/bluetooth.c
Normal file
118
modules/bluetooth.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include "bluetooth.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
static long long powered_devices = 0;
|
||||
|
||||
static GPtrArray *get_bluetooth_device_paths() {
|
||||
DIR *dir = opendir("/sys/class/bluetooth");
|
||||
if (!dir) {
|
||||
return NULL;
|
||||
}
|
||||
GPtrArray *arr = g_ptr_array_new();
|
||||
struct dirent *current;
|
||||
while ((current = readdir(dir))) {
|
||||
if (strcmp(current->d_name, ".") != 0 &&
|
||||
strcmp(current->d_name, "..") != 0) {
|
||||
char *path = g_strdup_printf("/org/bluez/%s", current->d_name);
|
||||
g_ptr_array_add(arr, path);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return arr;
|
||||
}
|
||||
|
||||
static void load_initial_device_states(GDBusConnection *dbus,
|
||||
GPtrArray *devices) {
|
||||
gsize i;
|
||||
for (i = 0; i < devices->len; ++i) {
|
||||
const char *path = g_ptr_array_index(devices, i);
|
||||
GError *err = NULL;
|
||||
GVariant *response = g_dbus_connection_call_sync(
|
||||
dbus, "org.bluez", path, "org.freedesktop.DBus.Properties", "Get",
|
||||
g_variant_new_parsed("('org.bluez.Adapter1', 'Powered')"),
|
||||
(GVariantType *)"(v)", G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
|
||||
if (response) {
|
||||
GVariant *wrapper = g_variant_get_child_value(response, 0);
|
||||
GVariant *value = g_variant_get_child_value(wrapper, 0);
|
||||
gboolean powered = g_variant_get_boolean(value);
|
||||
if (powered) {
|
||||
++powered_devices;
|
||||
} /* sice powered_devices is already 0, we dont have to increment it
|
||||
if the device is not powered */
|
||||
g_variant_unref(value);
|
||||
g_variant_unref(wrapper);
|
||||
g_variant_unref(response);
|
||||
}
|
||||
}
|
||||
qtb_signal_modules(4);
|
||||
}
|
||||
|
||||
static void device_changed_callback(GDBusConnection *dbus,
|
||||
const char *sender_name,
|
||||
const char *object_path,
|
||||
const char *interface_name,
|
||||
const char *signal_name, GVariant *params,
|
||||
gpointer user_data) {
|
||||
GVariant *changed = g_variant_get_child_value(params, 1);
|
||||
GVariant *value_wrapper = g_variant_lookup_value(changed, "Powered", G_VARIANT_TYPE_BOOLEAN);
|
||||
if (value_wrapper) {
|
||||
gboolean powered = g_variant_get_boolean(value_wrapper);
|
||||
if (powered) {
|
||||
++powered_devices;
|
||||
} else {
|
||||
--powered_devices;
|
||||
}
|
||||
g_variant_unref(value_wrapper);
|
||||
}
|
||||
g_variant_unref(changed);
|
||||
qtb_signal_modules(4);
|
||||
}
|
||||
|
||||
static void subscribe_to_events(GDBusConnection *dbus, GPtrArray *devices) {
|
||||
gsize i;
|
||||
for (i = 0; i < devices->len; ++i) {
|
||||
const char *path = g_ptr_array_index(devices, i);
|
||||
g_dbus_connection_signal_subscribe(
|
||||
dbus, NULL, "org.freedesktop.DBus.Properties", "PropertiesChanged",
|
||||
path, "org.bluez.Adapter1", G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
&device_changed_callback, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void *thread_action() {
|
||||
GMainContext *context = g_main_context_new();
|
||||
g_main_context_push_thread_default(context);
|
||||
GError *err = NULL;
|
||||
GDBusConnection *dbus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
|
||||
if (err) {
|
||||
qtb_log("could not connect to bluez on the system bus: %s",
|
||||
err->message);
|
||||
qtb_die();
|
||||
}
|
||||
GPtrArray *devices = get_bluetooth_device_paths();
|
||||
load_initial_device_states(dbus, devices);
|
||||
subscribe_to_events(dbus, devices);
|
||||
gsize i;
|
||||
for (i = 0; i < devices->len; ++i) {
|
||||
g_free(g_ptr_array_index(devices, i));
|
||||
}
|
||||
g_ptr_array_free(devices, TRUE);
|
||||
GMainLoop *main_loop = g_main_loop_new(context, FALSE);
|
||||
g_main_loop_run(main_loop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bluetooth_module_init() {
|
||||
g_thread_new("bluetooth-module", &thread_action, NULL);
|
||||
}
|
||||
|
||||
char *bluetooth_module_poll() {
|
||||
char *output = NULL;
|
||||
if (powered_devices != 0) {
|
||||
output = qtb_strdup(" ");
|
||||
}
|
||||
return output;
|
||||
}
|
2
modules/bluetooth.h
Normal file
2
modules/bluetooth.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern void bluetooth_module_init(void);
|
||||
extern char *bluetooth_module_poll(void);
|
89
modules/fcitx4.c
Normal file
89
modules/fcitx4.c
Normal file
@ -0,0 +1,89 @@
|
||||
#include "fcitx4.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
struct input_method {
|
||||
const char *name;
|
||||
const char *symbol;
|
||||
};
|
||||
const struct input_method input_methods[] = {
|
||||
{"fcitx-keyboard-us", "E"},
|
||||
{"kkc", "和"},
|
||||
{"mozc", "和"}
|
||||
};
|
||||
static const size_t im_count = sizeof(input_methods) / sizeof(struct input_method);
|
||||
static const struct input_method *current_im = NULL;
|
||||
|
||||
static const struct input_method *find_im(const char *name) {
|
||||
size_t i;
|
||||
for (i = 0; i < im_count; ++i) {
|
||||
if (strcmp(name, input_methods[i].name) == 0) {
|
||||
return &input_methods[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_current_im(GDBusConnection *dbus) {
|
||||
current_im = NULL;
|
||||
GVariant *tuple = g_dbus_connection_call_sync(
|
||||
dbus, "org.fcitx.Fcitx", "/inputmethod", "org.fcitx.Fcitx.InputMethod",
|
||||
"GetCurrentIM", NULL, G_VARIANT_TYPE_TUPLE, G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
NULL, NULL);
|
||||
if (tuple) {
|
||||
GVariant *response = g_variant_get_child_value(tuple, 0);
|
||||
size_t response_len;
|
||||
const char *response_im = g_variant_get_string(response, &response_len);
|
||||
current_im = find_im(response_im);
|
||||
g_variant_unref(response);
|
||||
g_variant_unref(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
static void im_changed_callback(GDBusConnection *dbus, const char *sender_name,
|
||||
const char *object_path, const char *interface_name,
|
||||
const char *signal_name, GVariant *params,
|
||||
gpointer user_data) {
|
||||
set_current_im(dbus);
|
||||
qtb_signal_modules(3);
|
||||
}
|
||||
|
||||
static void *thread_action(gpointer user_data) {
|
||||
GMainContext *context = g_main_context_new();
|
||||
g_main_context_push_thread_default(context);
|
||||
GError *err = NULL;
|
||||
GDBusConnection *dbus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
|
||||
if (err) {
|
||||
qtb_log("could not connect to fcitx on dbus: %s", err->message);
|
||||
qtb_die();
|
||||
}
|
||||
set_current_im(dbus);
|
||||
qtb_signal_modules(3);
|
||||
g_dbus_connection_signal_subscribe(
|
||||
dbus, NULL, "org.freedesktop.DBus.Properties", "PropertiesChanged",
|
||||
"/inputmethod", "org.fcitx.Fcitx.InputMethod", G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
&im_changed_callback, NULL, NULL);
|
||||
GMainLoop *main_loop = g_main_loop_new(context, FALSE);
|
||||
g_main_loop_run(main_loop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fcitx4_module_init() {
|
||||
g_thread_new("fcitx-module", &thread_action, NULL);
|
||||
}
|
||||
|
||||
char *fcitx4_module_poll() {
|
||||
const char *symbol;
|
||||
if (current_im) {
|
||||
symbol = current_im->symbol;
|
||||
} else {
|
||||
symbol = "?";
|
||||
}
|
||||
size_t sym_len = strlen(symbol);
|
||||
char *output = qtb_malloc(sizeof(" ") + sym_len);
|
||||
sprintf(output, " %s", symbol);
|
||||
return output;
|
||||
}
|
2
modules/fcitx4.h
Normal file
2
modules/fcitx4.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern void fcitx4_module_init(void);
|
||||
extern char *fcitx4_module_poll(void);
|
96
modules/linuxnm.c
Normal file
96
modules/linuxnm.c
Normal file
@ -0,0 +1,96 @@
|
||||
#include "linuxnm.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <NetworkManager.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TYPE_NO_MANAGER 0x1
|
||||
#define TYPE_WIRED 0x2
|
||||
#define TYPE_WIRELESS 0x4
|
||||
#define TYPE_VPN 0x8
|
||||
|
||||
typedef int connection_type;
|
||||
|
||||
static connection_type active_types;
|
||||
|
||||
static int is_connection_vpn(NMConnection *connection) {
|
||||
if (nm_connection_get_setting_vpn(connection)) {
|
||||
return TRUE;
|
||||
}
|
||||
const char *type = nm_connection_get_connection_type(connection);
|
||||
return strcmp(type, "wireguard") == 0;
|
||||
}
|
||||
|
||||
static void update_connections(NMClient *client) {
|
||||
const GPtrArray *active_connections =
|
||||
nm_client_get_active_connections(client);
|
||||
guint i;
|
||||
for (i = 0; i < active_connections->len; ++i) {
|
||||
NMActiveConnection *current_active =
|
||||
g_ptr_array_index(active_connections, i);
|
||||
NMConnection *current =
|
||||
NM_CONNECTION(nm_active_connection_get_connection(current_active));
|
||||
const char *type = nm_connection_get_connection_type(current);
|
||||
if (is_connection_vpn(current)) {
|
||||
active_types |= TYPE_VPN;
|
||||
} else if (nm_connection_get_setting_wired(current)) {
|
||||
active_types |= TYPE_WIRED;
|
||||
} else if (nm_connection_get_setting_wireless(current)) {
|
||||
active_types |= TYPE_WIRELESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void connections_changed(NMClient *client, GParamSpec *pspec,
|
||||
gpointer user_data) {
|
||||
active_types = 0;
|
||||
if (!nm_client_get_nm_running(client)) {
|
||||
active_types = TYPE_NO_MANAGER;
|
||||
} else {
|
||||
update_connections(client);
|
||||
}
|
||||
qtb_signal_modules(2);
|
||||
}
|
||||
|
||||
static void *thread_action(gpointer user_data) {
|
||||
GMainContext *context = g_main_context_new();
|
||||
g_main_context_push_thread_default(context);
|
||||
GError *err = NULL;
|
||||
NMClient *client = nm_client_new(NULL, &err);
|
||||
if (err) {
|
||||
return err->message;
|
||||
}
|
||||
g_signal_connect(client, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
|
||||
G_CALLBACK(connections_changed), NULL);
|
||||
g_signal_connect(client, "notify::" NM_CLIENT_NM_RUNNING,
|
||||
G_CALLBACK(connections_changed), NULL);
|
||||
connections_changed(client, NULL, NULL);
|
||||
GMainLoop *main_loop = g_main_loop_new(context, FALSE);
|
||||
g_main_loop_run(main_loop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void linuxnm_module_init() {
|
||||
g_thread_new("network-module", &thread_action, NULL);
|
||||
}
|
||||
|
||||
char *linuxnm_module_poll() {
|
||||
char *output = qtb_calloc(8, 1);
|
||||
if ((active_types & TYPE_NO_MANAGER) == TYPE_NO_MANAGER) {
|
||||
strcat(output, "ﳤ");
|
||||
}
|
||||
if ((active_types & TYPE_VPN) == TYPE_VPN) {
|
||||
strcat(output, "嬨");
|
||||
}
|
||||
if ((active_types & TYPE_WIRED) == TYPE_WIRED) {
|
||||
strcat(output, "");
|
||||
}
|
||||
if ((active_types & TYPE_WIRELESS) == TYPE_WIRELESS) {
|
||||
strcat(output, "直");
|
||||
}
|
||||
if (active_types == 0) { /* no valid connections found */
|
||||
strcat(output, "");
|
||||
}
|
||||
return output;
|
||||
}
|
2
modules/linuxnm.h
Normal file
2
modules/linuxnm.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern void linuxnm_module_init(void);
|
||||
extern char *linuxnm_module_poll(void);
|
44
modules/optimus.c
Normal file
44
modules/optimus.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include "optimus.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char *card_string;
|
||||
|
||||
void optimus_module_init() {
|
||||
int status = system("card_status=\"`optimus-manager --status 2>/dev/null | "
|
||||
"grep -Po '(?<=Current GPU mode : )[a-z]'`\"\n"
|
||||
"case \"$card_status\" in\n"
|
||||
" 'i')\n"
|
||||
" exit 1\n"
|
||||
" ;;\n"
|
||||
" 'h')\n"
|
||||
" exit 2\n"
|
||||
" ;;\n"
|
||||
" 'n')\n"
|
||||
" exit 3\n"
|
||||
" ;;\n"
|
||||
" *)\n"
|
||||
" exit 4\n"
|
||||
" ;;\n"
|
||||
"esac\n");
|
||||
switch (WEXITSTATUS(status)) {
|
||||
case 1:
|
||||
card_string = " I";
|
||||
break;
|
||||
case 2:
|
||||
card_string = " H";
|
||||
break;
|
||||
case 3:
|
||||
card_string = " N";
|
||||
break;
|
||||
/* case 4: */
|
||||
default:
|
||||
card_string = " ?";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *optimus_module_poll() {
|
||||
return qtb_strdup(card_string);
|
||||
}
|
2
modules/optimus.h
Normal file
2
modules/optimus.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern void optimus_module_init(void);
|
||||
extern char *optimus_module_poll(void);
|
63
modules/oss.c
Normal file
63
modules/oss.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "oss.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
int pcm;
|
||||
int vol;
|
||||
int mute;
|
||||
} mixer_data;
|
||||
|
||||
static mixer_data main_mixer;
|
||||
|
||||
#define ioctl_checked(fd, request, arg) _ioctl_checked(fd, request, #request, arg)
|
||||
static void _ioctl_checked(int fd, unsigned long request, const char *rq_name, void *arg) {
|
||||
if (ioctl(fd, request, arg) < 0) {
|
||||
qtb_log("ioctl request %s failed", rq_name);
|
||||
qtb_die();
|
||||
}
|
||||
}
|
||||
|
||||
static void open_mixer(const char *path, mixer_data *mixer) {
|
||||
mixer->fd = open(path, O_RDONLY);
|
||||
if (mixer->fd < 0) {
|
||||
qtb_log("could not open mixer '%s'", path);
|
||||
qtb_die();
|
||||
}
|
||||
}
|
||||
|
||||
static void read_mixer(mixer_data *mixer) {
|
||||
ioctl_checked(mixer->fd, SOUND_MIXER_READ_PCM, &mixer->pcm);
|
||||
mixer->pcm >>= 8;
|
||||
ioctl_checked(mixer->fd, SOUND_MIXER_READ_VOLUME, &mixer->vol);
|
||||
mixer->vol >>= 8;
|
||||
mixer->mute = !(mixer->vol * mixer->pcm);
|
||||
}
|
||||
|
||||
void oss_module_init() {
|
||||
open_mixer("/dev/mixer", &main_mixer);
|
||||
}
|
||||
|
||||
static const char *get_volume_icon(int volume, int mute) {
|
||||
if (mute) {
|
||||
return "ﱝ";
|
||||
} else if (volume > 50) {
|
||||
return "墳";
|
||||
} else if (volume > 0) {
|
||||
return "奔";
|
||||
}
|
||||
return "奄";
|
||||
}
|
||||
|
||||
char *oss_module_poll() {
|
||||
read_mixer(&main_mixer);
|
||||
const char *icon = get_volume_icon(main_mixer.vol, main_mixer.mute);
|
||||
char *buff = qtb_malloc(32);
|
||||
sprintf(buff, "%s%3d%%",icon, main_mixer.vol);
|
||||
return buff;
|
||||
}
|
2
modules/oss.h
Normal file
2
modules/oss.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern void oss_module_init(void);
|
||||
extern char *oss_module_poll(void);
|
132
modules/pulse.c
Normal file
132
modules/pulse.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include "pulse.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CONTEXT_NAME "quick-text-bar-audio"
|
||||
|
||||
#define CONTEXT_CONNECTING 0
|
||||
#define CONTEXT_CONNECTED 1
|
||||
#define CONTEXT_FAILED 2
|
||||
|
||||
static pa_threaded_mainloop *mainloop;
|
||||
static pa_mainloop_api *mainloop_api;
|
||||
static pa_context *context;
|
||||
static int volume;
|
||||
static int mute;
|
||||
|
||||
static void sink_info_callback(pa_context *ctx, const pa_sink_info *info,
|
||||
int eol, void *user_data) {
|
||||
if (info) {
|
||||
pa_volume_t arg = pa_cvolume_avg(&info->volume);
|
||||
float float_volume = ((float)arg / (float)PA_VOLUME_NORM) * 100.0f;
|
||||
int new_volume = round(float_volume);
|
||||
if (mute != info->mute || volume != new_volume) {
|
||||
mute = info->mute;
|
||||
volume = new_volume;
|
||||
qtb_signal_modules(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void server_info_callback(pa_context *ctx, const pa_server_info *info,
|
||||
void *user_data) {
|
||||
pa_operation *op = pa_context_get_sink_info_by_name(
|
||||
ctx, info->default_sink_name, &sink_info_callback, NULL);
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
|
||||
static void subscribe_callback(pa_context *ctx,
|
||||
pa_subscription_event_type_t type, uint32_t idx,
|
||||
void *user_data) {
|
||||
unsigned int facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
|
||||
pa_operation *op = NULL;
|
||||
switch (facility) {
|
||||
case PA_SUBSCRIPTION_EVENT_SINK:
|
||||
op = pa_context_get_sink_info_by_index(ctx, idx, &sink_info_callback,
|
||||
NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (op) {
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
}
|
||||
|
||||
static void state_callback(pa_context *ctx, void *user_data) {
|
||||
pa_operation *op;
|
||||
switch (pa_context_get_state(ctx)) {
|
||||
case PA_CONTEXT_READY:
|
||||
op = pa_context_get_server_info(ctx, &server_info_callback, NULL);
|
||||
pa_operation_unref(op);
|
||||
pa_context_set_subscribe_callback(ctx, &subscribe_callback, NULL);
|
||||
op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
|
||||
pa_operation_unref(op);
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
volume = -1;
|
||||
qtb_signal_modules(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pulse_module_init() {
|
||||
mainloop = pa_threaded_mainloop_new();
|
||||
if (!mainloop) {
|
||||
qtb_log("could not create mainloop");
|
||||
qtb_die();
|
||||
}
|
||||
mainloop_api = pa_threaded_mainloop_get_api(mainloop);
|
||||
if (!mainloop_api) {
|
||||
qtb_log("could not get api");
|
||||
qtb_die();
|
||||
}
|
||||
context = pa_context_new(mainloop_api, CONTEXT_NAME);
|
||||
if (!context) {
|
||||
qtb_log("could not create context");
|
||||
qtb_die();
|
||||
}
|
||||
pa_context_set_state_callback(
|
||||
context, (pa_context_notify_cb_t)&state_callback, NULL);
|
||||
if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
|
||||
qtb_log("could not connect");
|
||||
qtb_die();
|
||||
}
|
||||
if (pa_threaded_mainloop_start(mainloop) < 0) {
|
||||
qtb_log("could not start mainloop");
|
||||
qtb_die();
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_volume_icon() {
|
||||
if (mute) {
|
||||
return "ﱝ";
|
||||
} else if (volume > 50) {
|
||||
return "墳";
|
||||
} else if (volume > 0) {
|
||||
return "奔";
|
||||
}
|
||||
return "奄";
|
||||
}
|
||||
|
||||
char *pulse_module_poll() {
|
||||
char *output = qtb_calloc(32, 1);
|
||||
if (volume < 0) { /* not connected */
|
||||
sprintf(output, "ﱝ ??%%");
|
||||
pa_threaded_mainloop_stop(
|
||||
mainloop); /* free the old mainloop and reset this module */
|
||||
pa_threaded_mainloop_free(mainloop);
|
||||
pulse_module_init();
|
||||
} else {
|
||||
const char *volume_icon = get_volume_icon();
|
||||
sprintf(output, "%s%3d%%", volume_icon, volume);
|
||||
}
|
||||
return output;
|
||||
}
|
3
modules/pulse.h
Normal file
3
modules/pulse.h
Normal file
@ -0,0 +1,3 @@
|
||||
/* an example module that produces the current system volume */
|
||||
extern void pulse_module_init(void);
|
||||
extern char *pulse_module_poll(void);
|
21
modules/time.c
Normal file
21
modules/time.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include "time.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TIME_STRING_SIZE 64
|
||||
#define TIME_FORMAT " %a %b %d %R"
|
||||
|
||||
char *time_module_poll() {
|
||||
time_t time_num = time(NULL);
|
||||
struct tm time_tm;
|
||||
localtime_r(&time_num, &time_tm);
|
||||
char *output = qtb_malloc(TIME_STRING_SIZE);
|
||||
int result = strftime(output, TIME_STRING_SIZE, TIME_FORMAT, &time_tm);
|
||||
if (result == 0) {
|
||||
strcpy(output, " ?? ?? ?? ??:??");
|
||||
}
|
||||
return output;
|
||||
}
|
3
modules/time.h
Normal file
3
modules/time.h
Normal file
@ -0,0 +1,3 @@
|
||||
/* an example module that produces the current time */
|
||||
|
||||
extern char *time_module_poll(void);
|
Reference in New Issue
Block a user