Skip to content

Commit

Permalink
ticker: Initial support. Closes vivien#466
Browse files Browse the repository at this point in the history
Ticker feature implementation.
Added new options, such as: "ticker", "ticker_delimeter",
"ticker_interval", "ticker_chars_limit" & "ticker_direction".

"ticker" option enables/disables feature for a given block.
"ticker_delimeter" sets a character to separate tail and head of the
output string.
"ticker_interval" determines the amount of time periods on which the
output string is being shifted.
"ticker_chars_limit" defines the amount of symbols to be displayed.
"ticker_direction" defines the direction in which the characters will
shift.

This feature required to add a library to work with UTF8 characters, so
now i3blocks has "libutf8proc" in its dependencies.

Closes vivien#466
  • Loading branch information
bmigunov committed Oct 9, 2022
1 parent 3417602 commit 0a10f64
Show file tree
Hide file tree
Showing 13 changed files with 665 additions and 94 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -11,4 +11,4 @@ config.status
configure
i3blocks-config.h*
stamp-h1

cscope.out
12 changes: 11 additions & 1 deletion Makefile.am
Expand Up @@ -2,6 +2,14 @@ DEFS += \
-DSYSCONFDIR=\"$(sysconfdir)\"

bin_PROGRAMS = i3blocks

i3blocks_CFLAGS = \
$(AM_CFLAGS) \
$(UTF8PROC_CFLAGS)

i3blocks_LDADD = \
$(UTF8PROC_LIBS)

i3blocks_SOURCES = \
bar.c \
bar.h \
Expand All @@ -22,7 +30,9 @@ i3blocks_SOURCES = \
map.h \
sys.c \
sys.h \
term.h
term.h \
ticker.c \
ticker.h

dist_man1_MANS = \
docs/i3blocks.1
Expand Down
45 changes: 34 additions & 11 deletions bar.c
Expand Up @@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>

#include "bar.h"
#include "block.h"
Expand All @@ -28,9 +29,9 @@
#include "line.h"
#include "log.h"
#include "map.h"
#include "sched.h"
#include "sys.h"
#include "term.h"
#include "ticker.h"

