Compare commits
10 Commits
f18100c2ee
...
853324c8e3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
853324c8e3 | ||
|
|
fe538a7a2f | ||
|
|
8ebe985db8 | ||
|
|
dea248b824 | ||
|
|
12d4decdd4 | ||
|
|
c42a4215c8 | ||
|
|
56e6e2ef64 | ||
|
|
5f45160b65 | ||
|
|
df76bd50f2 | ||
|
|
c166ffe0b4 |
30
.clang-tidy
Normal file
30
.clang-tidy
Normal 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
|
||||
6
Makefile
6
Makefile
@@ -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
158
README.md
@@ -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`.
|
||||
|
||||

|
||||
|
||||
## 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/).
|
||||
|
||||
20
config.h
20
config.h
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
22
src/block.c
22
src/block.c
@@ -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;
|
||||
}
|
||||
|
||||
19
src/cli.c
19
src/cli.c
@@ -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;
|
||||
}
|
||||
|
||||
54
src/main.c
54
src/main.c
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
14
src/status.c
14
src/status.c
@@ -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
|
||||
|
||||
|
||||
21
src/timer.c
21
src/timer.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user