diff --git a/.gitignore b/.gitignore index d2e05475..c0ce76f5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ config.status configure i3blocks-config.h* stamp-h1 - +cscope.out diff --git a/Makefile.am b/Makefile.am index d72439c3..4f36e29c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ @@ -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 diff --git a/bar.c b/bar.c index 86681674..88b78068 100644 --- a/bar.c +++ b/bar.c @@ -1,6 +1,6 @@ /* * bar.c - status line handling functions - * Copyright (C) 2014-2019 Vivien Didelot + * Copyright (C) 2014-2023 Vivien Didelot, Bogdan Migunov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include #include #include +#include #include "bar.h" #include "block.h" @@ -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) { @@ -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"); @@ -106,6 +107,20 @@ 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->interval > block->ticker->interval) + block_set_full_text_saved(block); + + bar_print(bar); + } + } + block = block->next; } } @@ -148,11 +163,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); @@ -213,6 +229,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; } diff --git a/block.c b/block.c index 42965d15..62c757a8 100644 --- a/block.c +++ b/block.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include "bar.h" #include "block.h" @@ -26,6 +28,7 @@ #include "line.h" #include "log.h" #include "sys.h" +#include "ticker.h" const char *block_get(const struct block *block, const char *key) { @@ -113,8 +116,36 @@ 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 || + block->interval > block->ticker->interval) { + 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; @@ -148,6 +179,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; @@ -510,6 +571,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; } @@ -542,6 +636,8 @@ void block_destroy(struct block *block) map_destroy(block->env); if (block->name) free(block->name); + if (block->ticker) + ticker_destroy(block->ticker); free(block); } @@ -554,6 +650,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(); diff --git a/block.h b/block.h index a978ee3f..32c12507 100644 --- a/block.h +++ b/block.h @@ -1,6 +1,6 @@ /* * block.h - definition of a block - * Copyright (C) 2014-2019 Vivien Didelot + * Copyright (C) 2014-2023 Vivien Didelot, Bogdan Migunov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +20,12 @@ #define BLOCK_H #include +#include #include "bar.h" #include "log.h" #include "map.h" +#include "ticker.h" #define INTERVAL_ONCE -1 #define INTERVAL_REPEAT -2 @@ -60,6 +62,8 @@ struct block { int code; pid_t pid; + struct ticker *ticker; + struct block *next; }; @@ -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 */ diff --git a/configure.ac b/configure.ac index 1cab4a07..5db07297 100644 --- a/configure.ac +++ b/configure.ac @@ -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([ diff --git a/docs/README.adoc b/docs/README.adoc index bcf4ab8a..7f8a049d 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -65,6 +65,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: @@ -320,6 +330,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. diff --git a/docs/blocklets.html b/docs/blocklets.html index 09b04469..11cc619a 100644 --- a/docs/blocklets.html +++ b/docs/blocklets.html @@ -480,4 +480,4 @@

Blocklets

- \ No newline at end of file + diff --git a/docs/i3blocks.1 b/docs/i3blocks.1 index 032ab5b5..129ca26b 100644 --- a/docs/i3blocks.1 +++ b/docs/i3blocks.1 @@ -140,4 +140,4 @@ i3blocks is written by Vivien Didelot and other contributors. .SH "COPYING" .sp Copyright \(co Vivien Didelot. -Free use of this software is granted under the terms of the \fIGPLv3+\fP License. \ No newline at end of file +Free use of this software is granted under the terms of the \fIGPLv3+\fP License. diff --git a/docs/i3blocks.1.html b/docs/i3blocks.1.html index 285a8755..ac78c146 100644 --- a/docs/i3blocks.1.html +++ b/docs/i3blocks.1.html @@ -590,4 +590,4 @@

COPYING

- \ No newline at end of file + diff --git a/docs/index.html b/docs/index.html index 4289e46a..b10c3956 100644 --- a/docs/index.html +++ b/docs/index.html @@ -443,7 +443,11 @@

i3blocks

Table of Contents
  • Click
  • @@ -554,6 +559,17 @@

    Installation

    make install +
    +

    Dependencies

    +
    +

    Since ticker feature has been introduced, there is only one package (libutf8proc) which is need to be installed. On Debian-based systems it can be obtained via apt:

    +
    +
    +
    +
    sudo apt-get install libutf8proc-dev
    +
    +
    +
    @@ -926,6 +942,52 @@

    format

    +
    +

    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.

    +
    +
    +
    +
    #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.

    +
    +
    +
    @@ -1166,4 +1228,4 @@

    License

    - \ No newline at end of file + diff --git a/ticker.c b/ticker.c new file mode 100644 index 00000000..ef734cbf --- /dev/null +++ b/ticker.c @@ -0,0 +1,250 @@ +/* + * ticker.c - ticker implementation + * Copyright (C) 2022-2023 Bogdan Migunov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "ticker.h" +#include "log.h" +#include "sys.h" + +static enum ticker_result ticker_scroll(struct ticker *, char *); +static enum ticker_result ticker_convert_utf8_to_mbs(utf8proc_int32_t *, char *, + unsigned int); + +struct ticker *ticker_create(void) +{ + struct ticker *new_ticker = calloc(1, sizeof(struct ticker)); + int err; + + new_ticker->delimeter = TICKER_DELIMETER_DEFAULT; + new_ticker->direction = TICKER_DIRECTION_DEFAULT; + new_ticker->chars_limit = TICKER_CHARS_LIMIT_DEFAULT; + new_ticker->interval = TICKER_INTERVAL_DEFAULT; + + err = sys_gettime(&(new_ticker->timestamp)); + if (err) { + error("sys_gettime() error, code: %d", err); + free(new_ticker); + + return NULL; + } + + new_ticker->full_text_saved = NULL; + new_ticker->label_saved = NULL; + + memset(new_ticker->buf, '\0', sizeof(char) * BUFSIZ); + memset(new_ticker->utf8_buf, '\0', sizeof(utf8proc_int32_t) * UTF8_BUFSIZ); + new_ticker->utf8_buf_strlen = 0; + new_ticker->offset = 0; + + return new_ticker; +}; + +void ticker_destroy(struct ticker *ticker) +{ + debug("ticker_destroy()"); + free(ticker->full_text_saved); + free(ticker->label_saved); + free(ticker); + + return; +}; + +char *ticker_output_get(struct ticker *ticker, const char *full_text) +{ + char *ticker_output = calloc((ticker->chars_limit + 1) * sizeof(utf8proc_int32_t), + sizeof(char)); + + if (strcmp(ticker->buf, full_text) != 0) { + debug("New string"); + ticker->offset = 0; + + memset(ticker->buf, '\0', BUFSIZ * sizeof(char)); + memset(ticker->utf8_buf, '\0', sizeof(utf8proc_int32_t) * UTF8_BUFSIZ); + + snprintf(ticker->buf, sizeof(ticker->buf), "%s", full_text); + ticker->utf8_buf_strlen = + utf8proc_decompose((const utf8proc_uint8_t *)ticker->buf, 0, + ticker->utf8_buf, UTF8_BUFSIZ, UTF8PROC_NULLTERM); + if (ticker->utf8_buf_strlen < 0) { + error("Failed to decompose UTF8 multibyte string into an array of codepoints; error code: %d", + ticker->utf8_buf_strlen); + memset(ticker->buf, '\0', sizeof(char) * BUFSIZ); + memset(ticker->utf8_buf, '\0', + sizeof(utf8proc_int32_t) * UTF8_BUFSIZ); + free(ticker_output); + + return NULL; + } + debug("utf8_buf_strlen: %d", ticker->utf8_buf_strlen); + + *(ticker->utf8_buf + ticker->utf8_buf_strlen) = ' '; + *(ticker->utf8_buf + ticker->utf8_buf_strlen + 1) = ticker->delimeter; + *(ticker->utf8_buf + ticker->utf8_buf_strlen + 2) = ' '; + } + + if (ticker->utf8_buf_strlen <= ticker->chars_limit) { + debug("utf8_buf_strlen (%d) is less than chars_limit (%d)", + ticker->utf8_buf_strlen, ticker->chars_limit); + snprintf(ticker_output, BUFSIZ, "%s", full_text); + + return ticker_output; + } + + if (ticker_scroll(ticker, ticker_output) != TICKER_RESULT_SUCCESS) { + error("Failed to scroll string"); + memset(ticker->buf, '\0', sizeof(char) * BUFSIZ); + memset(ticker->utf8_buf, '\0', sizeof(utf8proc_int32_t) * UTF8_BUFSIZ); + free(ticker_output); + return NULL; + } + else { + debug("ticker_output: %s", ticker_output); + + return ticker_output; + } +}; + +enum ticker_result ticker_delimeter_set(struct ticker *ticker, + const char *delimeter) +{ + utf8proc_int32_t utf8_delimeter_str[UTF8_BUFSIZ]; + utf8proc_ssize_t utf8_delimeter_strlen = 0; + + memset(utf8_delimeter_str, '\0', sizeof(utf8proc_int32_t) * UTF8_BUFSIZ); + utf8_delimeter_strlen = + utf8proc_decompose((const utf8proc_uint8_t *)delimeter, 0, + utf8_delimeter_str, UTF8_BUFSIZ, UTF8PROC_NULLTERM); + + if (utf8_delimeter_strlen <= 0) { + if (utf8_delimeter_strlen != 0) + error("Failed to decompose UTF8 multibyte string; error code: %d", + utf8_delimeter_strlen); + else + error("Empty delimeter string"); + + return TICKER_RESULT_ERR; + } + + ticker->delimeter = utf8_delimeter_str[0]; + + return TICKER_RESULT_SUCCESS; +}; + +static enum ticker_result ticker_scroll(struct ticker *ticker, + char *ticker_output) +{ + utf8proc_int32_t utf8_output[UTF8_BUFSIZ]; + + memset(utf8_output, '\0', UTF8_BUFSIZ * sizeof(utf8proc_int32_t)); + debug("offset: %d", ticker->offset); + + if (ticker->direction == TICKER_DIRECTION_LEFT) + if (ticker->offset <= (ticker->utf8_buf_strlen + 3) - + ticker->chars_limit) + memcpy(utf8_output, ticker->utf8_buf + ticker->offset, + ticker->chars_limit * sizeof(utf8proc_int32_t)); + else { + memcpy(utf8_output, + ticker->utf8_buf + ticker->offset, + sizeof(utf8proc_int32_t) * ((ticker->utf8_buf_strlen + 3) - + ticker->offset)); + memcpy(utf8_output + ((ticker->utf8_buf_strlen + 3) - + ticker->offset), + ticker->utf8_buf, + sizeof(utf8proc_int32_t) * (ticker->chars_limit - + ((ticker->utf8_buf_strlen + 3) - ticker->offset))); + } + else + if (ticker->direction == TICKER_DIRECTION_RIGHT) { + if (ticker->offset < ticker->chars_limit) { + memcpy(utf8_output, + ticker->utf8_buf + (ticker->utf8_buf_strlen + 3) - + ticker->offset, + ticker->offset * sizeof(utf8proc_int32_t)); + memcpy(utf8_output + ticker->offset, + ticker->utf8_buf, + (ticker->chars_limit - ticker->offset) * + sizeof(utf8proc_int32_t)); + } + else + memcpy(utf8_output, + ticker->utf8_buf + (ticker->utf8_buf_strlen + 3) - + ticker->offset, + ticker->chars_limit * sizeof(utf8proc_int32_t)); + } + + if (ticker->interval > 0) { + int err; + unsigned long now; + const unsigned long next_update = ticker->timestamp + ticker->interval; + + err = sys_gettime(&now); + if (err) { + error("sys_gettime() error; code: %d", err); + + return TICKER_RESULT_ERR; + } + + if (((long) (next_update - now)) <= 0) { + debug("ticker expired: incrementing offset"); + + if (ticker->timestamp == now) { + debug("looping too fast"); + + return TICKER_RESULT_ERR; + } + + if (ticker->offset >= ticker->utf8_buf_strlen + 2) { + debug("Resetting offset"); + ticker->offset = 0; + } + else + ++(ticker->offset); + + ticker->timestamp = now; + } + } + + return ticker_convert_utf8_to_mbs(utf8_output, ticker_output, + ticker->chars_limit); +}; + +static enum ticker_result ticker_convert_utf8_to_mbs(utf8proc_int32_t *utf8_str, + char *mbs, unsigned int n) +{ + utf8proc_uint8_t utf8_codepoint[sizeof(utf8proc_int32_t)]; + + for (unsigned int i = 0; i < n; ++i) { + memset(utf8_codepoint, '\0', + sizeof(utf8proc_int32_t) * sizeof(utf8proc_uint8_t)); + + if (utf8proc_encode_char(*(utf8_str + i), utf8_codepoint)) + strncat(mbs, (const char *)utf8_codepoint, + sizeof(utf8proc_int32_t)); + else { + error("Failed to encode char %X", *(utf8_str + i)); + + return TICKER_RESULT_ERR; + } + } + + return TICKER_RESULT_SUCCESS; +}; diff --git a/ticker.h b/ticker.h new file mode 100644 index 00000000..12112094 --- /dev/null +++ b/ticker.h @@ -0,0 +1,67 @@ +/* + * ticker.h - definition of a ticker + * Copyright (C) 2022-2023 Bogdan Migunov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TICKER_H +#define TICKER_H + +#include +#include + +#define TICKER_CONFIG_OPTION "ticker" +#define TICKER_CONFIG_OPTION_DELIMETER "ticker_delimeter" +#define TICKER_CONFIG_OPTION_DIRECTION "ticker_direction" +#define TICKER_CONFIG_OPTION_CHARS_LIMIT "ticker_chars_limit" +#define TICKER_CONFIG_OPTION_INTERVAL "ticker_interval" + +#define TICKER_DELIMETER_DEFAULT '|' +#define TICKER_CHARS_LIMIT_DEFAULT 16 +#define TICKER_INTERVAL_DEFAULT 1 + +#define TICKER_DIRECTION_LEFT 0 +#define TICKER_DIRECTION_RIGHT 1 +#define TICKER_DIRECTION_DEFAULT TICKER_DIRECTION_LEFT + +#define UTF8_BUFSIZ ( BUFSIZ / sizeof(utf8proc_int32_t) ) + +struct ticker { + utf8proc_int32_t delimeter; + unsigned char direction; + unsigned int chars_limit; + + unsigned int interval; + unsigned long timestamp; + char *full_text_saved; + char *label_saved; + + char buf[BUFSIZ]; + utf8proc_int32_t utf8_buf[UTF8_BUFSIZ]; + utf8proc_ssize_t utf8_buf_strlen; + unsigned int offset; +}; + +enum ticker_result { + TICKER_RESULT_SUCCESS = 0, + TICKER_RESULT_ERR, +}; + +struct ticker *ticker_create(void); +void ticker_destroy(struct ticker *); +char *ticker_output_get(struct ticker *, const char *); +enum ticker_result ticker_delimeter_set(struct ticker *, const char *); + +#endif /* TICKER_H */