Support align and min_width module options
This patch enables users to define "align" and "min_width" options right in the i3status module config sections. Specifically this patch: * Adds macros for the two new options that are used in the option definitions. As the min_width option can take either a string or a number, a custom type has been added along with a corresponding callback function that parses the provided value (and provides input validation). The align option also uses a callback for input validation * Expands all module config option definitions to include the new options * Extends the SEC_CLOSE_MAP() macro to generate the JSON for the new options as necessary * Updates the manpage to explain the new options
This commit is contained in:
parent
0c2b518b8a
commit
1de12e7b20
83
i3status.c
83
i3status.c
@ -11,6 +11,7 @@
|
|||||||
* See file LICENSE for license information.
|
* See file LICENSE for license information.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -35,6 +36,9 @@
|
|||||||
|
|
||||||
#define exit_if_null(pointer, ...) { if (pointer == NULL) die(__VA_ARGS__); }
|
#define exit_if_null(pointer, ...) { if (pointer == NULL) die(__VA_ARGS__); }
|
||||||
|
|
||||||
|
#define CFG_CUSTOM_ALIGN_OPT \
|
||||||
|
CFG_STR_CB("align", NULL, CFGF_NONE, parse_align)
|
||||||
|
|
||||||
#define CFG_COLOR_OPTS(good, degraded, bad) \
|
#define CFG_COLOR_OPTS(good, degraded, bad) \
|
||||||
CFG_STR("color_good", good, CFGF_NONE), \
|
CFG_STR("color_good", good, CFGF_NONE), \
|
||||||
CFG_STR("color_degraded", degraded, CFGF_NONE), \
|
CFG_STR("color_degraded", degraded, CFGF_NONE), \
|
||||||
@ -42,6 +46,9 @@
|
|||||||
|
|
||||||
#define CFG_CUSTOM_COLOR_OPTS CFG_COLOR_OPTS(NULL, NULL, NULL)
|
#define CFG_CUSTOM_COLOR_OPTS CFG_COLOR_OPTS(NULL, NULL, NULL)
|
||||||
|
|
||||||
|
#define CFG_CUSTOM_MIN_WIDTH_OPT \
|
||||||
|
CFG_PTR_CB("min_width", NULL, CFGF_NONE, parse_min_width, free)
|
||||||
|
|
||||||
/* socket file descriptor for general purposes */
|
/* socket file descriptor for general purposes */
|
||||||
int general_socket;
|
int general_socket;
|
||||||
|
|
||||||
@ -89,6 +96,54 @@ static char *sstrdup(const char *str) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parses the "align" module option (to validate input).
|
||||||
|
*/
|
||||||
|
static int parse_align(cfg_t *context, cfg_opt_t *option, const char *value, void *result) {
|
||||||
|
if (strcasecmp(value, "left") != 0 && strcasecmp(value,"right") != 0 && strcasecmp(value, "center") != 0)
|
||||||
|
die("Invalid alignment attribute found in section %s, line %d: \"%s\"\n"
|
||||||
|
"Valid attributes are: left, center, right\n", context->name, context->line, value);
|
||||||
|
|
||||||
|
char **cresult = result;
|
||||||
|
*cresult = sstrdup(value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parses the "min_width" module option whose value can either be a string or an integer.
|
||||||
|
*/
|
||||||
|
static int parse_min_width(cfg_t *context, cfg_opt_t *option, const char *value, void *result) {
|
||||||
|
char *end;
|
||||||
|
long num = strtol(value, &end, 10);
|
||||||
|
|
||||||
|
if (num < 0)
|
||||||
|
die("Invalid min_width attribute found in section %s, line %d: %d\n"
|
||||||
|
"Expected positive integer or string\n", context->name, context->line, num);
|
||||||
|
else if (num == LONG_MIN || num == LONG_MAX || (end && *end != '\0'))
|
||||||
|
num = 0;
|
||||||
|
|
||||||
|
if (strlen(value) == 0)
|
||||||
|
die("Empty min_width attribute found in section %s, line %d\n"
|
||||||
|
"Expected positive integer or non-empty string\n", context->name, context->line);
|
||||||
|
|
||||||
|
if (strcmp(value, "0") == 0)
|
||||||
|
die("Invalid min_width attribute found in section %s, line %d: \"%s\"\n"
|
||||||
|
"Expected positive integer or string\n", context->name, context->line, value);
|
||||||
|
|
||||||
|
struct min_width *parsed = scalloc(sizeof(struct min_width));
|
||||||
|
parsed->num = num;
|
||||||
|
|
||||||
|
/* num is preferred, but if it’s 0 (i.e. not valid), store and use
|
||||||
|
* the raw string value */
|
||||||
|
if (num == 0)
|
||||||
|
parsed->str = sstrdup(value);
|
||||||
|
|
||||||
|
struct min_width **cresult = result;
|
||||||
|
*cresult = parsed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validates a color in "#RRGGBB" format
|
* Validates a color in "#RRGGBB" format
|
||||||
@ -219,35 +274,45 @@ int main(int argc, char *argv[]) {
|
|||||||
cfg_opt_t run_watch_opts[] = {
|
cfg_opt_t run_watch_opts[] = {
|
||||||
CFG_STR("pidfile", NULL, CFGF_NONE),
|
CFG_STR("pidfile", NULL, CFGF_NONE),
|
||||||
CFG_STR("format", "%title: %status", CFGF_NONE),
|
CFG_STR("format", "%title: %status", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t path_exists_opts[] = {
|
cfg_opt_t path_exists_opts[] = {
|
||||||
CFG_STR("path", NULL, CFGF_NONE),
|
CFG_STR("path", NULL, CFGF_NONE),
|
||||||
CFG_STR("format", "%title: %status", CFGF_NONE),
|
CFG_STR("format", "%title: %status", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t wireless_opts[] = {
|
cfg_opt_t wireless_opts[] = {
|
||||||
CFG_STR("format_up", "W: (%quality at %essid, %bitrate) %ip", CFGF_NONE),
|
CFG_STR("format_up", "W: (%quality at %essid, %bitrate) %ip", CFGF_NONE),
|
||||||
CFG_STR("format_down", "W: down", CFGF_NONE),
|
CFG_STR("format_down", "W: down", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t ethernet_opts[] = {
|
cfg_opt_t ethernet_opts[] = {
|
||||||
CFG_STR("format_up", "E: %ip (%speed)", CFGF_NONE),
|
CFG_STR("format_up", "E: %ip (%speed)", CFGF_NONE),
|
||||||
CFG_STR("format_down", "E: down", CFGF_NONE),
|
CFG_STR("format_down", "E: down", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t ipv6_opts[] = {
|
cfg_opt_t ipv6_opts[] = {
|
||||||
CFG_STR("format_up", "%ip", CFGF_NONE),
|
CFG_STR("format_up", "%ip", CFGF_NONE),
|
||||||
CFG_STR("format_down", "no IPv6", CFGF_NONE),
|
CFG_STR("format_down", "no IPv6", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -260,35 +325,47 @@ int main(int argc, char *argv[]) {
|
|||||||
CFG_BOOL("last_full_capacity", false, CFGF_NONE),
|
CFG_BOOL("last_full_capacity", false, CFGF_NONE),
|
||||||
CFG_BOOL("integer_battery_capacity", false, CFGF_NONE),
|
CFG_BOOL("integer_battery_capacity", false, CFGF_NONE),
|
||||||
CFG_BOOL("hide_seconds", false, CFGF_NONE),
|
CFG_BOOL("hide_seconds", false, CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t time_opts[] = {
|
cfg_opt_t time_opts[] = {
|
||||||
CFG_STR("format", "%Y-%m-%d %H:%M:%S", CFGF_NONE),
|
CFG_STR("format", "%Y-%m-%d %H:%M:%S", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t tztime_opts[] = {
|
cfg_opt_t tztime_opts[] = {
|
||||||
CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
|
CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
|
||||||
CFG_STR("timezone", "", CFGF_NONE),
|
CFG_STR("timezone", "", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t ddate_opts[] = {
|
cfg_opt_t ddate_opts[] = {
|
||||||
CFG_STR("format", "%{%a, %b %d%}, %Y%N - %H", CFGF_NONE),
|
CFG_STR("format", "%{%a, %b %d%}, %Y%N - %H", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t load_opts[] = {
|
cfg_opt_t load_opts[] = {
|
||||||
CFG_STR("format", "%1min %5min %15min", CFGF_NONE),
|
CFG_STR("format", "%1min %5min %15min", CFGF_NONE),
|
||||||
CFG_FLOAT("max_threshold", 5, CFGF_NONE),
|
CFG_FLOAT("max_threshold", 5, CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t usage_opts[] = {
|
cfg_opt_t usage_opts[] = {
|
||||||
CFG_STR("format", "%usage", CFGF_NONE),
|
CFG_STR("format", "%usage", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -296,13 +373,17 @@ int main(int argc, char *argv[]) {
|
|||||||
CFG_STR("format", "%degrees C", CFGF_NONE),
|
CFG_STR("format", "%degrees C", CFGF_NONE),
|
||||||
CFG_STR("path", NULL, CFGF_NONE),
|
CFG_STR("path", NULL, CFGF_NONE),
|
||||||
CFG_INT("max_threshold", 75, CFGF_NONE),
|
CFG_INT("max_threshold", 75, CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_opt_t disk_opts[] = {
|
cfg_opt_t disk_opts[] = {
|
||||||
CFG_STR("format", "%free", CFGF_NONE),
|
CFG_STR("format", "%free", CFGF_NONE),
|
||||||
CFG_STR("prefix_type", "binary", CFGF_NONE),
|
CFG_STR("prefix_type", "binary", CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -312,7 +393,9 @@ int main(int argc, char *argv[]) {
|
|||||||
CFG_STR("device", "default", CFGF_NONE),
|
CFG_STR("device", "default", CFGF_NONE),
|
||||||
CFG_STR("mixer", "Master", CFGF_NONE),
|
CFG_STR("mixer", "Master", CFGF_NONE),
|
||||||
CFG_INT("mixer_idx", 0, CFGF_NONE),
|
CFG_INT("mixer_idx", 0, CFGF_NONE),
|
||||||
|
CFG_CUSTOM_ALIGN_OPT,
|
||||||
CFG_CUSTOM_COLOR_OPTS,
|
CFG_CUSTOM_COLOR_OPTS,
|
||||||
|
CFG_CUSTOM_MIN_WIDTH_OPT,
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,6 +88,22 @@ enum { O_DZEN2, O_XMOBAR, O_I3BAR, O_TERM, O_NONE } output_format;
|
|||||||
#define SEC_CLOSE_MAP \
|
#define SEC_CLOSE_MAP \
|
||||||
do { \
|
do { \
|
||||||
if (output_format == O_I3BAR) { \
|
if (output_format == O_I3BAR) { \
|
||||||
|
char *_align = cfg_getstr(sec, "align"); \
|
||||||
|
if (_align) { \
|
||||||
|
yajl_gen_string(json_gen, (const unsigned char *)"align", strlen("align")); \
|
||||||
|
yajl_gen_string(json_gen, (const unsigned char *)_align, strlen(_align)); \
|
||||||
|
} \
|
||||||
|
struct min_width *_width = cfg_getptr(sec, "min_width"); \
|
||||||
|
if (_width) { \
|
||||||
|
/* if the value can be parsed as a number, we use the numerical value */ \
|
||||||
|
if (_width->num > 0) { \
|
||||||
|
yajl_gen_string(json_gen, (const unsigned char *)"min_width", strlen("min_width")); \
|
||||||
|
yajl_gen_integer(json_gen, _width->num); \
|
||||||
|
} else { \
|
||||||
|
yajl_gen_string(json_gen, (const unsigned char *)"min_width", strlen("min_width")); \
|
||||||
|
yajl_gen_string(json_gen, (const unsigned char *)_width->str, strlen(_width->str)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
const char *_sep = cfg_getstr(cfg_general, "separator"); \
|
const char *_sep = cfg_getstr(cfg_general, "separator"); \
|
||||||
if (strlen(_sep) == 0) {\
|
if (strlen(_sep) == 0) {\
|
||||||
yajl_gen_string(json_gen, (const unsigned char *)"separator", strlen("separator")); \
|
yajl_gen_string(json_gen, (const unsigned char *)"separator", strlen("separator")); \
|
||||||
@ -132,6 +148,14 @@ enum { O_DZEN2, O_XMOBAR, O_I3BAR, O_TERM, O_NONE } output_format;
|
|||||||
|
|
||||||
typedef enum { CS_DISCHARGING, CS_CHARGING, CS_FULL } charging_status_t;
|
typedef enum { CS_DISCHARGING, CS_CHARGING, CS_FULL } charging_status_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "min_width" module option may either be defined as a string or a number.
|
||||||
|
*/
|
||||||
|
struct min_width {
|
||||||
|
long num;
|
||||||
|
const char *str;
|
||||||
|
};
|
||||||
|
|
||||||
/* src/general.c */
|
/* src/general.c */
|
||||||
char *skip_character(char *input, char character, int amount);
|
char *skip_character(char *input, char character, int amount);
|
||||||
void die(const char *fmt, ...);
|
void die(const char *fmt, ...);
|
||||||
|
@ -404,6 +404,35 @@ volume master {
|
|||||||
}
|
}
|
||||||
-------------------------------------------------------------
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
== Universal module options
|
||||||
|
|
||||||
|
When using the i3bar output format, there are a few additional options that
|
||||||
|
can be used with all modules to customize their appearance:
|
||||||
|
|
||||||
|
align::
|
||||||
|
The alignment policy to use when the minimum width (see below) is not
|
||||||
|
reached. Either +center+ (default), +right+ or +left+.
|
||||||
|
min_width::
|
||||||
|
The minimum width (in pixels) the module should occupy. If the module takes
|
||||||
|
less space than the specified size, the block will be padded to the left
|
||||||
|
and/or the right side, according to the defined alignment policy. This is
|
||||||
|
useful when you want to prevent the whole status line from shifting when
|
||||||
|
values take more or less space between each iteration.
|
||||||
|
The option can also be a string. In this case, the width of the given text
|
||||||
|
determines the minimum width of the block. This is useful when you want to
|
||||||
|
set a sensible minimum width regardless of which font you are using, and at
|
||||||
|
what particular size. Please note that a number enclosed with quotes will
|
||||||
|
still be treated as a number.
|
||||||
|
|
||||||
|
*Example configuration*:
|
||||||
|
-------------------------------------------------------------
|
||||||
|
disk "/" {
|
||||||
|
format = "%avail"
|
||||||
|
align = "left"
|
||||||
|
min_width = 100
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
== Using i3status with dzen2
|
== Using i3status with dzen2
|
||||||
|
|
||||||
After installing dzen2, you can directly use it with i3status. Just ensure that
|
After installing dzen2, you can directly use it with i3status. Just ensure that
|
||||||
|
Loading…
Reference in New Issue
Block a user