static void bar_read(struct bar *bar)
{
Expand Down Expand Up @@ -88,16 +89,16 @@ static void bar_poll_timed(struct bar *bar)
static void bar_poll_expired(struct bar *bar)
{
struct block *block = bar->blocks;
unsigned long now, next_update;
int err;

err = sys_gettime(&now);
if (err)
return;

while (block) {
if (block->interval > 0) {
const unsigned long next_update = block->timestamp + block->interval;
unsigned long now;
int err;

err = sys_gettime(&now);
if (err)
return;
next_update = block->timestamp + block->interval;

if (((long) (next_update - now)) <= 0) {
block_debug(block, "expired");
Expand All @@ -106,6 +107,19 @@ static void bar_poll_expired(struct bar *bar)
}
}

if (block->ticker && block->ticker->interval > 0) {
next_update = block->ticker->timestamp + block->ticker->interval;

if (((long) (next_update - now)) <= 0) {
block_debug(block, "ticker expired");

if (block->interval == 0 || block->interval == INTERVAL_ONCE)
block_set_full_text_saved(block);

bar_print(bar);
}
}

block = block->next;
}
}
Expand Down Expand Up @@ -148,11 +162,12 @@ static void bar_poll_exited(struct bar *bar)
if (block) {
block_debug(block, "exited");
block_reap(block);
if (block->interval == INTERVAL_PERSIST) {

if (block->interval == INTERVAL_PERSIST)
block_debug(block, "unexpected exit?");
} else {
else
block_update(block);
}

block_close(block);
if (block->interval == INTERVAL_REPEAT) {
block_spawn(block);
Expand Down Expand Up @@ -213,6 +228,14 @@ static int bar_setup(struct bar *bar)
sleeptime = block->interval;
}

if (block->ticker)
if (sleeptime > 0 &&
sleeptime > gcd(sleeptime, block->ticker->interval))
sleeptime = gcd(sleeptime, block->ticker->interval);
else
if (block->ticker->interval < block->interval)
sleeptime = block->ticker->interval;

block = block->next;
}

Expand Down
102 changes: 100 additions & 2 deletions block.c
Expand Up @@ -19,13 +19,16 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>

#include "bar.h"
#include "block.h"
#include "json.h"
#include "line.h"
#include "log.h"
#include "sys.h"
#include "ticker.h"

const char *block_get(const struct block *block, const char *key)
{
Expand Down Expand Up @@ -113,8 +116,35 @@ static int block_stdout(struct block *block)
/* Deprecated label */
label = block_get(block, "label");
full_text = block_get(block, "full_text");
if (label && full_text) {
snprintf(buf, sizeof(buf), "%s%s", label, full_text);

memset(buf, '\0', BUFSIZ);

if (full_text && (label || block->ticker)) {
char *ticker_output = NULL;
size_t label_strlen = 0;

if (label)
label_strlen = snprintf(buf, sizeof(buf), "%s", label);

if (block->ticker && block->format == FORMAT_RAW) {
ticker_output = ticker_output_get(block->ticker, full_text);

if (block->interval == 0 || block->interval == INTERVAL_ONCE) {
free(block->ticker->full_text_saved);
free(block->ticker->label_saved);

block->ticker->full_text_saved = strdup(full_text);
if (label)
block->ticker->label_saved = strdup(label);
}
}

if (ticker_output) {
strncat(buf, ticker_output, BUFSIZ - label_strlen);
free(ticker_output);
} else
strncat(buf, full_text, BUFSIZ - label_strlen);

err = block_set(block, "full_text", buf);
if (err)
return err;
Expand Down Expand Up @@ -148,6 +178,36 @@ int block_update(struct block *block)
return 0;
}

void block_set_full_text_saved(struct block *block)
{
char buf[BUFSIZ];

memset(buf, '\0', BUFSIZ);

if (block->ticker && block->ticker->full_text_saved) {
size_t label_strlen = 0;
char *ticker_output = NULL;

if (block->ticker->label_saved)
label_strlen = snprintf(buf, sizeof(buf), "%s",
block->ticker->label_saved);

if (block->ticker && block->format == FORMAT_RAW)
ticker_output = ticker_output_get(block->ticker,
block->ticker->full_text_saved);

if (ticker_output) {
strncat(buf, ticker_output, BUFSIZ - label_strlen);
free(ticker_output);
} else
strncat(buf, block->ticker->full_text_saved, BUFSIZ - label_strlen);
}

block_set(block, "full_text", buf);

return;
}

static int block_send_key(const char *key, const char *value, void *data)
{
struct block *block = data;
Expand Down Expand Up @@ -510,6 +570,39 @@ static int i3blocks_setup(struct block *block)
else
block->signal = atoi(value);

value = map_get(block->config, TICKER_CONFIG_OPTION);
if (value && strcmp(value, "true") == 0)
block->ticker = ticker_create();

if (block->ticker) {
value = map_get(block->config, TICKER_CONFIG_OPTION_DELIMETER);
if (!value || (ticker_delimeter_set(block->ticker, value)
!= TICKER_RESULT_SUCCESS)) {
debug("Failed to set ticker delimeter. Setting default delimeter");
block->ticker->delimeter = TICKER_DELIMETER_DEFAULT;
}

value = map_get(block->config, TICKER_CONFIG_OPTION_DIRECTION);
if (value && (strcmp(value, "left") == 0 || strcmp(value, "l") == 0))
block->ticker->direction = TICKER_DIRECTION_LEFT;
else if (value && (strcmp(value, "right") == 0 || strcmp(value, "r") == 0))
block->ticker->direction = TICKER_DIRECTION_RIGHT;
else
block->ticker->direction = TICKER_DIRECTION_DEFAULT;

value = map_get(block->config, TICKER_CONFIG_OPTION_CHARS_LIMIT);
if (value && (atoi(value) > 0))
block->ticker->chars_limit = atoi(value);
else
block->ticker->chars_limit = TICKER_CHARS_LIMIT_DEFAULT;

value = map_get(block->config, TICKER_CONFIG_OPTION_INTERVAL);
if (value && (atoi(value) > 0))
block->ticker->interval = atoi(value);
else
block->ticker->interval = TICKER_INTERVAL_DEFAULT;
}

return 0;
}

Expand All @@ -536,9 +629,12 @@ int block_setup(struct block *block)

void block_destroy(struct block *block)
{
debug("block_destroy");
map_destroy(block->config);
map_destroy(block->env);
free(block->name);
if (block->ticker)
ticker_destroy(block->ticker);
free(block);
}

Expand All @@ -551,6 +647,8 @@ struct block *block_create(struct bar *bar, const struct map *config)
if (!block)
return NULL;

block->ticker = NULL;

block->bar = bar;

block->config = map_create();
Expand Down
5 changes: 5 additions & 0 deletions block.h
Expand Up @@ -20,10 +20,12 @@
#define BLOCK_H

#include <sys/types.h>
#include <stdbool.h>

#include "bar.h"
#include "log.h"
#include "map.h"
#include "ticker.h"

#define INTERVAL_ONCE -1
#define INTERVAL_REPEAT -2
Expand Down Expand Up @@ -60,6 +62,8 @@ struct block {
int code;
pid_t pid;

struct ticker *ticker;

struct block *next;
};

Expand Down Expand Up @@ -107,6 +111,7 @@ int block_spawn(struct block *block);
void block_touch(struct block *block);
int block_reap(struct block *block);
int block_update(struct block *block);
void block_set_full_text_saved(struct block *block);
void block_close(struct block *block);

#endif /* BLOCK_H */
1 change: 1 addition & 0 deletions configure.ac
Expand Up @@ -7,6 +7,7 @@ PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
[BASH_COMPLETION_DIR="$(pkg-config --variable=completionsdir bash-completion)"],
[BASH_COMPLETION_DIR="$datadir/bash-completion/completions"]
)
PKG_CHECK_MODULES([UTF8PROC], [libutf8proc])
AC_SUBST([BASH_COMPLETION_DIR])
AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "xBASH_COMPLETION_DIR" != "x"])
AC_CONFIG_FILES([
Expand Down
47 changes: 47 additions & 0 deletions docs/README.adoc
Expand Up @@ -63,6 +63,16 @@ make
make install
----

=== Dependencies

Since ticker feature has been introduced, there is only one package (link:https://github.com/JuliaStrings/utf8proc[libutf8proc]) which is need to be installed. On Debian-based systems it can be obtained via apt:

[source]
----
sudo apt-get install libutf8proc-dev
----


== Getting started

In your i3 configuration file, define {progname} as the link:https://i3wm.org/docs/userguide.html#status_command[status line command] of a new bar block:
Expand Down Expand Up @@ -316,6 +326,43 @@ format=json
interval=1
----


=== ticker

Optional property. Enable or disable ticker feature. Valid values are `true` & `false`.
This feature only works with the raw format. It will scroll output string char by char with given interval. Offset zeroes if there are changes in the output string.
Default value is `false`.

[source,ini]
----
#Output string differs every minute
[ticker_test]
command=echo 'TEST_STRING-'$(date +%M)
interval=1
ticker=true
ticker_interval=2
----

==== ticker_delimeter

Optional property (use in conjunction with _ticker_). Delimeter character which separates beginning & ending of the output string. If value is set to a string containing multiple characters, only the first character will be used as the delimeter.
Default value is `|`.

==== ticker_direction

Direction of the ticker. Valid values are `right` (shortcut `r`) & `left` (shortcut `l`).
Default value is `left`.

==== ticker_chars_limit

Limit of the characters to be displayed if _ticker_ is enabled. `0` or negative values set limit to default value.
Default value is `16`.

==== ticker_interval

Optional property. Defines interval of time after which the output string is shifted by a single char.
Default value is `1`.

== Click

When you click on a block, data such as the button number and coordinates are merged into the block variables.
Expand Down

0 comments on commit 0a10f64

Please sign in to comment.