void **cur_instance;
+ pthread_cond_t i3status_sleep_cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t i3status_sleep_mutex = PTHREAD_MUTEX_INITIALIZER;
+
/*
* Set the exit_upon_signal flag, because one cannot do anything in a safe
* manner in a signal handler (e.g. fprintf, which we really want to do for
cfg_opt_t run_watch_opts[] = {
CFG_STR("pidfile", NULL, CFGF_NONE),
CFG_STR("format", "%title: %status", CFGF_NONE),
+ CFG_STR("format_down", NULL, CFGF_NONE),
CFG_CUSTOM_ALIGN_OPT,
CFG_CUSTOM_COLOR_OPTS,
CFG_CUSTOM_MIN_WIDTH_OPT,
cfg_opt_t path_exists_opts[] = {
CFG_STR("path", NULL, CFGF_NONE),
CFG_STR("format", "%title: %status", CFGF_NONE),
+ CFG_STR("format_down", NULL, CFGF_NONE),
CFG_CUSTOM_ALIGN_OPT,
CFG_CUSTOM_COLOR_OPTS,
CFG_CUSTOM_MIN_WIDTH_OPT,
char buffer[4096];
void **per_instance = calloc(cfg_size(cfg, "order"), sizeof(*per_instance));
+ pthread_mutex_lock(&i3status_sleep_mutex);
while (1) {
if (exit_upon_signal) {
CASE_SEC_TITLE("run_watch") {
SEC_OPEN_MAP("run_watch");
- print_run_watch(json_gen, buffer, title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
+ print_run_watch(json_gen, buffer, title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"), cfg_getstr(sec, "format_down"));
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("path_exists") {
SEC_OPEN_MAP("path_exists");
- print_path_exists(json_gen, buffer, title, cfg_getstr(sec, "path"), cfg_getstr(sec, "format"));
+ print_path_exists(json_gen, buffer, title, cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getstr(sec, "format_down"));
SEC_CLOSE_MAP;
}
fflush(stdout);
/* To provide updates on every full second (as good as possible)
- * we don’t use sleep(interval) but we sleep until the next
- * second (with microsecond precision) plus (interval-1)
- * seconds. We also align to 60 seconds modulo interval such
+ * we don’t use sleep(interval) but we sleep until the next second.
+ * We also align to 60 seconds modulo interval such
* that we start with :00 on every new minute. */
- struct timeval current_timeval;
- gettimeofday(¤t_timeval, NULL);
- struct timespec ts = {interval - 1 - (current_timeval.tv_sec % interval), (10e5 - current_timeval.tv_usec) * 1000};
- nanosleep(&ts, NULL);
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += interval - (ts.tv_sec % interval);
+ ts.tv_nsec = 0;
+
+ /* Sleep to absolute time 'ts', unless the condition
+ * 'i3status_sleep_cond' is signaled from another thread */
+ pthread_cond_timedwait(&i3status_sleep_cond, &i3status_sleep_mutex, &ts);
}
}
#include <yajl/yajl_version.h>
#include <unistd.h>
#include <string.h>
+ #include <pthread.h>
+ #include <stdint.h>
#define BEGINS_WITH(haystack, needle) (strncmp(haystack, needle, strlen(needle)) == 0)
#define max(a, b) ((a) > (b) ? (a) : (b))
+ #define DEFAULT_SINK_INDEX UINT32_MAX
+
#if defined(LINUX)
#define THERMAL_ZONE "/sys/class/thermal/thermal_zone%d/temp"
void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, const char *status_chr, const char *status_bat, const char *status_full, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity, bool hide_seconds);
void print_time(yajl_gen json_gen, char *buffer, const char *title, const char *format, const char *tz, time_t t);
void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t);
-const char *get_ip_addr();
+const char *get_ip_addr(const char *interface);
void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
-void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format);
-void print_path_exists(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format);
+void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format, const char *format_down);
+void print_path_exists(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format, const char *format_down);
void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, int);
void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format);
void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
void print_load(yajl_gen json_gen, char *buffer, const char *format, const float max_threshold);
void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_muted, const char *device, const char *mixer, int mixer_idx);
bool process_runs(const char *path);
+ int volume_pulseaudio(uint32_t sink_idx);
+ bool pulse_initialize(void);
/* socket file descriptor for general purposes */
extern int general_socket;
extern void **cur_instance;
+ extern pthread_cond_t i3status_sleep_cond;
+ extern pthread_mutex_t i3status_sleep_mutex;
+
#endif
You can define a different format with the option "format_not_mounted"
which is used if the path is not a mount point. So you can just empty
-the output for the given path with adding »format_not_mounted=""«
+the output for the given path with adding +format_not_mounted=""+
to the config section.
*Example order*: +disk /mnt/usbstick+
Expands the given path to a pidfile and checks if the process ID found inside
is valid (that is, if the process is running). You can use this to check if
a specific application, such as a VPN client or your DHCP client is running.
+There also is an option "format_down". You can hide the output with
++format_down=""+.
*Example order*: +run_watch DHCP+
Checks if the given path exists in the filesystem. You can use this to check if
something is active, like for example a VPN tunnel managed by NetworkManager.
+There also is an option "format_down". You can hide the output with
++format_down=""+.
*Example order*: +path_exists VPN+
=== Volume
- Outputs the volume of the specified mixer on the specified device. Works only
- on Linux because it uses ALSA.
- A simplified configuration can be used on FreeBSD and OpenBSD due to
- the lack of ALSA, the +device+ and +mixer+ options can be
- ignored on these systems. On these systems the OSS API is used instead to
- query +/dev/mixer+ directly if +mixer_dix+ is -1, otherwise
- +/dev/mixer++mixer_idx+.
+ Outputs the volume of the specified mixer on the specified device. PulseAudio
+ and ALSA (Linux only) are supported. If PulseAudio is absent, a simplified
+ configuration can be used on FreeBSD and OpenBSD due to the lack of ALSA, the
+ +device+ and +mixer+ options can be ignored on these systems. On these systems
+ the OSS API is used instead to query +/dev/mixer+ directly if +mixer_idx+ is
+ -1, otherwise +/dev/mixer++mixer_idx+.
+
+ To get PulseAudio volume information, one must use the following format in the
+ device line:
+
+ device = "pulse"
+
+ or
+
+ device = "pulse:N"
+
+ where N is the index of the PulseAudio sink. If no sink is specified the
+ default is used. If the device string is missing or is set to "default",
+ PulseAudio will be tried if detected and will fallback to ALSA (Linux)
+ or OSS (FreeBSD/OpenBSD).
*Example order*: +volume master+
*Example format*: +♪: %volume+
+
*Example format_muted*: +♪: 0%%+
*Example configuration*:
mixer_idx = 0
}
-------------------------------------------------------------
+ *Example configuration (PulseAudio)*:
+ -------------------------------------------------------------
+ volume master {
+ format = "♪: %volume"
+ format_muted = "♪: muted (%volume)"
+ device = "pulse:1"
+ }
+ -------------------------------------------------------------
== Universal module options