Compare commits

...

10 Commits

Author SHA1 Message Date
Utkarsh Verma
fe538a7a2f feat: Add support for block-specific icons
Icons can now be specified on a per-block basis. Closes #64.
2024-04-20 08:49:01 +05:30
Utkarsh Verma
8ebe985db8 fix: Ensure that all blocks execute on SIGUSR1. (closes #63) 2024-03-19 06:53:49 +05:30
Utkarsh Verma
dea248b824 build: Add DEBUG option 2024-03-19 06:52:21 +05:30
Utkarsh Verma
12d4decdd4 fix: Fix timer logic for blocks 2023-12-19 09:51:41 +05:30
Utkarsh Verma
c42a4215c8 tidy: Remove unnecessary newline from Makefile 2023-11-22 20:41:12 +05:30
Luca Bilke
56e6e2ef64 fix: Rename headers to allow compilation against musl libc
tidy: Format includes
2023-11-22 20:38:55 +05:30
Utkarsh Verma
5f45160b65 fix: Fix command-line argument parsing order 2023-11-22 15:41:31 +05:30
Utkarsh Verma
df76bd50f2 fix: Remove invalid strcat invocation for TRAILING_DELIMITER
Fixes #51
2023-11-20 15:02:27 +05:30
Utkarsh Verma
c166ffe0b4 refactor: Add clang-tidy checks and simplify codebase 2023-11-16 11:01:07 +05:30
Utkarsh Verma
f18100c2ee tidy: Remove unused include 2023-11-01 15:44:24 +05:30
22 changed files with 204 additions and 139 deletions

30
.clang-tidy Normal file
View File

@@ -0,0 +1,30 @@
Checks: |
-*,
abseil-*,
bugprone-*,
clang-analyzer-*,
misc-*,
modernize-*,
performance-*,
portability-*,
readability-*,
llvm-*,
-bugprone-easily-swappable-parameters,
-readability-avoid-const-params-in-decls,
-readability-identifier-length
CheckOptions:
- key: readability-inconsistent-declaration-parameter-name.Strict
value: true
- key: readability-identifier-naming.StructCase
value: lower_case
- key: readability-identifier-naming.FunctionCase
value: lower_case
- key: readability-identifier-naming.VariableCase
value: lower_case
- key: readability-identifier-naming.EnumConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.MacroDefinitionCase
value: UPPER_CASE
- key: readability-function-cognitive-complexity.Threshold
value: 15

View File

@@ -5,6 +5,7 @@ BUILD_DIR := build
SRC_DIR := src SRC_DIR := src
INC_DIR := include INC_DIR := include
DEBUG := 0
VERBOSE := 0 VERBOSE := 0
LIBS := xcb-atom LIBS := xcb-atom
@@ -26,6 +27,10 @@ ifeq ($(VERBOSE), 0)
Q := @ Q := @
endif endif
ifeq ($(DEBUG), 1)
CFLAGS += -g
endif
all: $(BUILD_DIR)/$(BIN) all: $(BUILD_DIR)/$(BIN)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.h $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.h
@@ -33,7 +38,6 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.h
$(PRINTF) "CC" $@ $(PRINTF) "CC" $@
$Q$(COMPILE.c) -o $@ $< $Q$(COMPILE.c) -o $@ $<
$(BUILD_DIR)/$(BIN): $(OBJS) $(BUILD_DIR)/$(BIN): $(OBJS)
$(PRINTF) "LD" $@ $(PRINTF) "LD" $@
$Q$(LINK.o) $^ $(LDLIBS) -o $@ $Q$(LINK.o) $^ $(LDLIBS) -o $@

View File

@@ -90,8 +90,8 @@ You can define your status bar blocks in `config.h`:
```c ```c
#define BLOCKS(X) \ #define BLOCKS(X) \
... ...
X("volume", 0, 5), \ X("", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -d' ' -f2", 0, 5) \
X("date", 1800, 1), \ X("󰥔 ", "date '+%H:%M:%S'", 1, 1) \
... ...
``` ```
@@ -99,6 +99,7 @@ Each block has the following properties:
| Property | Description | | Property | Description |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Icon | An icon you wish to prepend to your block output. |
| Command | The command you wish to execute in your block. | | Command | The command you wish to execute in your block. |
| Update interval | Time in seconds, after which you want the block to update. If `0`, the block will never be updated. | | Update interval | Time in seconds, after which you want the block to update. If `0`, the block will never be updated. |
| Update signal | Signal to be used for triggering the block. Must be a positive integer. If `0`, a signal won't be set up for the block and it will be unclickable. | | Update signal | Signal to be used for triggering the block. Must be a positive integer. If `0`, a signal won't be set up for the block and it will be unclickable. |

View File

@@ -1,4 +1,5 @@
#pragma once #ifndef CONFIG_H
#define CONFIG_H
// String used to delimit block outputs in the status. // String used to delimit block outputs in the status.
#define DELIMITER " " #define DELIMITER " "
@@ -15,15 +16,17 @@
// Control whether a trailing delimiter should be appended to the status. // Control whether a trailing delimiter should be appended to the status.
#define TRAILING_DELIMITER 0 #define TRAILING_DELIMITER 0
// Define blocks for the status feed as X(cmd, interval, signal). // Define blocks for the status feed as X(icon, cmd, interval, signal).
#define BLOCKS(X) \ #define BLOCKS(X) \
X("sb-mail", 600, 1) \ X("", "sb-mail", 600, 1) \
X("sb-music", 0, 2) \ X("", "sb-music", 0, 2) \
X("sb-disk", 1800, 3) \ X("", "sb-disk", 1800, 3) \
X("sb-memory", 10, 4) \ X("", "sb-memory", 10, 4) \
X("sb-loadavg", 5, 5) \ X("", "sb-loadavg", 5, 5) \
X("sb-mic", 0, 6) \ X("", "sb-mic", 0, 6) \
X("sb-record", 0, 7) \ X("", "sb-record", 0, 7) \
X("sb-volume", 0, 8) \ X("", "sb-volume", 0, 8) \
X("sb-battery", 5, 9) \ X("", "sb-battery", 5, 9) \
X("sb-date", 1, 10) X("", "sb-date", 1, 10)
#endif // CONFIG_H

View File

@@ -1,13 +1,15 @@
#pragma once #ifndef BLOCK_H
#define BLOCK_H
#include <bits/stdint-uintn.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
typedef struct { typedef struct {
const char *const icon;
const char *const command; const char *const command;
const unsigned int interval; const unsigned int interval;
const int signal; const int signal;
@@ -17,10 +19,11 @@ typedef struct {
pid_t fork_pid; pid_t fork_pid;
} block; } block;
block block_new(const char *const command, const unsigned int interval, block block_new(const char *const icon, const char *const command,
const int signal); const unsigned int interval, const int signal);
int block_init(block *const block); int block_init(block *const block);
int block_deinit(block *const block); int block_deinit(block *const block);
int block_execute(block *const block, const uint8_t button); int block_execute(block *const block, const uint8_t button);
int block_update(block *const block); int block_update(block *const block);
bool block_must_run(const block *const block, const unsigned int time);
#endif // BLOCK_H

View File

@@ -1,4 +1,5 @@
#pragma once #ifndef CLI_H
#define CLI_H
#include <stdbool.h> #include <stdbool.h>
@@ -6,5 +7,6 @@ typedef struct {
bool is_debug_mode; bool is_debug_mode;
} cli_arguments; } cli_arguments;
int cli_init(cli_arguments* const args, const char* const argv[], cli_arguments cli_parse_arguments(const char* const argv[], const int argc);
const int argc);
#endif // CLI_H

View File

@@ -1,4 +1,5 @@
#pragma once #ifndef MAIN_H
#define MAIN_H
#include <signal.h> #include <signal.h>
@@ -11,3 +12,5 @@
#define X(...) "." #define X(...) "."
enum { BLOCK_COUNT = LEN(BLOCKS(X)) - 1 }; enum { BLOCK_COUNT = LEN(BLOCKS(X)) - 1 };
#undef X #undef X
#endif // MAIN_H

View File

@@ -1,6 +1,7 @@
#pragma once #ifndef SIGNAL_HANDLER_H
#define SIGNAL_HANDLER_H
#include <bits/types/sigset_t.h> #include <signal.h>
#include "block.h" #include "block.h"
#include "timer.h" #include "timer.h"
@@ -28,3 +29,5 @@ signal_handler signal_handler_new(
int signal_handler_init(signal_handler* const handler); int signal_handler_init(signal_handler* const handler);
int signal_handler_deinit(signal_handler* const handler); int signal_handler_deinit(signal_handler* const handler);
int signal_handler_process(signal_handler* const handler, timer* const timer); int signal_handler_process(signal_handler* const handler, timer* const timer);
#endif // SIGNAL_HANDLER_H

View File

@@ -1,4 +1,5 @@
#pragma once #ifndef STATUS_H
#define STATUS_H
#include <stdbool.h> #include <stdbool.h>
@@ -26,3 +27,5 @@ status status_new(const block* const blocks, const unsigned short block_count);
bool status_update(status* const status); bool status_update(status* const status);
int status_write(const status* const status, const bool is_debug_mode, int status_write(const status* const status, const bool is_debug_mode,
x11_connection* const connection); x11_connection* const connection);
#endif // STATUS_H

View File

@@ -1,6 +1,8 @@
#pragma once #ifndef TIMER_H
#define TIMER_H
#include <signal.h> #include <signal.h>
#include <stdbool.h>
#include "block.h" #include "block.h"
@@ -14,3 +16,6 @@ typedef struct {
timer timer_new(const block *const blocks, const unsigned short block_count); timer timer_new(const block *const blocks, const unsigned short block_count);
int timer_arm(timer *const timer); int timer_arm(timer *const timer);
bool timer_must_run_block(const timer *const timer, const block *const block);
#endif // TIMER_H

View File

@@ -1,13 +1,17 @@
#pragma once #ifndef UTIL_H
#define UTIL_H
#include <stddef.h> #include <stddef.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b))
#define LEN(arr) (sizeof(arr) / sizeof(arr[0])) #define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
#define BIT(n) (1 << (n)) #define BIT(n) (1 << (n))
// NOLINTBEGIN(bugprone-macro-parentheses)
#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member) #define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member)
#define MEMBER_LENGTH(type, member) \ #define MEMBER_LENGTH(type, member) \
(MEMBER_SIZE(type, member) / MEMBER_SIZE(type, member[0])) (MEMBER_SIZE(type, member) / MEMBER_SIZE(type, member[0]))
// NOLINTEND(bugprone-macro-parentheses)
#define UTF8_MAX_BYTE_COUNT 4 #define UTF8_MAX_BYTE_COUNT 4
@@ -20,3 +24,5 @@ enum pipe_fd_index {
unsigned int gcd(unsigned int a, unsigned int b); unsigned int gcd(unsigned int a, unsigned int b);
size_t truncate_utf8_string(char* const buffer, const size_t size, size_t truncate_utf8_string(char* const buffer, const size_t size,
const size_t char_limit); const size_t char_limit);
#endif // UTIL_H

View File

@@ -1,27 +1,28 @@
#pragma once #ifndef WATCHER_H
#define WATCHER_H
#include <poll.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/poll.h>
#include "block.h" #include "block.h"
#include "main.h" #include "main.h"
typedef enum { enum watcher_fd_index {
SIGNAL_FD = BLOCK_COUNT, SIGNAL_FD = BLOCK_COUNT,
WATCHER_FD_COUNT, WATCHER_FD_COUNT,
} watcher_fd_index; };
typedef struct pollfd watcher_fd; typedef struct pollfd watcher_fd;
typedef struct { typedef struct {
watcher_fd fds[WATCHER_FD_COUNT]; watcher_fd fds[WATCHER_FD_COUNT];
unsigned short active_blocks[BLOCK_COUNT];
const block *const blocks; unsigned short active_block_count;
const unsigned short block_count; bool got_signal;
} watcher; } watcher;
watcher watcher_new(const block *const blocks, int watcher_init(watcher *const watcher, const block *const blocks,
const unsigned short block_count); const unsigned short block_count, const int signal_fd);
int watcher_init(watcher *const watcher, const int signal_fd);
int watcher_poll(watcher *const watcher, const int timeout_ms); int watcher_poll(watcher *const watcher, const int timeout_ms);
bool watcher_fd_is_readable(const watcher_fd *const watcher_fd);
#endif // WATCHER_H

View File

@@ -1,4 +1,5 @@
#pragma once #ifndef X11_H
#define X11_H
#include <xcb/xcb.h> #include <xcb/xcb.h>
@@ -8,3 +9,5 @@ x11_connection* x11_connection_open(void);
void x11_connection_close(x11_connection* const connection); void x11_connection_close(x11_connection* const connection);
int x11_set_root_name(x11_connection* const connection, int x11_set_root_name(x11_connection* const connection,
const char* const name); const char* const name);
#endif // X11_H

View File

@@ -1,9 +1,8 @@
#include "block.h" #include "block.h"
#include <bits/stdint-uintn.h>
#include <bits/types/FILE.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -14,9 +13,10 @@
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
block block_new(const char *const command, const unsigned int interval, block block_new(const char *const icon, const char *const command,
const int signal) { const unsigned int interval, const int signal) {
block block = { block block = {
.icon = icon,
.command = command, .command = command,
.interval = interval, .interval = interval,
.signal = signal, .signal = signal,
@@ -141,19 +141,7 @@ int block_update(block *const block) {
return 1; return 1;
} }
(void)strcpy(block->output, buffer); (void)strncpy(block->output, buffer, LEN(buffer));
return 0; return 0;
} }
bool block_must_run(const block *const block, const unsigned int time) {
if (time == 0) {
return true;
}
if (block->interval == 0) {
return false;
}
return time % block->interval == 0;
}

View File

@@ -1,30 +1,33 @@
#include "cli.h" #include "cli.h"
#include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
int cli_init(cli_arguments *const args, const char *const argv[], cli_arguments cli_parse_arguments(const char *const argv[], const int argc) {
const int argc) { errno = 0;
args->is_debug_mode = false; cli_arguments args = {
.is_debug_mode = false,
};
int opt = -1; int opt = -1;
opterr = 0; // Suppress getopt's built-in invalid opt message opterr = 0; // Suppress getopt's built-in invalid opt message
while ((opt = getopt(argc, (char *const *)argv, "dh")) != -1) { while ((opt = getopt(argc, (char *const *)argv, "dh")) != -1) {
switch (opt) { switch (opt) {
case 'd': case 'd':
args->is_debug_mode = true; args.is_debug_mode = true;
break; break;
case 'h':
// fall through
case '?': case '?':
(void)fprintf(stderr, "error: unknown option `-%c'\n", optopt); (void)fprintf(stderr, "error: unknown option `-%c'\n", optopt);
// fall through // fall through
case 'h':
// fall through
default: default:
(void)fprintf(stderr, "usage: %s [-d]\n", BINARY); (void)fprintf(stderr, "usage: %s [-d]\n", BINARY);
return 1; errno = 1;
} }
} }
return 0; return args;
} }

View File

@@ -1,5 +1,6 @@
#include "main.h" #include "main.h"
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@@ -38,10 +39,10 @@ static int deinit_blocks(block *const blocks,
static int execute_blocks(block *const blocks, static int execute_blocks(block *const blocks,
const unsigned short block_count, const unsigned short block_count,
const unsigned int time) { const timer *const timer) {
for (unsigned short i = 0; i < block_count; ++i) { for (unsigned short i = 0; i < block_count; ++i) {
block *const block = &blocks[i]; block *const block = &blocks[i];
if (!block_must_run(block, time)) { if (!timer_must_run_block(timer, block)) {
continue; continue;
} }
@@ -55,7 +56,7 @@ static int execute_blocks(block *const blocks,
static int trigger_event(block *const blocks, const unsigned short block_count, static int trigger_event(block *const blocks, const unsigned short block_count,
timer *const timer) { timer *const timer) {
if (execute_blocks(blocks, block_count, timer->time) != 0) { if (execute_blocks(blocks, block_count, timer) != 0) {
return 1; return 1;
} }
@@ -68,7 +69,7 @@ static int trigger_event(block *const blocks, const unsigned short block_count,
static int refresh_callback(block *const blocks, static int refresh_callback(block *const blocks,
const unsigned short block_count) { const unsigned short block_count) {
if (execute_blocks(blocks, block_count, 0) != 0) { if (execute_blocks(blocks, block_count, NULL) != 0) {
return 1; return 1;
} }
@@ -86,55 +87,39 @@ static int event_loop(block *const blocks, const unsigned short block_count,
return 1; return 1;
} }
watcher watcher = watcher_new(blocks, block_count); watcher watcher;
if (watcher_init(&watcher, signal_handler->fd) != 0) { if (watcher_init(&watcher, blocks, block_count, signal_handler->fd) != 0) {
return 1; return 1;
} }
status status = status_new(blocks, block_count); status status = status_new(blocks, block_count);
bool is_alive = true; bool is_alive = true;
while (is_alive) { while (is_alive) {
const int event_count = watcher_poll(&watcher, -1); if (watcher_poll(&watcher, -1) != 0) {
if (event_count == -1) {
return 1; return 1;
} }
int i = 0; if (watcher.got_signal) {
for (unsigned short j = 0; j < WATCHER_FD_COUNT; ++j) {
if (i == event_count) {
break;
}
const watcher_fd *const watcher_fd = &watcher.fds[j];
if (!watcher_fd_is_readable(watcher_fd)) {
continue;
}
++i;
if (j == SIGNAL_FD) {
is_alive = signal_handler_process(signal_handler, &timer) == 0; is_alive = signal_handler_process(signal_handler, &timer) == 0;
continue;
} }
block *const block = &blocks[j]; for (unsigned short i = 0; i < watcher.active_block_count; ++i) {
(void)block_update(block); (void)block_update(&blocks[watcher.active_blocks[i]]);
} }
const bool has_status_changed = status_update(&status); const bool has_status_changed = status_update(&status);
if (has_status_changed) { if (has_status_changed &&
if (status_write(&status, is_debug_mode, connection) != 0) { status_write(&status, is_debug_mode, connection) != 0) {
return 1; return 1;
} }
} }
}
return 0; return 0;
} }
int main(const int argc, const char *const argv[]) { int main(const int argc, const char *const argv[]) {
cli_arguments cli_args; const cli_arguments cli_args = cli_parse_arguments(argv, argc);
if (cli_init(&cli_args, argv, argc) != 0) { if (errno != 0) {
return 1; return 1;
} }
@@ -143,7 +128,8 @@ int main(const int argc, const char *const argv[]) {
return 1; return 1;
} }
#define BLOCK(command, interval, signal) block_new(command, interval, signal), #define BLOCK(icon, command, interval, signal) \
block_new(icon, command, interval, signal),
block blocks[BLOCK_COUNT] = {BLOCKS(BLOCK)}; block blocks[BLOCK_COUNT] = {BLOCKS(BLOCK)};
#undef BLOCK #undef BLOCK
const unsigned short block_count = LEN(blocks); const unsigned short block_count = LEN(blocks);

View File

@@ -1,8 +1,7 @@
#include "signal-handler.h" #include "signal-handler.h"
#include <bits/stdint-uintn.h>
#include <bits/types/sigset_t.h>
#include <signal.h> #include <signal.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <sys/types.h> #include <sys/types.h>

View File

@@ -6,6 +6,7 @@
#include "block.h" #include "block.h"
#include "config.h" #include "config.h"
#include "util.h"
#include "x11.h" #include "x11.h"
static bool has_status_changed(const status *const status) { static bool has_status_changed(const status *const status) {
@@ -26,7 +27,7 @@ status status_new(const block *const blocks,
} }
bool status_update(status *const status) { bool status_update(status *const status) {
(void)strcpy(status->previous, status->current); (void)strncpy(status->previous, status->current, LEN(status->current));
status->current[0] = '\0'; status->current[0] = '\0';
for (unsigned short i = 0; i < status->block_count; ++i) { for (unsigned short i = 0; i < status->block_count; ++i) {
@@ -34,27 +35,28 @@ bool status_update(status *const status) {
if (strlen(block->output) > 0) { if (strlen(block->output) > 0) {
#if LEADING_DELIMITER #if LEADING_DELIMITER
(void)strcat(status->current, DELIMITER); (void)strncat(status->current, DELIMITER, LEN(DELIMITER));
#else #else
if (status->current[0] != '\0') { if (status->current[0] != '\0') {
(void)strcat(status->current, DELIMITER); (void)strncat(status->current, DELIMITER, LEN(DELIMITER));
} }
#endif #endif
#if CLICKABLE_BLOCKS #if CLICKABLE_BLOCKS
if (block->signal > 0) { if (block->signal > 0) {
const char signal[] = {(char)block->signal, '\0'}; const char signal[] = {(char)block->signal, '\0'};
(void)strcat(status->current, signal); (void)strncat(status->current, signal, LEN(signal));
} }
#endif #endif
(void)strcat(status->current, block->output); (void)strncat(status->current, block->icon, LEN(block->output));
(void)strncat(status->current, block->output, LEN(block->output));
} }
} }
#if TRAILING_DELIMITER #if TRAILING_DELIMITER
if (status->current[0] != '\0') { if (status->current[0] != '\0') {
(void)strcat(status->current, DELIMITER); (void)strncat(status->current, DELIMITER, LEN(DELIMITER));
} }
#endif #endif

View File

@@ -1,6 +1,7 @@
#include "timer.h" #include "timer.h"
#include <errno.h> #include <errno.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@@ -32,10 +33,12 @@ static unsigned int compute_reset_value(const block *const blocks,
} }
timer timer_new(const block *const blocks, const unsigned short block_count) { timer timer_new(const block *const blocks, const unsigned short block_count) {
const unsigned int reset_value = compute_reset_value(blocks, block_count);
timer timer = { timer timer = {
.time = 0, .time = reset_value, // Initial value to execute all blocks.
.tick = compute_tick(blocks, block_count), .tick = compute_tick(blocks, block_count),
.reset_value = compute_reset_value(blocks, block_count), .reset_value = reset_value,
}; };
return timer; return timer;
@@ -51,7 +54,19 @@ int timer_arm(timer *const timer) {
} }
// Wrap `time` to the interval [1, reset_value]. // Wrap `time` to the interval [1, reset_value].
timer->time = (timer->time + timer->tick) % timer->reset_value + 1; timer->time = (timer->time + timer->tick) % timer->reset_value;
return 0; return 0;
} }
bool timer_must_run_block(const timer *const timer, const block *const block) {
if (timer == NULL || timer->time == timer->reset_value) {
return true;
}
if (block->interval == 0) {
return false;
}
return timer->time % block->interval == 0;
}

View File

@@ -1,6 +1,5 @@
#include "util.h" #include "util.h"
#include <stdio.h>
#define UTF8_MULTIBYTE_BIT BIT(7) #define UTF8_MULTIBYTE_BIT BIT(7)
unsigned int gcd(unsigned int a, unsigned int b) { unsigned int gcd(unsigned int a, unsigned int b) {
@@ -25,7 +24,7 @@ size_t truncate_utf8_string(char* const buffer, const size_t size,
unsigned short skip = 1; unsigned short skip = 1;
// Multibyte unicode character // Multibyte unicode character.
if ((ch & UTF8_MULTIBYTE_BIT) != 0) { if ((ch & UTF8_MULTIBYTE_BIT) != 0) {
// Skip continuation bytes. // Skip continuation bytes.
ch <<= 1; ch <<= 1;

View File

@@ -1,26 +1,22 @@
#include "watcher.h" #include "watcher.h"
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <sys/poll.h>
#include "block.h" #include "block.h"
#include "util.h" #include "util.h"
watcher watcher_new(const block* const blocks, static bool watcher_fd_is_readable(const watcher_fd* const watcher_fd) {
const unsigned short block_count) { return (watcher_fd->revents & POLLIN) != 0;
watcher watcher = {
.blocks = blocks,
.block_count = block_count,
};
return watcher;
} }
int watcher_init(watcher* const watcher, const int signal_fd) { int watcher_init(watcher* const watcher, const block* const blocks,
const unsigned short block_count, const int signal_fd) {
if (signal_fd == -1) { if (signal_fd == -1) {
fprintf(stderr, (void)fprintf(
stderr,
"error: invalid signal file descriptor passed to watcher\n"); "error: invalid signal file descriptor passed to watcher\n");
return 1; return 1;
} }
@@ -29,10 +25,10 @@ int watcher_init(watcher* const watcher, const int signal_fd) {
fd->fd = signal_fd; fd->fd = signal_fd;
fd->events = POLLIN; fd->events = POLLIN;
for (unsigned short i = 0; i < watcher->block_count; ++i) { for (unsigned short i = 0; i < block_count; ++i) {
const int block_fd = watcher->blocks[i].pipe[READ_END]; const int block_fd = blocks[i].pipe[READ_END];
if (block_fd == -1) { if (block_fd == -1) {
fprintf( (void)fprintf(
stderr, stderr,
"error: invalid block file descriptors passed to watcher\n"); "error: invalid block file descriptors passed to watcher\n");
return 1; return 1;
@@ -47,17 +43,27 @@ int watcher_init(watcher* const watcher, const int signal_fd) {
} }
int watcher_poll(watcher* watcher, const int timeout_ms) { int watcher_poll(watcher* watcher, const int timeout_ms) {
const int event_count = poll(watcher->fds, LEN(watcher->fds), timeout_ms); int event_count = poll(watcher->fds, LEN(watcher->fds), timeout_ms);
// Don't return non-zero status for signal interruptions. // Don't return non-zero status for signal interruptions.
if (event_count == -1 && errno != EINTR) { if (event_count == -1 && errno != EINTR) {
(void)fprintf(stderr, "error: watcher could not poll blocks\n"); (void)fprintf(stderr, "error: watcher could not poll blocks\n");
return -1; return 1;
} }
return event_count; watcher->got_signal = watcher_fd_is_readable(&watcher->fds[SIGNAL_FD]);
watcher->active_block_count = event_count - (int)watcher->got_signal;
unsigned short i = 0;
unsigned short j = 0;
while (i < event_count && j < LEN(watcher->active_blocks)) {
if (watcher_fd_is_readable(&watcher->fds[j])) {
watcher->active_blocks[i] = j;
++i;
} }
bool watcher_fd_is_readable(const watcher_fd* const watcher_fd) { ++j;
return (watcher_fd->revents & POLLIN) != 0; }
return 0;
} }

View File

@@ -8,7 +8,7 @@
x11_connection *x11_connection_open(void) { x11_connection *x11_connection_open(void) {
xcb_connection_t *const connection = xcb_connect(NULL, NULL); xcb_connection_t *const connection = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(connection)) { if (xcb_connection_has_error(connection)) {
(void)fprintf(stderr, "error: could not connect to the X server\n"); (void)fprintf(stderr, "error: could not connect to X server\n");
return NULL; return NULL;
} }