diff --git a/Makefile b/Makefile index 20e9f27..66447c7 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,11 @@ SED = sed GREP = grep CUT = cut -VERSION != $(GREP) VERSION main.h | $(CUT) -d \" -f2 -PROGNAME != $(GREP) PROGNAME main.h | $(CUT) -d \" -f2 -PROGUPPER != $(GREP) PROGUPPER main.h | $(CUT) -d \" -f2 +MAIN_HEADER := include/main.h + +VERSION != $(GREP) VERSION $(MAIN_HEADER) | $(CUT) -d \" -f2 +PROGNAME != $(GREP) PROGNAME $(MAIN_HEADER) | $(CUT) -d \" -f2 +PROGUPPER != $(GREP) PROGUPPER $(MAIN_HEADER) | $(CUT) -d \" -f2 PREFIX = /usr/local @@ -25,6 +27,7 @@ MANPREFIX.=/usr/share/man MANPREFIX=$(MANPREFIX.$(PREFIX)) INCLUDES != pkg-config --cflags libnotify +INCLUDES := $(INCLUDES) -I./include/ CFLAGS_EXTRA = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Os CFLAGS := $(CFLAGS_EXTRA) $(INCLUDES) $(CFLAGS) @@ -33,9 +36,9 @@ LIBS := $(LIBS) -lm LDFLAGS_EXTRA = -s LDFLAGS := $(LDFLAGS_EXTRA) $(LDFLAGS) -SRC = main.c options.c battery.c notify.c +SRC = $(wildcard src/*.c) OBJ = $(SRC:.c=.o) -HDR = $(SRC:.c=.h) +HDR = include/*.h .PHONY: all install install-service clean test compile-test @@ -46,7 +49,7 @@ $(TARGET): $(OBJ) %.o: $(HDR) -$(TARGET).1: $(TARGET).1.in main.h +$(TARGET).1: $(TARGET).1.in $(MAIN_HEADER) $(SED) "s/VERSION/$(VERSION)/g" < $(TARGET).1.in | $(SED) "s/PROGNAME/$(PROGNAME)/g" | $(SED) "s/PROGUPPER/$(PROGUPPER)/g" > $@ install: all diff --git a/README.md b/README.md index e69030f..7559a16 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,14 @@ Authors batsignal is written by Corey Hinshaw. It was originally forked from juiced by Aaron Marcher. +Development Notes +----------------- + +For supporting language-server freatures, the `compile_commands.json` file is necessary (at least for the clangd-lsp). +This can be generated with [Bear](https://github.com/rizsotto/Bear): + + $ bear -- make + License and Copyright --------------------- Copyright (c) 2018-2024 Corey Hinshaw diff --git a/battery.c b/battery.c deleted file mode 100644 index 170e282..0000000 --- a/battery.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2018-2024 Corey Hinshaw - */ - -#define _DEFAULT_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include "battery.h" - -static char *attr_path = NULL; - -static void set_attributes(char *battery_name, char **now_attribute, char **full_attribute) -{ - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/charge_now", battery_name); - if (access(attr_path, F_OK) == 0) { - *now_attribute = "charge_now"; - *full_attribute = "charge_full"; - } else { - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/energy_now", battery_name); - if (access(attr_path, F_OK) == 0) { - *now_attribute = "energy_now"; - *full_attribute = "energy_full"; - } else { - *now_attribute = "capacity"; - *full_attribute = NULL; - } - } -} - -static bool is_type_battery(char *name) -{ - FILE *file; - char type[11] = ""; - - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/type", name); - file = fopen(attr_path, "r"); - if (file != NULL) { - if (fscanf(file, "%10s", type) == 0) { /* Continue... */ } - fclose(file); - } - return strcmp(type, "Battery") == 0; -} - -static bool has_capacity_field(char *name) -{ - FILE *file; - int capacity = -1; - char *now_attribute; - char *full_attribute; - - set_attributes(name, &now_attribute, &full_attribute); - - if (strcmp(now_attribute, "capacity") == 0) { - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/capacity", name); - file = fopen(attr_path, "r"); - if (file != NULL) { - if (fscanf(file, "%d", &capacity) == 0) { /* Continue... */ } - fclose(file); - } - } else { - capacity = 1; - } - return capacity >= 0; -} - -static bool is_battery(char *name) -{ - return is_type_battery(name) && has_capacity_field(name); -} - -int find_batteries(char ***battery_names) -{ - unsigned int path_len = strlen(POWER_SUPPLY_SUBSYSTEM) + POWER_SUPPLY_ATTR_LENGTH; - unsigned int entry_name_len = 5; - int battery_count = 0; - DIR *dir; - struct dirent *entry; - - attr_path = realloc(attr_path, path_len + entry_name_len); - - dir = opendir(POWER_SUPPLY_SUBSYSTEM); - if (dir) { - while ((entry = readdir(dir)) != NULL) { - if (strlen(entry->d_name) > entry_name_len) { - entry_name_len = strlen(entry->d_name); - attr_path = realloc(attr_path, path_len + entry_name_len); - if (attr_path == NULL) - err(EXIT_FAILURE, "Memory allocation failed"); - } - - if (is_battery(entry->d_name)) { - *battery_names = realloc(*battery_names, sizeof(char *) * (battery_count+1)); - if (*battery_names == NULL) - err(EXIT_FAILURE, "Memory allocation failed"); - (*battery_names)[battery_count] = strdup(entry->d_name); - if ((*battery_names)[battery_count] == NULL) - err(EXIT_FAILURE, "Memory allocation failed"); - battery_count++; - } - } - closedir(dir); - } - - return battery_count; -} - -int validate_batteries(char **battery_names, int battery_count) -{ - unsigned int path_len = strlen(POWER_SUPPLY_SUBSYSTEM) + POWER_SUPPLY_ATTR_LENGTH; - unsigned int name_len = 5; - int return_value = -1; - - attr_path = realloc(attr_path, path_len + name_len); - - for (int i = 0; i < battery_count; i++) { - if (strlen(battery_names[i]) > name_len) { - name_len = strlen(battery_names[i]); - attr_path = realloc(attr_path, path_len + name_len); - if (attr_path == NULL) - err(EXIT_FAILURE, "Memory allocation failed"); - } - if (!is_battery(battery_names[i]) && return_value < 0) { - return_value = i; - } - } - return return_value; -} - -void update_battery_state(BatteryState *battery, bool required) -{ - char state[15]; - char *now_attribute; - char *full_attribute; - unsigned int tmp_now; - unsigned int tmp_full; - FILE *file; - - battery->discharging = false; - battery->full = true; - battery->energy_now = 0; - battery->energy_full = 0; - set_attributes(battery->names[0], &now_attribute, &full_attribute); - - /* iterate through all batteries */ - for (int i = 0; i < battery->count; i++) { - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/status", battery->names[i]); - file = fopen(attr_path, "r"); - if (file == NULL || fscanf(file, "%12s", state) == 0) { - if (required) - err(EXIT_FAILURE, "Could not read %s", attr_path); - battery->discharging |= 0; - if (file) - fclose(file); - continue; - } - fclose(file); - - battery->discharging |= strcmp(state, POWER_SUPPLY_DISCHARGING) == 0; - battery->full &= strcmp(state, POWER_SUPPLY_FULL) == 0; - - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/%s", battery->names[i], now_attribute); - file = fopen(attr_path, "r"); - if (file == NULL || fscanf(file, "%u", &tmp_now) == 0) { - if (required) - err(EXIT_FAILURE, "Could not read %s", attr_path); - if (file) - fclose(file); - continue; - } - fclose(file); - - if (full_attribute != NULL) { - sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/%s", battery->names[i], full_attribute); - file = fopen(attr_path, "r"); - if (file == NULL || fscanf(file, "%u", &tmp_full) == 0) { - if (required) - err(EXIT_FAILURE, "Could not read %s", attr_path); - if (file) - fclose(file); - continue; - } - fclose(file); - } else { - tmp_full = 100; - } - - battery->energy_now += tmp_now; - battery->energy_full += tmp_full; - } - - battery->level = round(100.0 * battery->energy_now / battery->energy_full); -} diff --git a/battery.h b/include/battery.h similarity index 64% rename from battery.h rename to include/battery.h index 6c2c12d..0e9fede 100644 --- a/battery.h +++ b/include/battery.h @@ -5,7 +5,10 @@ #ifndef BATTERY_H #define BATTERY_H +#include +#include #include +#include /* battery states */ #define STATE_AC 0 @@ -34,10 +37,18 @@ typedef struct BatteryState { int level; int energy_full; int energy_now; + int inotify_fd; + int *watch_fds; + pthread_cond_t *bat_state_change; + pthread_mutex_t *state_change_mut; + pthread_t *thread_ids; + atomic_bool *watching; } BatteryState; +BatteryState* init_batteries(char **battery_names, int battery_count); +void uninit_batteries(BatteryState * battery); int find_batteries(char ***battery_names); int validate_batteries(char **battery_names, int battery_count); -void update_battery_state(BatteryState *battery, bool required); +void wait_for_update_battery_state(BatteryState *battery, bool required, struct timespec timeout); #endif diff --git a/main.h b/include/main.h similarity index 100% rename from main.h rename to include/main.h diff --git a/notify.h b/include/notify.h similarity index 100% rename from notify.h rename to include/notify.h diff --git a/options.h b/include/options.h similarity index 100% rename from options.h rename to include/options.h diff --git a/src/battery.c b/src/battery.c new file mode 100644 index 0000000..deed947 --- /dev/null +++ b/src/battery.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2018-2024 Corey Hinshaw + */ + +#include "battery.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INOTIFY_BUF_SIZE 4096 + +static char *attr_path = NULL; + +static void set_attributes(char *battery_name, char **now_attribute, + char **full_attribute) { + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/charge_now", battery_name); + if (access(attr_path, F_OK) == 0) { + *now_attribute = "charge_now"; + *full_attribute = "charge_full"; + } else { + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/energy_now", battery_name); + if (access(attr_path, F_OK) == 0) { + *now_attribute = "energy_now"; + *full_attribute = "energy_full"; + } else { + *now_attribute = "capacity"; + *full_attribute = NULL; + } + } +} + +static bool is_type_battery(char *name) { + FILE *file; + char type[11] = ""; + + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/type", name); + file = fopen(attr_path, "r"); + if (file != NULL) { + if (fscanf(file, "%10s", type) == 0) { /* Continue... */ + } + fclose(file); + } + return strcmp(type, "Battery") == 0; +} + +static bool has_capacity_field(char *name) { + FILE *file; + int capacity = -1; + char *now_attribute; + char *full_attribute; + + set_attributes(name, &now_attribute, &full_attribute); + + if (strcmp(now_attribute, "capacity") == 0) { + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/capacity", name); + file = fopen(attr_path, "r"); + if (file != NULL) { + if (fscanf(file, "%d", &capacity) == 0) { /* Continue... */ + } + fclose(file); + } + } else { + capacity = 1; + } + return capacity >= 0; +} + +static bool is_battery(char *name) { + return is_type_battery(name) && has_capacity_field(name); +} + +int find_batteries(char ***battery_names) { + unsigned int path_len = + strlen(POWER_SUPPLY_SUBSYSTEM) + POWER_SUPPLY_ATTR_LENGTH; + unsigned int entry_name_len = 5; + int battery_count = 0; + DIR *dir; + struct dirent *entry; + + attr_path = realloc(attr_path, path_len + entry_name_len); + + dir = opendir(POWER_SUPPLY_SUBSYSTEM); + if (dir) { + while ((entry = readdir(dir)) != NULL) { + if (strlen(entry->d_name) > entry_name_len) { + entry_name_len = strlen(entry->d_name); + attr_path = realloc(attr_path, path_len + entry_name_len); + if (attr_path == NULL) + err(EXIT_FAILURE, "Memory allocation failed"); + } + + if (is_battery(entry->d_name)) { + *battery_names = + realloc(*battery_names, sizeof(char *) * (battery_count + 1)); + if (*battery_names == NULL) + err(EXIT_FAILURE, "Memory allocation failed"); + (*battery_names)[battery_count] = strdup(entry->d_name); + if ((*battery_names)[battery_count] == NULL) + err(EXIT_FAILURE, "Memory allocation failed"); + battery_count++; + } + } + closedir(dir); + } + + return battery_count; +} + +struct BatteryStateWrapper { + BatteryState *battery; + int bat_id; +}; + +void *watch_for_file_changes(void *battery) { + struct BatteryStateWrapper *bat = battery; + char buf[INOTIFY_BUF_SIZE]; + while (bat->battery->watching) { + // blocks here, until the watched file changes or a signal is send to the + // thread + int len = read(bat->battery->inotify_fd, &buf, sizeof(buf)); + + // error while reading -> signal was send to stop or IO-Error + if (len == -1) { + perror("Unexpected Error in inotify thread"); + printf("Thread stopped\n"); + return NULL; + } + + // file changed, update request with conditional variable + pthread_cond_signal(bat->battery->bat_state_change); + } + printf("Thread stopped\n"); + return NULL; +} + +BatteryState *init_batteries(char **battery_names, int battery_count) { + BatteryState *battery; + battery = calloc(1, sizeof(*battery)); + battery->names = battery_names; + battery->count = battery_count; + battery->bat_state_change = calloc(1, sizeof(*battery->bat_state_change)); + battery->state_change_mut = calloc(1, sizeof(*battery->state_change_mut)); + if (battery->bat_state_change == NULL || battery->state_change_mut == NULL) { + perror("Error on initialising conditional var"); + return battery; + } + + // initialise conditional variable and mutex + // for battery charging state changes on all batteries + pthread_cond_init(battery->bat_state_change, NULL); + pthread_mutex_init(battery->state_change_mut, NULL); + battery->watching = calloc(1, sizeof(*battery->watching)); + if (battery->watching == NULL) { + perror("Error on initialising atomic variable for inotify"); + return battery; + } + *battery->watching = ATOMIC_VAR_INIT(true); + + // init inotify-fd for notification on battery charging state changes + battery->inotify_fd = inotify_init(); + if (battery->inotify_fd == -1) { + perror("Error on initialising inotify"); + return battery; + } + battery->watch_fds = calloc(battery_count, sizeof(int)); + if (battery->watch_fds == NULL) { + perror("Error while creating memory for inotify watch fds"); + return battery; + } + + battery->thread_ids = calloc(battery->count, sizeof(*battery->thread_ids)); + if (battery->thread_ids == NULL) { + perror("Error while creating memory for inotify thread infos"); + return battery; + } + + // add watch fds for file modifications for each battery charge state file + for (int i = 0; i < battery->count; i++) { + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/status", battery->names[i]); + battery->watch_fds[i] = + inotify_add_watch(battery->inotify_fd, attr_path, IN_MODIFY | IN_ACCESS); + if (battery->watch_fds[i] == -1) { + fprintf(stderr, "Cannot watch '%s': %s\n", attr_path, strerror(errno)); + continue; + } + + struct BatteryStateWrapper *b_state = + calloc(1, sizeof(struct BatteryStateWrapper)); + if (b_state == NULL) { + perror("Error while creating memory for battery-state wrapper"); + continue; + } + b_state->battery = battery; + b_state->bat_id = i; + + // start a thread polling the watch_fd + int ret = pthread_create(&battery->thread_ids[i], NULL, + &watch_for_file_changes, b_state); + if (ret != 0) { + printf("Couldn't start the inotify thread for %s\n", battery->names[i]); + } + } + + return battery; +} + +void uninit_batteries(BatteryState *battery) { + if (battery->inotify_fd != -1) { + // stopping threads + battery->watching = false; + if (battery->thread_ids != NULL) { + for (int i = 0; i < battery->count; i++) { + pthread_cancel(battery->thread_ids[i]); + pthread_join(battery->thread_ids[i], NULL); + } + } + pthread_cond_broadcast(battery->bat_state_change); + + // close watch fds + if (battery->watch_fds != NULL) { + for (int i = 0; i < battery->count; i++) { + if (battery->watch_fds[i] != -1) { + close(battery->watch_fds[i]); + } + } + // stop inotify + close(battery->inotify_fd); + } + } +} + +int validate_batteries(char **battery_names, int battery_count) { + unsigned int path_len = + strlen(POWER_SUPPLY_SUBSYSTEM) + POWER_SUPPLY_ATTR_LENGTH; + unsigned int name_len = 5; + int return_value = -1; + + attr_path = realloc(attr_path, path_len + name_len); + + for (int i = 0; i < battery_count; i++) { + if (strlen(battery_names[i]) > name_len) { + name_len = strlen(battery_names[i]); + attr_path = realloc(attr_path, path_len + name_len); + if (attr_path == NULL) + err(EXIT_FAILURE, "Memory allocation failed"); + } + if (!is_battery(battery_names[i]) && return_value < 0) { + return_value = i; + } + } + return return_value; +} + +void wait_for_update_battery_state(BatteryState *battery, bool required, + struct timespec timeout) { + char state[15]; + char *now_attribute; + char *full_attribute; + unsigned int tmp_now; + unsigned int tmp_full; + struct timespec ts; + FILE *file; + + battery->discharging = false; + battery->full = true; + battery->energy_now = 0; + battery->energy_full = 0; + set_attributes(battery->names[0], &now_attribute, &full_attribute); + + // wait for changes on the state files or for timeout + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += timeout.tv_sec; + ts.tv_nsec += timeout.tv_nsec; + pthread_mutex_lock(battery->state_change_mut); + pthread_cond_timedwait(battery->bat_state_change, + battery->state_change_mut, &ts); + pthread_mutex_unlock(battery->state_change_mut); + + /* iterate through all batteries */ + for (int i = 0; i < battery->count; i++) { + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/status", battery->names[i]); + file = fopen(attr_path, "r"); + if (file == NULL || fscanf(file, "%12s", state) == 0) { + if (required) + err(EXIT_FAILURE, "Could not read %s", attr_path); + battery->discharging |= 0; + if (file) + fclose(file); + continue; + } + fclose(file); + + battery->discharging |= strcmp(state, POWER_SUPPLY_DISCHARGING) == 0; + battery->full &= strcmp(state, POWER_SUPPLY_FULL) == 0; + + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/%s", battery->names[i], + now_attribute); + file = fopen(attr_path, "r"); + if (file == NULL || fscanf(file, "%u", &tmp_now) == 0) { + if (required) + err(EXIT_FAILURE, "Could not read %s", attr_path); + if (file) + fclose(file); + continue; + } + fclose(file); + + if (full_attribute != NULL) { + sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/%s", battery->names[i], + full_attribute); + file = fopen(attr_path, "r"); + if (file == NULL || fscanf(file, "%u", &tmp_full) == 0) { + if (required) + err(EXIT_FAILURE, "Could not read %s", attr_path); + if (file) + fclose(file); + continue; + } + fclose(file); + } else { + tmp_full = 100; + } + + battery->energy_now += tmp_now; + battery->energy_full += tmp_full; + } + + battery->level = round(100.0 * battery->energy_now / battery->energy_full); +} diff --git a/main.c b/src/main.c similarity index 73% rename from main.c rename to src/main.c index 6529f13..6ecd9c9 100644 --- a/main.c +++ b/src/main.c @@ -28,12 +28,14 @@ #include "notify.h" #include "options.h" -void print_version() +BatteryState *battery; + +void print_version(void) { printf("%s %s\n", PROGNAME, VERSION); } -void print_help() +void print_help(void) { printf("Usage: %s [OPTIONS]\n\ \n\ @@ -75,14 +77,17 @@ Options:\n\ ", PROGNAME, PROGNAME); } -void cleanup() +void cleanup(void) { if (notify_is_initted()) { notify_uninit(); } + if (battery->inotify_fd!=-1) { + uninit_batteries(battery); + } } -void signal_handler() +void signal_handler(int _) { exit(EXIT_SUCCESS); } @@ -93,11 +98,15 @@ int main(int argc, char *argv[]) bool previous_discharging_status; sigset_t sigs; struct timespec timeout = { .tv_sec = 0 }; + struct timespec time_0 = {0,0}; int bat_index; - BatteryState battery; char *config_file = NULL; int conf_argc = 0; char **conf_argv; + battery = calloc(1, sizeof(*battery)); + if (battery==NULL) { + err(EXIT_FAILURE, "Failed to allocate memory for battery struct"); + } Config config = { .daemonize = false, @@ -176,69 +185,67 @@ int main(int argc, char *argv[]) err(EXIT_FAILURE, "Failed to daemonize"); } - battery.names = config.battery_names; - battery.count = config.battery_count; - update_battery_state(&battery, config.battery_required); + battery = init_batteries(config.battery_names, config.battery_count); + wait_for_update_battery_state(battery, config.battery_required, timeout); for(;;) { - previous_discharging_status = battery.discharging; - update_battery_state(&battery, config.battery_required); + previous_discharging_status = battery->discharging; duration = config.multiplier; - if (battery.discharging) { /* discharging */ - if (config.danger && battery.level <= config.danger) { - if (battery.state != STATE_DANGER) { - battery.state = STATE_DANGER; + if (battery->discharging) { /* discharging */ + if (config.danger && battery->level <= config.danger) { + if (battery->state != STATE_DANGER) { + battery->state = STATE_DANGER; if (config.dangercmd[0] != '\0') if (system(config.dangercmd) == -1) { /* Ignore command errors... */ } } - } else if (config.critical && battery.level <= config.critical) { - if (battery.state != STATE_CRITICAL) { - battery.state = STATE_CRITICAL; - notify(config.criticalmsg, NOTIFY_URGENCY_CRITICAL, battery); + } else if (config.critical && battery->level <= config.critical) { + if (battery->state != STATE_CRITICAL) { + battery->state = STATE_CRITICAL; + notify(config.criticalmsg, NOTIFY_URGENCY_CRITICAL, *battery); } - } else if (config.warning && battery.level <= config.warning) { + } else if (config.warning && battery->level <= config.warning) { if (!config.fixed) - duration = (battery.level - config.critical) * config.multiplier; + duration = (battery->level - config.critical) * config.multiplier; - if (battery.state != STATE_WARNING) { - battery.state = STATE_WARNING; - notify(config.warningmsg, NOTIFY_URGENCY_NORMAL, battery); + if (battery->state != STATE_WARNING) { + battery->state = STATE_WARNING; + notify(config.warningmsg, NOTIFY_URGENCY_NORMAL, *battery); } } else { - if (config.show_charging_msg && battery.discharging != previous_discharging_status) { - notify(config.dischargingmsg, NOTIFY_URGENCY_NORMAL, battery); - } else if (battery.state == STATE_FULL) { + if (config.show_charging_msg && battery->discharging != previous_discharging_status) { + notify(config.dischargingmsg, NOTIFY_URGENCY_NORMAL, *battery); + } else if (battery->state == STATE_FULL) { close_notification(); } - battery.state = STATE_DISCHARGING; + battery->state = STATE_DISCHARGING; if (!config.fixed) - duration = (battery.level - config.warning) * config.multiplier; + duration = (battery->level - config.warning) * config.multiplier; } } else { /* charging */ - if ((config.full && battery.state != STATE_FULL) && (battery.level >= config.full || battery.full)) { - battery.state = STATE_FULL; - notify(config.fullmsg, NOTIFY_URGENCY_NORMAL, battery); + if ((config.full && battery->state != STATE_FULL) && (battery->level >= config.full || battery->full)) { + battery->state = STATE_FULL; + notify(config.fullmsg, NOTIFY_URGENCY_NORMAL, *battery); - } else if (config.show_charging_msg && battery.discharging != previous_discharging_status) { - battery.state = STATE_AC; - notify(config.chargingmsg, NOTIFY_URGENCY_NORMAL, battery); + } else if (config.show_charging_msg && battery->discharging != previous_discharging_status) { + battery->state = STATE_AC; + notify(config.chargingmsg, NOTIFY_URGENCY_NORMAL, *battery); } else { - battery.state = STATE_AC; + battery->state = STATE_AC; close_notification(); } } if (config.multiplier == 0) { - sigwaitinfo(&sigs, NULL); + wait_for_update_battery_state(battery, config.battery_required, time_0); } else { timeout.tv_sec = duration; - sigtimedwait(&sigs, NULL, &timeout); + wait_for_update_battery_state(battery, config.battery_required, timeout); } if (config.run_once) break; diff --git a/notify.c b/src/notify.c similarity index 100% rename from notify.c rename to src/notify.c diff --git a/options.c b/src/options.c similarity index 100% rename from options.c rename to src/options.c