]> git.sur5r.net Git - i3/i3status/commitdiff
Merge pull request #7 from Watcom/master
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Fri, 3 Apr 2015 21:45:40 +0000 (14:45 -0700)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Fri, 3 Apr 2015 21:45:40 +0000 (14:45 -0700)
PulseAudio support for volume input

1  2 
i3status.c
include/i3status.h
man/i3status.man

diff --combined i3status.c
index 48bb59dc4c45f08bc8b951b7b63a0db3828704a1,a0beb3e8307df9b9211ae31ffbea5c492b4be3d8..a4c12bfc25619a2e96cb036e82c25b7edfba97e9
@@@ -62,6 -62,9 +62,9 @@@ cfg_t *cfg, *cfg_general, *cfg_section
  
  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
@@@ -287,7 -290,6 +290,7 @@@ int main(int argc, char *argv[]) 
      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(&current_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);
      }
  }
diff --combined include/i3status.h
index 54aee13a9130f8c234b3534a58d0d253949b5046,f2a262c035fae8b1e193e76e452e64df18fd1f25..8fb1b7970a168738e04ade72f87886cafb58870e
@@@ -14,10 -14,14 +14,14 @@@ enum { O_DZEN2
  #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"
@@@ -185,16 -189,18 +189,18 @@@ void print_disk_info(yajl_gen json_gen
  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;
@@@ -203,4 -209,7 +209,7 @@@ extern cfg_t *cfg, *cfg_general, *cfg_s
  
  extern void **cur_instance;
  
+ extern pthread_cond_t i3status_sleep_cond;
+ extern pthread_mutex_t i3status_sleep_mutex;
  #endif
diff --combined man/i3status.man
index 57541965a650c67225e7f8747549c10e32ac7eb8,502f391ea29538f30f1dd30c7715a32062391719..a3a8c60e97d4dc58ebe458f84d860862bca87088
@@@ -239,7 -239,7 +239,7 @@@ implies no coloring at all
  
  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+
  
@@@ -426,18 -422,30 +426,31 @@@ details on the format string
  
  === 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*:
@@@ -450,6 -458,14 +463,14 @@@ volume master 
        mixer_idx = 0
  }
  -------------------------------------------------------------
+ *Example configuration (PulseAudio)*:
+ -------------------------------------------------------------
+ volume master {
+       format = "♪: %volume"
+       format_muted = "♪: muted (%volume)"
+       device = "pulse:1"
+ }
+ -------------------------------------------------------------
  
  == Universal module options