Compare commits

...

10 Commits

Author SHA1 Message Date
Mike Wilson
853324c8e3 Initial configuration 2025-09-25 15:42:25 -04:00
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
22 changed files with 199 additions and 287 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
INC_DIR := include
DEBUG := 0
VERBOSE := 0
LIBS := xcb-atom
@@ -26,6 +27,10 @@ ifeq ($(VERBOSE), 0)
Q := @
endif
ifeq ($(DEBUG), 1)
CFLAGS += -g
endif
all: $(BUILD_DIR)/$(BIN)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.h
@@ -33,7 +38,6 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c config.h
$(PRINTF) "CC" $@
$Q$(COMPILE.c) -o $@ $<
$(BUILD_DIR)/$(BIN): $(OBJS)
$(PRINTF) "LD" $@
$Q$(LINK.o) $^ $(LDLIBS) -o $@

158
README.md
View File

@@ -1,163 +1,19 @@
# dwmblocks-async
# dwmblocks-async - mike's build
A [`dwm`](https://dwm.suckless.org) status bar that has a modular, async
design, so it is always responsive. Imagine `i3blocks`, but for `dwm`.
![A lean config of dwmblocks-async.](preview.png)
## Features
- [Modular](#modifying-the-blocks)
- Lightweight
- [Suckless](https://suckless.org/philosophy)
- Blocks:
- [Clickable](#clickable-blocks)
- Loaded asynchronously
- [Updates can be externally triggered](#signalling-changes)
- Compatible with `i3blocks` scripts
> Additionally, this build of `dwmblocks` is more optimized and fixes the
> flickering of the status bar when scrolling.
## Why `dwmblocks`?
In `dwm`, you have to set the status bar through an infinite loop, like so:
```sh
while :; do
xsetroot -name "$(date)"
sleep 30
done
```
This is inefficient when running multiple commands that need to be updated at
different frequencies. For example, to display an unread mail count and a clock
in the status bar:
```sh
while :; do
xsetroot -name "$(mailCount) $(date)"
sleep 60
done
```
Both are executed at the same rate, which is wasteful. Ideally, the mail
counter would be updated every thirty minutes, since there's a limit to the
number of requests I can make using Gmail's APIs (as a free user).
`dwmblocks` allows you to divide the status bar into multiple blocks, each of
which can be updated at its own interval. This effectively addresses the
previous issue, because the commands in a block are only executed once within
that time frame.
## Why `dwmblocks-async`?
The magic of `dwmblocks-async` is in the `async` part. Since vanilla
`dwmblocks` executes the commands of each block sequentially, it leads to
annoying freezes. In cases where one block takes several seconds to execute,
like in the mail and date blocks example from above, the delay is clearly
visible. Fire up a new instance of `dwmblocks` and you'll see!
With `dwmblocks-async`, the computer executes each block asynchronously
(simultaneously).
This is a build/configuration of [dwmblocks-async](https://github.com/UtkarshVerma/dwmblocks-async). Vanilla [dwmblocks](https://github.com/torrinfail/dwmblocks) runs blocks sequentially, which means if one block freezes or simply takes a long time to load (for example, a weather block trying to pull from the internet when you don't have connection), all subsequent blocks have to wait on it.
## Installation
Clone this repository, modify `config.h` appropriately, then compile the
program:
```sh
git clone https://github.com/UtkarshVerma/dwmblocks-async.git
git clone https://git.mjwilson.org/mike/dwmblocks-async.git
cd dwmblocks-async
vi config.h
sudo make install
sudo make clean install
```
## Usage
To set `dwmblocks-async` as your status bar, you need to run it as a background
process on startup. One way is to add the following to `~/.xinitrc`:
```sh
# The binary of `dwmblocks-async` is named `dwmblocks`
Add dwmblocks (the binary is still called dwmblocks, **not** dwmblocks-async) to your ~/.xinitrc to run in the background at login/startup:
```sh ~/.xinitrc
dwmblocks &
exec dwm
```
### Modifying the blocks
You can define your status bar blocks in `config.h`:
```c
#define BLOCKS(X) \
...
X("volume", 0, 5), \
X("date", 1800, 1), \
...
```
Each block has the following properties:
| Property | Description |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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 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. |
Apart from defining the blocks, features can be toggled through `config.h`:
```c
// String used to delimit block outputs in the status.
#define DELIMITER " "
// Maximum number of Unicode characters that a block can output.
#define MAX_BLOCK_OUTPUT_LENGTH 45
// Control whether blocks are clickable.
#define CLICKABLE_BLOCKS 1
// Control whether a leading delimiter should be prepended to the status.
#define LEADING_DELIMITER 0
// Control whether a trailing delimiter should be appended to the status.
#define TRAILING_DELIMITER 0
```
### Signalling changes
Most status bars constantly rerun all scripts every few seconds. This is an
option here, but a superior choice is to give your block a signal through which
you can indicate it to update on relevant event, rather than have it rerun
idly.
For example, the volume block has the update signal `5` by default. I run
`kill -39 $(pidof dwmblocks)` alongside my volume shortcuts in `dwm` to only
update it when relevant. Just add `34` to your signal number! You could also
run `pkill -RTMIN+5 dwmblocks`, but it's slower.
To refresh all the blocks, run `kill -10 $(pidof dwmblocks)` or
`pkill -SIGUSR1 dwmblocks`.
> All blocks must have different signal numbers!
### Clickable blocks
Like `i3blocks`, this build allows you to build in additional actions into your
scripts in response to click events. You can check out
[my status bar scripts](https://github.com/UtkarshVerma/dotfiles/tree/main/.local/bin/statusbar)
as references for using the `$BLOCK_BUTTON` variable.
To use this feature, define the `CLICKABLE_BLOCKS` feature macro in your
`config.h`:
```c
#define CLICKABLE_BLOCKS 1
```
Apart from that, you need `dwm` to be patched with
[statuscmd](https://dwm.suckless.org/patches/statuscmd/).
## Credits
This work would not have been possible without
[Luke's build of dwmblocks](https://github.com/LukeSmithxyz/dwmblocks) and
[Daniel Bylinka's statuscmd patch](https://dwm.suckless.org/patches/statuscmd/).

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef CONFIG_H
#define CONFIG_H
// String used to delimit block outputs in the status.
#define DELIMITER " "
@@ -15,15 +16,8 @@
// Control whether a trailing delimiter should be appended to the status.
#define TRAILING_DELIMITER 0
// Define blocks for the status feed as X(cmd, interval, signal).
#define BLOCKS(X) \
X("sb-mail", 600, 1) \
X("sb-music", 0, 2) \
X("sb-disk", 1800, 3) \
X("sb-memory", 10, 4) \
X("sb-loadavg", 5, 5) \
X("sb-mic", 0, 6) \
X("sb-record", 0, 7) \
X("sb-volume", 0, 8) \
X("sb-battery", 5, 9) \
X("sb-date", 1, 10)
// Define blocks for the status feed as X(icon, cmd, interval, signal).
#define BLOCKS(X) \
X("", "date '+%H:%M:%S'", 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 <stdint.h>
#include <sys/types.h>
#include "config.h"
#include "util.h"
typedef struct {
const char *const icon;
const char *const command;
const unsigned int interval;
const int signal;
@@ -17,10 +19,11 @@ typedef struct {
pid_t fork_pid;
} block;
block block_new(const char *const command, const unsigned int interval,
const int signal);
block block_new(const char *const icon, const char *const command,
const unsigned int interval, const int signal);
int block_init(block *const block);
int block_deinit(block *const block);
int block_execute(block *const block, const uint8_t button);
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>
@@ -6,5 +7,6 @@ typedef struct {
bool is_debug_mode;
} cli_arguments;
int cli_init(cli_arguments* const args, const char* const argv[],
const int argc);
cli_arguments cli_parse_arguments(const char* const argv[], const int argc);
#endif // CLI_H

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef MAIN_H
#define MAIN_H
#include <signal.h>
@@ -11,3 +12,5 @@
#define X(...) "."
enum { BLOCK_COUNT = LEN(BLOCKS(X)) - 1 };
#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 "timer.h"
@@ -28,3 +29,5 @@ signal_handler signal_handler_new(
int signal_handler_init(signal_handler* const handler);
int signal_handler_deinit(signal_handler* const handler);
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>
@@ -26,3 +27,5 @@ status status_new(const block* const blocks, const unsigned short block_count);
bool status_update(status* const status);
int status_write(const status* const status, const bool is_debug_mode,
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 <stdbool.h>
#include "block.h"
@@ -14,3 +16,6 @@ typedef struct {
timer timer_new(const block *const blocks, const unsigned short block_count);
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>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define LEN(arr) (sizeof(arr) / sizeof(arr[0]))
#define BIT(n) (1 << (n))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
#define BIT(n) (1 << (n))
// NOLINTBEGIN(bugprone-macro-parentheses)
#define MEMBER_SIZE(type, member) sizeof(((type*)NULL)->member)
#define MEMBER_LENGTH(type, member) \
(MEMBER_SIZE(type, member) / MEMBER_SIZE(type, member[0]))
// NOLINTEND(bugprone-macro-parentheses)
#define UTF8_MAX_BYTE_COUNT 4
@@ -20,3 +24,5 @@ enum pipe_fd_index {
unsigned int gcd(unsigned int a, unsigned int b);
size_t truncate_utf8_string(char* const buffer, const size_t size,
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 <sys/poll.h>
#include "block.h"
#include "main.h"
typedef enum {
enum watcher_fd_index {
SIGNAL_FD = BLOCK_COUNT,
WATCHER_FD_COUNT,
} watcher_fd_index;
};
typedef struct pollfd watcher_fd;
typedef struct {
watcher_fd fds[WATCHER_FD_COUNT];
const block *const blocks;
const unsigned short block_count;
unsigned short active_blocks[BLOCK_COUNT];
unsigned short active_block_count;
bool got_signal;
} watcher;
watcher watcher_new(const block *const blocks,
const unsigned short block_count);
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);
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>
@@ -8,3 +9,5 @@ x11_connection* x11_connection_open(void);
void x11_connection_close(x11_connection* const connection);
int x11_set_root_name(x11_connection* const connection,
const char* const name);
#endif // X11_H

View File

@@ -1,9 +1,8 @@
#include "block.h"
#include <bits/stdint-uintn.h>
#include <bits/types/FILE.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,9 +13,10 @@
#include "config.h"
#include "util.h"
block block_new(const char *const command, const unsigned int interval,
const int signal) {
block block_new(const char *const icon, const char *const command,
const unsigned int interval, const int signal) {
block block = {
.icon = icon,
.command = command,
.interval = interval,
.signal = signal,
@@ -141,19 +141,7 @@ int block_update(block *const block) {
return 1;
}
(void)strcpy(block->output, buffer);
(void)strncpy(block->output, buffer, LEN(buffer));
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 <errno.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
int cli_init(cli_arguments *const args, const char *const argv[],
const int argc) {
args->is_debug_mode = false;
cli_arguments cli_parse_arguments(const char *const argv[], const int argc) {
errno = 0;
cli_arguments args = {
.is_debug_mode = false,
};
int opt = -1;
opterr = 0; // Suppress getopt's built-in invalid opt message
while ((opt = getopt(argc, (char *const *)argv, "dh")) != -1) {
switch (opt) {
case 'd':
args->is_debug_mode = true;
args.is_debug_mode = true;
break;
case 'h':
// fall through
case '?':
(void)fprintf(stderr, "error: unknown option `-%c'\n", optopt);
// fall through
case 'h':
// fall through
default:
(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 <errno.h>
#include <stdbool.h>
#include <stddef.h>
@@ -38,10 +39,10 @@ static int deinit_blocks(block *const blocks,
static int execute_blocks(block *const blocks,
const unsigned short block_count,
const unsigned int time) {
const timer *const timer) {
for (unsigned short i = 0; i < block_count; ++i) {
block *const block = &blocks[i];
if (!block_must_run(block, time)) {
if (!timer_must_run_block(timer, block)) {
continue;
}
@@ -55,7 +56,7 @@ static int execute_blocks(block *const blocks,
static int trigger_event(block *const blocks, const unsigned short block_count,
timer *const timer) {
if (execute_blocks(blocks, block_count, timer->time) != 0) {
if (execute_blocks(blocks, block_count, timer) != 0) {
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,
const unsigned short block_count) {
if (execute_blocks(blocks, block_count, 0) != 0) {
if (execute_blocks(blocks, block_count, NULL) != 0) {
return 1;
}
@@ -86,46 +87,30 @@ static int event_loop(block *const blocks, const unsigned short block_count,
return 1;
}
watcher watcher = watcher_new(blocks, block_count);
if (watcher_init(&watcher, signal_handler->fd) != 0) {
watcher watcher;
if (watcher_init(&watcher, blocks, block_count, signal_handler->fd) != 0) {
return 1;
}
status status = status_new(blocks, block_count);
bool is_alive = true;
while (is_alive) {
const int event_count = watcher_poll(&watcher, -1);
if (event_count == -1) {
if (watcher_poll(&watcher, -1) != 0) {
return 1;
}
int i = 0;
for (unsigned short j = 0; j < WATCHER_FD_COUNT; ++j) {
if (i == event_count) {
break;
}
if (watcher.got_signal) {
is_alive = signal_handler_process(signal_handler, &timer) == 0;
}
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;
continue;
}
block *const block = &blocks[j];
(void)block_update(block);
for (unsigned short i = 0; i < watcher.active_block_count; ++i) {
(void)block_update(&blocks[watcher.active_blocks[i]]);
}
const bool has_status_changed = status_update(&status);
if (has_status_changed) {
if (status_write(&status, is_debug_mode, connection) != 0) {
return 1;
}
if (has_status_changed &&
status_write(&status, is_debug_mode, connection) != 0) {
return 1;
}
}
@@ -133,8 +118,8 @@ static int event_loop(block *const blocks, const unsigned short block_count,
}
int main(const int argc, const char *const argv[]) {
cli_arguments cli_args;
if (cli_init(&cli_args, argv, argc) != 0) {
const cli_arguments cli_args = cli_parse_arguments(argv, argc);
if (errno != 0) {
return 1;
}
@@ -143,7 +128,8 @@ int main(const int argc, const char *const argv[]) {
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)};
#undef BLOCK
const unsigned short block_count = LEN(blocks);

View File

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

View File

@@ -6,6 +6,7 @@
#include "block.h"
#include "config.h"
#include "util.h"
#include "x11.h"
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) {
(void)strcpy(status->previous, status->current);
(void)strncpy(status->previous, status->current, LEN(status->current));
status->current[0] = '\0';
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 LEADING_DELIMITER
(void)strcat(status->current, DELIMITER);
(void)strncat(status->current, DELIMITER, LEN(DELIMITER));
#else
if (status->current[0] != '\0') {
(void)strcat(status->current, DELIMITER);
(void)strncat(status->current, DELIMITER, LEN(DELIMITER));
}
#endif
#if CLICKABLE_BLOCKS
if (block->signal > 0) {
const char signal[] = {(char)block->signal, '\0'};
(void)strcat(status->current, signal);
(void)strncat(status->current, signal, LEN(signal));
}
#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 (status->current[0] != '\0') {
(void)strcat(status->current, DELIMITER);
(void)strncat(status->current, DELIMITER, LEN(DELIMITER));
}
#endif

View File

@@ -1,6 +1,7 @@
#include "timer.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.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) {
const unsigned int reset_value = compute_reset_value(blocks, block_count);
timer timer = {
.time = 0,
.time = reset_value, // Initial value to execute all blocks.
.tick = compute_tick(blocks, block_count),
.reset_value = compute_reset_value(blocks, block_count),
.reset_value = reset_value,
};
return timer;
@@ -51,7 +54,19 @@ int timer_arm(timer *const timer) {
}
// 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;
}
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

@@ -24,7 +24,7 @@ size_t truncate_utf8_string(char* const buffer, const size_t size,
unsigned short skip = 1;
// Multibyte unicode character
// Multibyte unicode character.
if ((ch & UTF8_MULTIBYTE_BIT) != 0) {
// Skip continuation bytes.
ch <<= 1;

View File

@@ -1,27 +1,23 @@
#include "watcher.h"
#include <errno.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/poll.h>
#include "block.h"
#include "util.h"
watcher watcher_new(const block* const blocks,
const unsigned short block_count) {
watcher watcher = {
.blocks = blocks,
.block_count = block_count,
};
return watcher;
static bool watcher_fd_is_readable(const watcher_fd* const watcher_fd) {
return (watcher_fd->revents & POLLIN) != 0;
}
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) {
fprintf(stderr,
"error: invalid signal file descriptor passed to watcher\n");
(void)fprintf(
stderr,
"error: invalid signal file descriptor passed to watcher\n");
return 1;
}
@@ -29,10 +25,10 @@ int watcher_init(watcher* const watcher, const int signal_fd) {
fd->fd = signal_fd;
fd->events = POLLIN;
for (unsigned short i = 0; i < watcher->block_count; ++i) {
const int block_fd = watcher->blocks[i].pipe[READ_END];
for (unsigned short i = 0; i < block_count; ++i) {
const int block_fd = blocks[i].pipe[READ_END];
if (block_fd == -1) {
fprintf(
(void)fprintf(
stderr,
"error: invalid block file descriptors passed to watcher\n");
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) {
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.
if (event_count == -1 && errno != EINTR) {
(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]);
bool watcher_fd_is_readable(const watcher_fd* const watcher_fd) {
return (watcher_fd->revents & POLLIN) != 0;
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;
}
++j;
}
return 0;
}

View File

@@ -8,7 +8,7 @@
x11_connection *x11_connection_open(void) {
xcb_connection_t *const connection = xcb_connect(NULL, NULL);
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;
}