1 #ifndef _I3STATUS_H
2 #define _I3STATUS_H
3 
4 typedef enum {
5     O_DZEN2,
6     O_XMOBAR,
7     O_I3BAR,
8     O_LEMONBAR,
9     O_TERM,
10     O_NONE
11 } output_format_t;
12 extern output_format_t output_format;
13 
14 typedef enum {
15     M_PANGO,
16     M_NONE
17 } markup_format_t;
18 extern markup_format_t markup_format;
19 
20 extern char *pct_mark;
21 
22 #include <stdbool.h>
23 #include <confuse.h>
24 #include <time.h>
25 #include <yajl/yajl_gen.h>
26 #include <yajl/yajl_version.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <pthread.h>
30 #include <stdint.h>
31 
32 #define BEGINS_WITH(haystack, needle) (strncmp(haystack, needle, strlen(needle)) == 0)
33 #define max(a, b) ((a) > (b) ? (a) : (b))
34 
35 #define DEFAULT_SINK_INDEX UINT32_MAX
36 #define COMPOSE_VOLUME_MUTE(vol, mute) ((vol) | ((mute) ? (1 << 30) : 0))
37 #define DECOMPOSE_VOLUME(cvol) ((cvol) & ~(1 << 30))
38 #define DECOMPOSE_MUTED(cvol) (((cvol) & (1 << 30)) != 0)
39 #define MAX_SINK_DESCRIPTION_LEN (128) /* arbitrary */
40 
41 #if defined(__linux__)
42 
43 #define THERMAL_ZONE "/sys/class/thermal/thermal_zone%d/temp"
44 
45 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
46 
47 /* this needs the coretemp module to be loaded */
48 #if defined(__DragonFly__)
49 #define THERMAL_ZONE "hw.sensors.cpu%d.temp0"
50 #else
51 #define THERMAL_ZONE "dev.cpu.%d.temperature"
52 #endif
53 #define BATT_LIFE "hw.acpi.battery.life"
54 #define BATT_TIME "hw.acpi.battery.time"
55 #define BATT_STATE "hw.acpi.battery.state"
56 
57 #elif defined(__OpenBSD__) || defined(__NetBSD__)
58 /* Default to acpitz(4) if no path is set. */
59 #define THERMAL_ZONE "acpitz%d"
60 #endif
61 
62 #if defined(__FreeBSD_kernel__) && defined(__GLIBC__)
63 
64 #include <sys/stat.h>
65 #include <sys/param.h>
66 
67 #endif
68 
69 /* Allows for the definition of a variable without opening a new scope, thus
70  * suited for usage in a macro. Idea from wmii. */
71 #define with(type, var, init) \
72     for (type var = (type)-1; (var == (type)-1) && ((var = (init)) || 1); var = (type)1)
73 
74 #define CASE_SEC(name)              \
75     if (BEGINS_WITH(current, name)) \
76     with(cfg_t *, sec, cfg_section = cfg_getsec(cfg, name)) if (sec != NULL)
77 
78 #define CASE_SEC_TITLE(name)                              \
79     if (BEGINS_WITH(current, name))                       \
80     with(const char *, title, current + strlen(name) + 1) \
81         with(cfg_t *, sec, cfg_section = cfg_gettsec(cfg, name, title)) if (sec != NULL)
82 
83 /* Macro which any plugin can use to output the full_text part (when the output
84  * format is JSON) or just output to stdout (any other output format). */
85 #define OUTPUT_FULL_TEXT(text)                                                                       \
86     do {                                                                                             \
87         /* Terminate the output buffer here in any case, so that it’s                              \
88          * not forgotten in the module */                                                            \
89         *outwalk = '\0';                                                                             \
90         if (output_format == O_I3BAR) {                                                              \
91             char *_markup = cfg_getstr(cfg_general, "markup");                                       \
92             yajl_gen_string(ctx->json_gen, (const unsigned char *)"markup", strlen("markup"));       \
93             yajl_gen_string(ctx->json_gen, (const unsigned char *)_markup, strlen(_markup));         \
94             yajl_gen_string(ctx->json_gen, (const unsigned char *)"full_text", strlen("full_text")); \
95             yajl_gen_string(ctx->json_gen, (const unsigned char *)text, strlen(text));               \
96         } else {                                                                                     \
97             printf("%s", text);                                                                      \
98         }                                                                                            \
99     } while (0)
100 
101 #define SEC_OPEN_MAP(name)                                                            \
102     do {                                                                              \
103         if (output_format == O_I3BAR) {                                               \
104             yajl_gen_map_open(json_gen);                                              \
105             yajl_gen_string(json_gen, (const unsigned char *)"name", strlen("name")); \
106             yajl_gen_string(json_gen, (const unsigned char *)name, strlen(name));     \
107         }                                                                             \
108     } while (0)
109 
110 #define SEC_CLOSE_MAP                                                                                                       \
111     do {                                                                                                                    \
112         if (output_format == O_I3BAR) {                                                                                     \
113             char *_align = cfg_getstr(sec, "align");                                                                        \
114             if (_align) {                                                                                                   \
115                 yajl_gen_string(json_gen, (const unsigned char *)"align", strlen("align"));                                 \
116                 yajl_gen_string(json_gen, (const unsigned char *)_align, strlen(_align));                                   \
117             }                                                                                                               \
118             struct min_width *_width = cfg_getptr(sec, "min_width");                                                        \
119             if (_width) {                                                                                                   \
120                 /* if the value can be parsed as a number, we use the numerical value */                                    \
121                 if (_width->num > 0) {                                                                                      \
122                     yajl_gen_string(json_gen, (const unsigned char *)"min_width", strlen("min_width"));                     \
123                     yajl_gen_integer(json_gen, _width->num);                                                                \
124                 } else {                                                                                                    \
125                     yajl_gen_string(json_gen, (const unsigned char *)"min_width", strlen("min_width"));                     \
126                     yajl_gen_string(json_gen, (const unsigned char *)_width->str, strlen(_width->str));                     \
127                 }                                                                                                           \
128             }                                                                                                               \
129             if (cfg_size(sec, "separator") > 0) {                                                                           \
130                 yajl_gen_string(json_gen, (const unsigned char *)"separator", strlen("separator"));                         \
131                 yajl_gen_bool(json_gen, cfg_getbool(sec, "separator"));                                                     \
132             }                                                                                                               \
133             if (cfg_size(sec, "separator_block_width") > 0) {                                                               \
134                 yajl_gen_string(json_gen, (const unsigned char *)"separator_block_width", strlen("separator_block_width")); \
135                 yajl_gen_integer(json_gen, cfg_getint(sec, "separator_block_width"));                                       \
136             }                                                                                                               \
137             const char *_sep = cfg_getstr(cfg_general, "separator");                                                        \
138             if (strlen(_sep) == 0) {                                                                                        \
139                 yajl_gen_string(json_gen, (const unsigned char *)"separator", strlen("separator"));                         \
140                 yajl_gen_bool(json_gen, false);                                                                             \
141             }                                                                                                               \
142             yajl_gen_map_close(json_gen);                                                                                   \
143         }                                                                                                                   \
144     } while (0)
145 
146 #define START_COLOR(colorstr)                                                                    \
147     do {                                                                                         \
148         if (cfg_getbool(cfg_general, "colors")) {                                                \
149             const char *_val = NULL;                                                             \
150             if (cfg_section)                                                                     \
151                 _val = cfg_getstr(cfg_section, colorstr);                                        \
152             if (!_val)                                                                           \
153                 _val = cfg_getstr(cfg_general, colorstr);                                        \
154             if (output_format == O_I3BAR) {                                                      \
155                 yajl_gen_string(ctx->json_gen, (const unsigned char *)"color", strlen("color")); \
156                 yajl_gen_string(ctx->json_gen, (const unsigned char *)_val, strlen(_val));       \
157             } else {                                                                             \
158                 outwalk += sprintf(outwalk, "%s", color(colorstr));                              \
159             }                                                                                    \
160         }                                                                                        \
161     } while (0)
162 
163 #define END_COLOR                                                             \
164     do {                                                                      \
165         if (cfg_getbool(cfg_general, "colors") && output_format != O_I3BAR) { \
166             outwalk += sprintf(outwalk, "%s", endcolor());                    \
167         }                                                                     \
168     } while (0)
169 
170 #define INSTANCE(instance)                                                                         \
171     do {                                                                                           \
172         if (output_format == O_I3BAR) {                                                            \
173             yajl_gen_string(ctx->json_gen, (const unsigned char *)"instance", strlen("instance")); \
174             yajl_gen_string(ctx->json_gen, (const unsigned char *)instance, strlen(instance));     \
175         }                                                                                          \
176     } while (0)
177 
178 #define OUTPUT_FORMATTED                                             \
179     do {                                                             \
180         const size_t remaining = ctx->buflen - (outwalk - ctx->buf); \
181         strncpy(outwalk, formatted, remaining);                      \
182         outwalk += strlen(formatted);                                \
183     } while (0)
184 
185 /*
186  * The "min_width" module option may either be defined as a string or a number.
187  */
188 struct min_width {
189     long num;
190     const char *str;
191 };
192 
193 /* src/general.c */
194 char *skip_character(char *input, char character, int amount);
195 
196 void die(const char *fmt, ...) __attribute__((format(printf, 1, 2), noreturn));
197 bool slurp(const char *filename, char *destination, int size);
198 char *resolve_tilde(const char *path);
199 void *scalloc(size_t size);
200 char *sstrdup(const char *str);
201 
202 /* src/output.c */
203 void print_separator(const char *separator);
204 char *color(const char *colorstr);
205 char *endcolor() __attribute__((pure));
206 void reset_cursor(void);
207 void maybe_escape_markup(char *text, char **buffer);
208 
209 char *rtrim(const char *s);
210 char *ltrim(const char *s);
211 char *trim(const char *s);
212 
213 // copied from  i3:libi3/format_placeholders.c
214 /* src/format_placeholders.c */
215 typedef struct {
216     /* The placeholder to be replaced, e.g., "%title". */
217     const char *name;
218     /* The value this placeholder should be replaced with. */
219     const char *value;
220 } placeholder_t;
221 char *format_placeholders(const char *format, placeholder_t *placeholders, int num);
222 
223 /* src/auto_detect_format.c */
224 char *auto_detect_format();
225 
226 /* src/print_time.c */
227 void set_timezone(const char *tz);
228 
229 /* src/first_network_device.c */
230 typedef enum {
231     NET_TYPE_WIRELESS = 0,
232     NET_TYPE_ETHERNET = 1,
233     NET_TYPE_OTHER = 2
234 } net_type_t;
235 const char *first_eth_interface(const net_type_t type);
236 
237 typedef struct {
238     yajl_gen json_gen;
239     char *buf;
240     const size_t buflen;
241     const char *format_up;
242     const char *format_down;
243 } ipv6_info_ctx_t;
244 
245 void print_ipv6_info(ipv6_info_ctx_t *ctx);
246 
247 typedef struct {
248     yajl_gen json_gen;
249     char *buf;
250     const size_t buflen;
251     const char *path;
252     const char *format;
253     const char *format_below_threshold;
254     const char *format_not_mounted;
255     const char *prefix_type;
256     const char *threshold_type;
257     const double low_threshold;
258 } disk_info_ctx_t;
259 
260 void print_disk_info(disk_info_ctx_t *ctx);
261 
262 typedef struct {
263     yajl_gen json_gen;
264     char *buf;
265     const size_t buflen;
266     int number;
267     const char *path;
268     const char *format;
269     const char *format_down;
270     const char *status_chr;
271     const char *status_bat;
272     const char *status_unk;
273     const char *status_full;
274     int low_threshold;
275     char *threshold_type;
276     bool last_full_capacity;
277     const char *format_percentage;
278     bool hide_seconds;
279 } battery_info_ctx_t;
280 
281 void print_battery_info(battery_info_ctx_t *ctx);
282 
283 typedef struct {
284     yajl_gen json_gen;
285     char *buf;
286     const size_t buflen;
287     const char *title;
288     const char *format;
289     const char *tz;
290     const char *locale;
291     const char *format_time;
292     bool hide_if_equals_localtime;
293     time_t t;
294 } time_ctx_t;
295 
296 void print_time(time_ctx_t *ctx);
297 
298 typedef struct {
299     yajl_gen json_gen;
300     char *buf;
301     const size_t buflen;
302     const char *format;
303     time_t t;
304 } ddate_ctx_t;
305 
306 void print_ddate(ddate_ctx_t *ctx);
307 
308 const char *get_ip_addr(const char *interface, int family);
309 
310 typedef struct {
311     yajl_gen json_gen;
312     char *buf;
313     const size_t buflen;
314     const char *interface;
315     const char *format_up;
316     const char *format_down;
317     const char *format_bitrate;
318     const char *format_noise;
319     const char *format_quality;
320     const char *format_signal;
321 } wireless_info_ctx_t;
322 
323 void print_wireless_info(wireless_info_ctx_t *ctx);
324 
325 typedef struct {
326     yajl_gen json_gen;
327     char *buf;
328     const size_t buflen;
329     const char *title;
330     const char *pidfile;
331     const char *format;
332     const char *format_down;
333 } run_watch_ctx_t;
334 
335 void print_run_watch(run_watch_ctx_t *ctx);
336 
337 typedef struct {
338     yajl_gen json_gen;
339     char *buf;
340     const size_t buflen;
341     const char *title;
342     const char *path;
343     const char *format;
344     const char *format_down;
345 } path_exists_ctx_t;
346 
347 void print_path_exists(path_exists_ctx_t *ctx);
348 
349 typedef struct {
350     yajl_gen json_gen;
351     char *buf;
352     const size_t buflen;
353     int zone;
354     const char *path;
355     const char *format;
356     const char *format_above_threshold;
357     int max_threshold;
358 } cpu_temperature_ctx_t;
359 
360 void print_cpu_temperature_info(cpu_temperature_ctx_t *ctx);
361 
362 typedef struct {
363     yajl_gen json_gen;
364     char *buf;
365     const size_t buflen;
366     const char *format;
367     const char *format_above_threshold;
368     const char *format_above_degraded_threshold;
369     const char *path;
370     const float max_threshold;
371     const float degraded_threshold;
372 } cpu_usage_ctx_t;
373 
374 void print_cpu_usage(cpu_usage_ctx_t *ctx);
375 
376 typedef struct {
377     yajl_gen json_gen;
378     char *buf;
379     const size_t buflen;
380     const char *interface;
381     const char *format_up;
382     const char *format_down;
383 } eth_info_ctx_t;
384 
385 void print_eth_info(eth_info_ctx_t *ctx);
386 
387 typedef struct {
388     yajl_gen json_gen;
389     char *buf;
390     const size_t buflen;
391     const char *format;
392     const char *format_above_threshold;
393     const float max_threshold;
394 } load_ctx_t;
395 
396 void print_load(load_ctx_t *ctx);
397 
398 typedef struct {
399     yajl_gen json_gen;
400     char *buf;
401     const size_t buflen;
402     const char *format;
403     const char *format_degraded;
404     const char *threshold_degraded;
405     const char *threshold_critical;
406     const char *memory_used_method;
407     const char *unit;
408     const int decimals;
409 } memory_ctx_t;
410 
411 void print_memory(memory_ctx_t *ctx);
412 
413 typedef struct {
414     yajl_gen json_gen;
415     char *buf;
416     const size_t buflen;
417     const char *fmt;
418     const char *fmt_muted;
419     const char *device;
420     const char *mixer;
421     int mixer_idx;
422 } volume_ctx_t;
423 
424 void print_volume(volume_ctx_t *ctx);
425 
426 bool process_runs(const char *path);
427 int volume_pulseaudio(uint32_t sink_idx, const char *sink_name);
428 bool description_pulseaudio(uint32_t sink_idx, const char *sink_name, char buffer[MAX_SINK_DESCRIPTION_LEN]);
429 bool pulse_initialize(void);
430 
431 typedef struct {
432     yajl_gen json_gen;
433     char *buf;
434     const size_t buflen;
435     const char *title;
436     const char *path;
437     const char *format;
438     const char *format_bad;
439     const int max_chars;
440 } file_contents_ctx_t;
441 
442 void print_file_contents(file_contents_ctx_t *ctx);
443 
444 /* socket file descriptor for general purposes */
445 extern int general_socket;
446 
447 extern cfg_t *cfg, *cfg_general, *cfg_section;
448 
449 extern void **cur_instance;
450 
451 extern pthread_t main_thread;
452 #endif
453