Compare commits

..

No commits in common. "master" and "releases/1.10" have entirely different histories.

103 changed files with 3269 additions and 4106 deletions

View file

@ -3,7 +3,6 @@ BasedOnStyle: GNU
IndentWidth: 4
---
Language: Cpp
Standard: Auto
PointerAlignment: Right
ColumnLimit: 120
BreakBeforeBraces: Custom
@ -16,9 +15,3 @@ BraceWrapping:
SpaceBeforeParens: ControlStatements
Cpp11BracedListStyle: true
WhitespaceSensitiveMacros:
- REGISTER_CORE_PARTICLE
- REGISTER_CORE_DECORATION
- REGISTER_CORE_PLUGIN
- REGISTER_CORE_MODULE

View file

@ -1,25 +1,21 @@
steps:
- name: codespell
pipeline:
codespell:
when:
- event: [manual, pull_request]
- event: [push, tag]
branch: [master, releases/*]
branch:
- master
- releases/*
image: alpine:latest
commands:
- apk add openssl
- apk add python3
- apk add py3-pip
- python3 -m venv codespell-venv
- source codespell-venv/bin/activate
- pip install codespell
- codespell README.md CHANGELOG.md *.c *.h doc/*.scd bar decorations modules particles examples
- deactivate
- codespell README.md CHANGELOG.md *.c *.h doc/*.scd
- name: subprojects
subprojects:
when:
- event: [manual, pull_request]
- event: [push, tag]
branch: [master, releases/*]
branch:
- master
- releases/*
image: alpine:latest
commands:
- apk add git
@ -28,12 +24,12 @@ steps:
- git clone https://codeberg.org/dnkl/fcft.git
- cd ..
- name: x64
x64:
when:
- event: [manual, pull_request]
- event: [push, tag]
branch: [master, releases/*]
depends_on: [subprojects]
branch:
- master
- releases/*
group: build
image: alpine:latest
commands:
- apk update
@ -87,12 +83,12 @@ steps:
- ./yambar --version
- cd ../..
- name: x86
x86:
when:
- event: [manual, pull_request]
- event: [push, tag]
branch: [master, releases/*]
depends_on: [subprojects]
branch:
- master
- releases/*
group: build
image: i386/alpine:latest
commands:
- apk add musl-dev eudev-libs eudev-dev linux-headers meson ninja gcc scdoc

View file

@ -1,7 +1,5 @@
# Changelog
* [Unreleased](#unreleased)
* [1.11.0](#1-11-0)
* [1.10.0](#1-10-0)
* [1.9.0](#1-9-0)
* [1.8.0](#1-8-0)
@ -12,126 +10,6 @@
* [1.5.0](#1-5-0)
## Unreleased
### Added
* environment variable substitution in config files ([#96][96]).
* Log output now respects the [`NO_COLOR`](http://no-color.org/)
environment variable.
* network: `type` tag ([#380][380]).
* network: `type` and `kind` tags ([#380][380]).
* tags: `/<N>` tag formatter: divides the tag's decimal value with `N`
([#392][392]).
* i3/sway: `output` tag, reflecting the output (monitor) a workspace
is on.
* Added "string like" `~~` operator to Map particle. Allows glob-style
matching on strings using `*` and `?` characters ([#400][400]).
* Added "single" mode flag to the `mpd` module ([#428][428]).
* niri: add a new module for niri-workspaces and niri-language
([#404][404]).
[96]: https://codeberg.org/dnkl/yambar/issues/96
[380]: https://codeberg.org/dnkl/yambar/issues/380
[392]: https://codeberg.org/dnkl/yambar/issues/392
[400]: https://codeberg.org/dnkl/yambar/pulls/400
[428]: https://codeberg.org/dnkl/yambar/pulls/428
[404]: https://codeberg.org/dnkl/yambar/issues/404
### Changed
* `river`: expand to an empty list of particles when river is not
running ([#384][384]).
[384]: https://codeberg.org/dnkl/yambar/issues/384
### Deprecated
### Removed
### Fixed
* network: fix missing break in switch statement ([#377][377]).
* i3/sway: crash when output is turned off an on ([#300][300]).
* mpd: yambar never attempting to reconnect after MPD closed the
connection (for example, when MPD is restarted).
* Bar positioning on multi-monitor setups, when `location=bottom`.
* pipewire: Improve handling of node switching ([#424][424]).
[377]: https://codeberg.org/dnkl/yambar/issues/377
[300]: https://codeberg.org/dnkl/yambar/issues/300
[424]: https://codeberg.org/dnkl/yambar/pulls/424
### Security
### Contributors
## 1.11.0
### Added
* battery: current smoothing, for improved discharge estimates.
* battery: scale option, for batteries that report 'charge' at a
different scale than 'current'.
* network: new `quality` tag (Wi-Fi only).
* Read alternative config from pipes and FIFOs (e.g. `--config
/dev/stdin`) ([#340][340]).
* Added `overlay` and `background` as possible `layer` values
([#372][372]).
[340]: https://codeberg.org/dnkl/yambar/pulls/340
[372]: https://codeberg.org/dnkl/yambar/issues/372
### Changed
* log-level: default to `warning`
* network: use dynlist instead of fixed name ([#355][355])
[355]: https://codeberg.org/dnkl/yambar/pulls/355
### Fixed
* Compiler error _fmt may be used uninitialized_ ([#311][311]).
* map: conditions failing to match when they contain multiple, quoted
tag values ([#302][302]).
* Crash when hidden by an opaque window.
* Bar not resizing itself when the screen resolution is changed
([#330][330]).
* i3/sway: incorrect empty/title state of workspaces ([#343][343]).
* mem: state updated on each bar redraw ([#352][352]).
* script: buffer overflow when reading large amounts of data.
* i3/sway: module fails when reloading config file ([#361][361]).
* Worked around bug in gcc causing a compilation error ([#350][350]).
* Miscalculation of list width in presence of empty particles ([#369][369]).
* Log-level not respected by syslog.
[311]: https://codeberg.org/dnkl/yambar/issues/311
[302]: https://codeberg.org/dnkl/yambar/issues/302
[330]: https://codeberg.org/dnkl/yambar/issues/330
[343]: https://codeberg.org/dnkl/yambar/issues/343
[352]: https://codeberg.org/dnkl/yambar/issues/352
[361]: https://codeberg.org/dnkl/yambar/issues/361
[350]: https://codeberg.org/dnkl/yambar/issues/350
[369]: https://codeberg.org/dnkl/yambar/issues/369
### Contributors
* Delgan
* Haden Collins
* Jordan Isaacs
* kotyk
* Leonardo Hernández Hernández
* oob
* rdbo
* Sertonix
* steovd
* Väinö Mäkelä
* Yiyu Zhou
## 1.10.0
### Added

View file

@ -1,5 +1,5 @@
pkgname=yambar
pkgver=1.11.0
pkgver=1.10.0
pkgrel=1
pkgdesc="Simplistic and highly configurable status panel for X and Wayland"
changelog=CHANGELOG.md

View file

@ -1,5 +1,5 @@
pkgname=yambar-wayland
pkgver=1.11.0
pkgver=1.10.0
pkgrel=1
pkgdesc="Simplistic and highly configurable status panel for Wayland"
arch=('x86_64' 'aarch64')

View file

@ -2,7 +2,7 @@
# Yambar
[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg?columns=4)](https://repology.org/project/yambar/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg)](https://repology.org/project/yambar/versions)
## Index
@ -87,7 +87,6 @@ Available modules:
* mem
* mpd
* network
* pipewire
* pulse
* removables
* river
@ -107,7 +106,7 @@ mkdir -p bld/release && cd bld/release
Second, configure the build (if you intend to install it globally, you
might also want `--prefix=/usr`):
```sh
meson setup --buildtype=release ../..
meson --buildtype=release ../..
```
Optionally, explicitly disable a backend (or enable, if you want a

View file

@ -7,8 +7,10 @@
struct backend {
bool (*setup)(struct bar *bar);
void (*cleanup)(struct bar *bar);
void (*loop)(struct bar *bar, void (*expose)(const struct bar *bar),
void (*on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y));
void (*loop)(struct bar *bar,
void (*expose)(const struct bar *bar),
void (*on_mouse)(struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y));
void (*commit)(const struct bar *bar);
void (*refresh)(const struct bar *bar);
void (*set_cursor)(struct bar *bar, const char *cursor);

View file

@ -1,15 +1,15 @@
#include "bar.h"
#include "private.h"
#include <assert.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <threads.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/eventfd.h>
@ -18,17 +18,17 @@
#include "../log.h"
#if defined(ENABLE_X11)
#include "xcb.h"
#include "xcb.h"
#endif
#if defined(ENABLE_WAYLAND)
#include "wayland.h"
#include "wayland.h"
#endif
#define max(x, y) ((x) > (y) ? (x) : (y))
/*
* Calculate total width of left/center/right groups.
* Calculate total width of left/center/rigth groups.
* Note: begin_expose() must have been called
*/
static void
@ -75,8 +75,9 @@ expose(const struct bar *_bar)
const struct private *bar = _bar->private;
pixman_image_t *pix = bar->pix;
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, &bar->background, 1,
&(pixman_rectangle16_t){0, 0, bar->width, bar->height_with_border});
pixman_image_fill_rectangles(
PIXMAN_OP_SRC, pix, &bar->background, 1,
&(pixman_rectangle16_t){0, 0, bar->width, bar->height_with_border});
pixman_image_fill_rectangles(
PIXMAN_OP_OVER, pix, &bar->border.color, 4,
@ -85,15 +86,20 @@ expose(const struct bar *_bar)
{0, 0, bar->border.left_width, bar->height_with_border},
/* Right */
{bar->width - bar->border.right_width, 0, bar->border.right_width, bar->height_with_border},
{bar->width - bar->border.right_width,
0, bar->border.right_width, bar->height_with_border},
/* Top */
{bar->border.left_width, 0, bar->width - bar->border.left_width - bar->border.right_width,
{bar->border.left_width,
0,
bar->width - bar->border.left_width - bar->border.right_width,
bar->border.top_width},
/* Bottom */
{bar->border.left_width, bar->height_with_border - bar->border.bottom_width,
bar->width - bar->border.left_width - bar->border.right_width, bar->border.bottom_width},
{bar->border.left_width,
bar->height_with_border - bar->border.bottom_width,
bar->width - bar->border.left_width - bar->border.right_width,
bar->border.bottom_width},
});
for (size_t i = 0; i < bar->left.count; i++) {
@ -130,8 +136,12 @@ expose(const struct bar *_bar)
int x = bar->border.left_width + bar->left_margin - bar->left_spacing;
pixman_region32_t clip;
pixman_region32_init_rect(
&clip, bar->border.left_width + bar->left_margin, bar->border.top_width,
(bar->width - bar->left_margin - bar->right_margin - bar->border.left_width - bar->border.right_width),
&clip,
bar->border.left_width + bar->left_margin,
bar->border.top_width,
(bar->width -
bar->left_margin - bar->right_margin -
bar->border.left_width - bar->border.right_width),
bar->height);
pixman_image_set_clip_region32(pix, &clip);
pixman_region32_fini(&clip);
@ -151,7 +161,11 @@ expose(const struct bar *_bar)
x += bar->left_spacing + e->width + bar->right_spacing;
}
x = bar->width - (right_width + bar->left_spacing + bar->right_margin + bar->border.right_width);
x = bar->width - (
right_width +
bar->left_spacing +
bar->right_margin +
bar->border.right_width);
for (size_t i = 0; i < bar->right.count; i++) {
const struct exposable *e = bar->right.exps[i];
@ -163,6 +177,7 @@ expose(const struct bar *_bar)
bar->backend.iface->commit(_bar);
}
static void
refresh(const struct bar *bar)
{
@ -185,12 +200,15 @@ output_name(const struct bar *bar)
}
static void
on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn, int x, int y)
on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn,
int x, int y)
{
struct private *bar = _bar->private;
if ((y < bar->border.top_width || y >= (bar->height_with_border - bar->border.bottom_width))
|| (x < bar->border.left_width || x >= (bar->width - bar->border.right_width))) {
if ((y < bar->border.top_width ||
y >= (bar->height_with_border - bar->border.bottom_width)) ||
(x < bar->border.left_width || x >= (bar->width - bar->border.right_width)))
{
set_cursor(_bar, "left_ptr");
return;
}
@ -232,7 +250,10 @@ on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn, int x,
mx += e->width + bar->right_spacing;
}
mx = bar->width - (right_width + bar->left_spacing + bar->right_margin + bar->border.right_width);
mx = bar->width - (right_width +
bar->left_spacing +
bar->right_margin +
bar->border.right_width);
for (size_t i = 0; i < bar->right.count; i++) {
struct exposable *e = bar->right.exps[i];
@ -273,7 +294,8 @@ run(struct bar *_bar)
{
struct private *bar = _bar->private;
bar->height_with_border = bar->height + bar->border.top_width + bar->border.bottom_width;
bar->height_with_border =
bar->height + bar->border.top_width + bar->border.bottom_width;
if (!bar->backend.iface->setup(_bar)) {
bar->backend.iface->cleanup(_bar);
@ -325,7 +347,8 @@ run(struct bar *_bar)
thrd_join(thrd_left[i], &mod_ret);
if (mod_ret != 0) {
const struct module *m = bar->left.mods[i];
LOG_ERR("module: LEFT #%zu (%s): non-zero exit value: %d", i, m->description(m), mod_ret);
LOG_ERR("module: LEFT #%zu (%s): non-zero exit value: %d",
i, m->description(m), mod_ret);
}
ret = ret == 0 && mod_ret != 0 ? mod_ret : ret;
}
@ -333,7 +356,8 @@ run(struct bar *_bar)
thrd_join(thrd_center[i], &mod_ret);
if (mod_ret != 0) {
const struct module *m = bar->center.mods[i];
LOG_ERR("module: CENTER #%zu (%s): non-zero exit value: %d", i, m->description(m), mod_ret);
LOG_ERR("module: CENTER #%zu (%s): non-zero exit value: %d",
i, m->description(m), mod_ret);
}
ret = ret == 0 && mod_ret != 0 ? mod_ret : ret;
}
@ -341,7 +365,8 @@ run(struct bar *_bar)
thrd_join(thrd_right[i], &mod_ret);
if (mod_ret != 0) {
const struct module *m = bar->right.mods[i];
LOG_ERR("module: RIGHT #%zu (%s): non-zero exit value: %d", i, m->description(m), mod_ret);
LOG_ERR("module: RIGHT #%zu (%s): non-zero exit value: %d",
i, m->description(m), mod_ret);
}
ret = ret == 0 && mod_ret != 0 ? mod_ret : ret;
}

View file

@ -18,7 +18,7 @@ struct bar {
};
enum bar_location { BAR_TOP, BAR_BOTTOM };
enum bar_layer { BAR_LAYER_OVERLAY, BAR_LAYER_TOP, BAR_LAYER_BOTTOM, BAR_LAYER_BACKGROUND };
enum bar_layer { BAR_LAYER_TOP, BAR_LAYER_BOTTOM };
enum bar_backend { BAR_BACKEND_AUTO, BAR_BACKEND_XCB, BAR_BACKEND_WAYLAND };
struct bar_config {

View file

@ -3,8 +3,7 @@
#include "../bar/bar.h"
#include "backend.h"
struct private
{
struct private {
/* From bar_config */
char *monitor;
enum bar_layer layer;

View file

@ -1,25 +1,25 @@
#include "wayland.h"
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/input-event-codes.h>
#include <sys/mman.h>
#include <pixman.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <tllist.h>
#include <wlr-layer-shell-unstable-v1.h>
#include <xdg-output-unstable-v1.h>
#include <wlr-layer-shell-unstable-v1.h>
#define LOG_MODULE "bar:wayland"
#define LOG_ENABLE_DBG 0
@ -28,10 +28,6 @@
#include "private.h"
#if !defined(MFD_NOEXEC_SEAL)
#define MFD_NOEXEC_SEAL 0
#endif
struct buffer {
bool busy;
size_t width;
@ -116,15 +112,16 @@ struct wayland_backend {
/* We're already waiting for a frame done callback */
bool render_scheduled;
tll(struct buffer) buffers; /* List of SHM buffers */
struct buffer *next_buffer; /* Bar is rendering to this one */
struct buffer *pending_buffer; /* Finished, but not yet rendered */
tll(struct buffer) buffers; /* List of SHM buffers */
struct buffer *next_buffer; /* Bar is rendering to this one */
struct buffer *pending_buffer; /* Finished, but not yet rendered */
struct wl_callback *frame_callback;
double aggregated_scroll;
bool have_discrete;
void (*bar_on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y);
void (*bar_on_mouse)(struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y);
};
static void
@ -156,7 +153,7 @@ bar_backend_wayland_new(void)
static void
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{
// printf("SHM format: 0x%08x\n", format);
//printf("SHM format: 0x%08x\n", format);
}
static const struct wl_shm_listener shm_listener = {
@ -166,7 +163,10 @@ static const struct wl_shm_listener shm_listener = {
static void
update_cursor_surface(struct wayland_backend *backend, struct seat *seat)
{
if (seat->pointer.serial == 0 || seat->pointer.cursor == NULL || seat->pointer.surface == NULL) {
if (seat->pointer.serial == 0 ||
seat->pointer.cursor == NULL ||
seat->pointer.surface == NULL)
{
return;
}
@ -175,12 +175,17 @@ update_cursor_surface(struct wayland_backend *backend, struct seat *seat)
const int scale = seat->pointer.scale;
wl_surface_set_buffer_scale(seat->pointer.surface, scale);
wl_surface_attach(seat->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0);
wl_surface_attach(
seat->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0);
wl_pointer_set_cursor(seat->wl_pointer, seat->pointer.serial, seat->pointer.surface, image->hotspot_x / scale,
image->hotspot_y / scale);
wl_pointer_set_cursor(
seat->wl_pointer, seat->pointer.serial,
seat->pointer.surface,
image->hotspot_x / scale, image->hotspot_y / scale);
wl_surface_damage_buffer(seat->pointer.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_damage_buffer(
seat->pointer.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(seat->pointer.surface);
wl_display_flush(backend->display);
@ -210,9 +215,11 @@ reload_cursor_theme(struct seat *seat, int new_scale)
}
}
LOG_INFO("%s: cursor theme: %s, size: %u, scale: %d", seat->name, cursor_theme, cursor_size, new_scale);
LOG_INFO("%s: cursor theme: %s, size: %u, scale: %d",
seat->name, cursor_theme, cursor_size, new_scale);
struct wl_cursor_theme *theme = wl_cursor_theme_load(cursor_theme, cursor_size * new_scale, seat->backend->shm);
struct wl_cursor_theme *theme = wl_cursor_theme_load(
cursor_theme, cursor_size * new_scale, seat->backend->shm);
if (theme == NULL) {
LOG_ERR("%s: failed to load cursor theme", seat->name);
@ -224,7 +231,8 @@ reload_cursor_theme(struct seat *seat, int new_scale)
}
static void
wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface,
wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t surface_x, wl_fixed_t surface_y)
{
struct seat *seat = data;
@ -240,7 +248,8 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, str
}
static void
wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface)
wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface)
{
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
@ -252,7 +261,8 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, str
}
static void
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
@ -261,12 +271,14 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_f
seat->pointer.y = wl_fixed_to_int(surface_y) * backend->scale;
backend->active_seat = seat;
backend->bar_on_mouse(backend->bar, ON_MOUSE_MOTION, MOUSE_BTN_NONE, seat->pointer.x, seat->pointer.y);
backend->bar_on_mouse(
backend->bar, ON_MOUSE_MOTION, MOUSE_BTN_NONE,
seat->pointer.x, seat->pointer.y);
}
static void
wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button,
uint32_t state)
wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
@ -277,31 +289,23 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, ui
enum mouse_button btn;
switch (button) {
case BTN_LEFT:
btn = MOUSE_BTN_LEFT;
break;
case BTN_MIDDLE:
btn = MOUSE_BTN_MIDDLE;
break;
case BTN_RIGHT:
btn = MOUSE_BTN_RIGHT;
break;
case BTN_SIDE:
btn = MOUSE_BTN_PREVIOUS;
break;
case BTN_EXTRA:
btn = MOUSE_BTN_NEXT;
break;
case BTN_LEFT: btn = MOUSE_BTN_LEFT; break;
case BTN_MIDDLE: btn = MOUSE_BTN_MIDDLE; break;
case BTN_RIGHT: btn = MOUSE_BTN_RIGHT; break;
case BTN_SIDE: btn = MOUSE_BTN_PREVIOUS; break;
case BTN_EXTRA: btn = MOUSE_BTN_NEXT; break;
default:
return;
}
backend->bar_on_mouse(backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y);
backend->bar_on_mouse(
backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y);
}
}
static void
wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value)
{
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
@ -317,18 +321,24 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32
const double amount = wl_fixed_to_double(value);
if ((backend->aggregated_scroll > 0 && amount < 0) || (backend->aggregated_scroll < 0 && amount > 0)) {
if ((backend->aggregated_scroll > 0 && amount < 0) ||
(backend->aggregated_scroll < 0 && amount > 0))
{
backend->aggregated_scroll = amount;
} else
backend->aggregated_scroll += amount;
enum mouse_button btn = backend->aggregated_scroll > 0 ? MOUSE_BTN_WHEEL_DOWN : MOUSE_BTN_WHEEL_UP;
enum mouse_button btn = backend->aggregated_scroll > 0
? MOUSE_BTN_WHEEL_DOWN
: MOUSE_BTN_WHEEL_UP;
const double step = bar->trackpad_sensitivity;
const double adjust = backend->aggregated_scroll > 0 ? -step : step;
while (fabs(backend->aggregated_scroll) >= step) {
backend->bar_on_mouse(backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y);
backend->bar_on_mouse(
backend->bar, ON_MOUSE_CLICK, btn,
seat->pointer.x, seat->pointer.y);
backend->aggregated_scroll += adjust;
}
}
@ -342,12 +352,14 @@ wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
}
static void
wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source)
wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
uint32_t axis_source)
{
}
static void
wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis)
wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis)
{
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
@ -358,7 +370,8 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, u
}
static void
wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete)
wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
uint32_t axis, int32_t discrete)
{
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
@ -367,12 +380,16 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axi
struct wayland_backend *backend = seat->backend;
backend->have_discrete = true;
enum mouse_button btn = discrete > 0 ? MOUSE_BTN_WHEEL_DOWN : MOUSE_BTN_WHEEL_UP;
enum mouse_button btn = discrete > 0
? MOUSE_BTN_WHEEL_DOWN
: MOUSE_BTN_WHEEL_UP;
int count = abs(discrete);
for (int32_t i = 0; i < count; i++) {
backend->bar_on_mouse(backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y);
backend->bar_on_mouse(
backend->bar, ON_MOUSE_CLICK, btn,
seat->pointer.x, seat->pointer.y);
}
}
@ -389,14 +406,16 @@ static const struct wl_pointer_listener pointer_listener = {
};
static void
seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps)
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps)
{
struct seat *seat = data;
if (caps & WL_SEAT_CAPABILITY_POINTER) {
if (seat->wl_pointer == NULL) {
assert(seat->pointer.surface == NULL);
seat->pointer.surface = wl_compositor_create_surface(seat->backend->compositor);
seat->pointer.surface = wl_compositor_create_surface(
seat->backend->compositor);
if (seat->pointer.surface == NULL) {
LOG_ERR("%s: failed to create pointer surface", seat->name);
@ -436,8 +455,10 @@ static const struct wl_seat_listener seat_listener = {
};
static void
output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width,
int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform)
output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y,
int32_t physical_width, int32_t physical_height,
int32_t subpixel, const char *make, const char *model,
int32_t transform)
{
struct monitor *mon = data;
mon->width_mm = physical_width;
@ -445,29 +466,19 @@ output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, i
}
static void
output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
int32_t width, int32_t height, int32_t refresh)
{
}
static void
output_done(void *data, struct wl_output *wl_output)
{
}
static bool update_size(struct wayland_backend *backend);
static void refresh(const struct bar *_bar);
static void
output_done(void *data, struct wl_output *wl_output)
{
struct monitor *mon = data;
if (mon->backend->monitor == mon) {
int old_scale = mon->backend->scale;
int old_width = mon->backend->width;
update_size(mon->backend);
if (mon->backend->scale != old_scale || mon->backend->width != old_width)
refresh(mon->backend->bar);
}
}
static void
output_scale(void *data, struct wl_output *wl_output, int32_t factor)
{
@ -476,6 +487,14 @@ output_scale(void *data, struct wl_output *wl_output, int32_t factor)
return;
mon->scale = factor;
if (mon->backend->monitor == mon) {
int old_scale = mon->backend->scale;
update_size(mon->backend);
if (mon->backend->scale != old_scale)
refresh(mon->backend->bar);
}
}
#if defined(WL_OUTPUT_NAME_SINCE_VERSION)
@ -490,7 +509,8 @@ output_name(void *data, struct wl_output *wl_output, const char *name)
#if defined(WL_OUTPUT_DESCRIPTION_SINCE_VERSION)
static void
output_description(void *data, struct wl_output *wl_output, const char *description)
output_description(void *data, struct wl_output *wl_output,
const char *description)
{
}
#endif
@ -509,7 +529,9 @@ static const struct wl_output_listener output_listener = {
};
static void
xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y)
xdg_output_handle_logical_position(void *data,
struct zxdg_output_v1 *xdg_output,
int32_t x, int32_t y)
{
struct monitor *mon = data;
mon->x = x;
@ -517,7 +539,8 @@ xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output
}
static void
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height)
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
int32_t width, int32_t height)
{
struct monitor *mon = data;
mon->width_px = width;
@ -532,8 +555,9 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
{
const struct monitor *mon = data;
LOG_INFO("monitor: %s: %dx%d+%d+%d (%dx%dmm)", mon->name, mon->width_px, mon->height_px, mon->x, mon->y,
mon->width_mm, mon->height_mm);
LOG_INFO("monitor: %s: %dx%d+%d+%d (%dx%dmm)",
mon->name, mon->width_px, mon->height_px,
mon->x, mon->y, mon->width_mm, mon->height_mm);
struct wayland_backend *backend = mon->backend;
struct private *bar = backend->bar->private;
@ -545,11 +569,15 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
return;
}
const bool output_is_our_configured_monitor
= (bar->monitor != NULL && mon->name != NULL && strcmp(bar->monitor, mon->name) == 0);
const bool output_is_our_configured_monitor = (
bar->monitor != NULL &&
mon->name != NULL &&
strcmp(bar->monitor, mon->name) == 0);
const bool output_is_last_mapped = (backend->last_mapped_monitor != NULL && mon->name != NULL
&& strcmp(backend->last_mapped_monitor, mon->name) == 0);
const bool output_is_last_mapped = (
backend->last_mapped_monitor != NULL &&
mon->name != NULL &&
strcmp(backend->last_mapped_monitor, mon->name) == 0);
if (output_is_our_configured_monitor)
LOG_DBG("%s: using this monitor (user configured)", mon->name);
@ -571,7 +599,8 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
}
static void
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name)
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
const char *name)
{
struct monitor *mon = data;
free(mon->name);
@ -579,7 +608,8 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char
}
static void
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description)
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
const char *description)
{
}
@ -597,12 +627,14 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted)
if (version >= wanted)
return true;
LOG_ERR("%s: need interface version %u, but compositor only implements %u", iface, wanted, version);
LOG_ERR("%s: need interface version %u, but compositor only implements %u",
iface, wanted, version);
return false;
}
static void
handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
LOG_DBG("global: 0x%08x, interface=%s, version=%u", name, interface, version);
struct wayland_backend *backend = data;
@ -612,7 +644,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
backend->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, required);
backend->compositor = wl_registry_bind(
registry, name, &wl_compositor_interface, required);
}
else if (strcmp(interface, wl_shm_interface.name) == 0) {
@ -620,7 +653,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
backend->shm = wl_registry_bind(registry, name, &wl_shm_interface, required);
backend->shm = wl_registry_bind(
registry, name, &wl_shm_interface, required);
wl_shm_add_listener(backend->shm, &shm_listener, backend);
}
@ -629,9 +663,13 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
struct wl_output *output = wl_registry_bind(registry, name, &wl_output_interface, required);
struct wl_output *output = wl_registry_bind(
registry, name, &wl_output_interface, required);
tll_push_back(backend->monitors, ((struct monitor){.backend = backend, .wl_name = name, .output = output}));
tll_push_back(backend->monitors, ((struct monitor){
.backend = backend,
.wl_name = name,
.output = output}));
struct monitor *mon = &tll_back(backend->monitors);
wl_output_add_listener(output, &output_listener, mon);
@ -644,7 +682,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
assert(backend->xdg_output_manager != NULL);
if (backend->xdg_output_manager != NULL) {
mon->xdg = zxdg_output_manager_v1_get_xdg_output(backend->xdg_output_manager, mon->output);
mon->xdg = zxdg_output_manager_v1_get_xdg_output(
backend->xdg_output_manager, mon->output);
zxdg_output_v1_add_listener(mon->xdg, &xdg_output_listener, mon);
}
@ -655,7 +694,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
backend->layer_shell = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, required);
backend->layer_shell = wl_registry_bind(
registry, name, &zwlr_layer_shell_v1_interface, required);
}
else if (strcmp(interface, wl_seat_interface.name) == 0) {
@ -663,10 +703,12 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
struct wl_seat *seat = wl_registry_bind(registry, name, &wl_seat_interface, required);
struct wl_seat *seat = wl_registry_bind(
registry, name, &wl_seat_interface, required);
assert(seat != NULL);
tll_push_back(backend->seats, ((struct seat){.backend = backend, .seat = seat, .id = name}));
tll_push_back(
backend->seats, ((struct seat){.backend = backend, .seat = seat, .id = name}));
wl_seat_add_listener(seat, &seat_listener, &tll_back(backend->seats));
}
@ -676,7 +718,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
backend->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, required);
backend->xdg_output_manager = wl_registry_bind(
registry, name, &zxdg_output_manager_v1_interface, required);
}
}
@ -685,8 +728,7 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
{
struct wayland_backend *backend = data;
tll_foreach(backend->seats, it)
{
tll_foreach(backend->seats, it) {
if (it->item.id == name) {
if (backend->active_seat == &it->item)
backend->active_seat = NULL;
@ -696,10 +738,8 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
}
}
tll_foreach(backend->monitors, it)
{
tll_foreach(backend->monitors, it) {
struct monitor *mon = &it->item;
/*
if (mon->wl_name == name) {
LOG_INFO("%s disconnected/disabled", mon->name);
@ -712,7 +752,6 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
tll_remove(backend->monitors, it);
return;
}
*/
}
LOG_WARN("unknown global removed: 0x%08x", name);
@ -724,7 +763,8 @@ static const struct wl_registry_listener registry_listener = {
};
static void
layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h)
layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t w, uint32_t h)
{
struct wayland_backend *backend = data;
backend->width = w * backend->scale;
@ -767,43 +807,33 @@ create_surface(struct wayland_backend *backend)
wl_surface_add_listener(backend->surface, &surface_listener, backend);
enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
switch (bar->layer) {
case BAR_LAYER_BACKGROUND:
layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
break;
case BAR_LAYER_BOTTOM:
layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
break;
case BAR_LAYER_TOP:
layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
break;
case BAR_LAYER_OVERLAY:
layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;
break;
}
enum zwlr_layer_shell_v1_layer layer = bar->layer == BAR_LAYER_BOTTOM
? ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM
: ZWLR_LAYER_SHELL_V1_LAYER_TOP;
backend->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
backend->layer_shell, backend->surface, backend->monitor != NULL ? backend->monitor->output : NULL, layer,
"panel");
backend->layer_shell, backend->surface,
backend->monitor != NULL ? backend->monitor->output : NULL,
layer, "panel");
if (backend->layer_surface == NULL) {
LOG_ERR("failed to create layer shell surface");
return false;
}
zwlr_layer_surface_v1_add_listener(backend->layer_surface, &layer_surface_listener, backend);
zwlr_layer_surface_v1_add_listener(
backend->layer_surface, &layer_surface_listener, backend);
/* Aligned to top, maximum width */
enum zwlr_layer_surface_v1_anchor top_or_bottom
= bar->location == BAR_TOP ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
enum zwlr_layer_surface_v1_anchor top_or_bottom = bar->location == BAR_TOP
? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
: ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
zwlr_layer_surface_v1_set_anchor(backend->layer_surface, ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | top_or_bottom);
zwlr_layer_surface_v1_set_anchor(
backend->layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
top_or_bottom);
return true;
}
@ -836,7 +866,7 @@ destroy_surface(struct wayland_backend *backend)
static void
buffer_release(void *data, struct wl_buffer *wl_buffer)
{
// printf("buffer release\n");
//printf("buffer release\n");
struct buffer *buffer = data;
assert(buffer->busy);
buffer->busy = false;
@ -849,8 +879,7 @@ static const struct wl_buffer_listener buffer_listener = {
static struct buffer *
get_buffer(struct wayland_backend *backend)
{
tll_foreach(backend->buffers, it)
{
tll_foreach(backend->buffers, it) {
if (!it->item.busy && it->item.width == backend->width && it->item.height == backend->height) {
it->item.busy = true;
return &it->item;
@ -878,16 +907,7 @@ get_buffer(struct wayland_backend *backend)
/* Backing memory for SHM */
#if defined(MEMFD_CREATE)
/*
* Older kernels reject MFD_NOEXEC_SEAL with EINVAL. Try first
* *with* it, and if that fails, try again *without* it.
*/
errno = 0;
pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL);
if (pool_fd < 0 && errno == EINVAL) {
pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
}
pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC);
#elif defined(__FreeBSD__)
// memfd_create on FreeBSD 13 is SHM_ANON without sealing support
pool_fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
@ -902,7 +922,8 @@ get_buffer(struct wayland_backend *backend)
}
/* Total size */
const uint32_t stride = stride_for_format_and_width(PIXMAN_a8r8g8b8, backend->width);
const uint32_t stride = stride_for_format_and_width(
PIXMAN_a8r8g8b8, backend->width);
size = stride * backend->height;
if (ftruncate(pool_fd, size) == -1) {
@ -916,50 +937,43 @@ get_buffer(struct wayland_backend *backend)
goto err;
}
#if defined(MEMFD_CREATE)
/* Seal file - we no longer allow any kind of resizing */
/* TODO: wayland mmaps(PROT_WRITE), for some unknown reason, hence we cannot use F_SEAL_FUTURE_WRITE */
if (fcntl(pool_fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0) {
LOG_ERRNO("failed to seal SHM backing memory file");
/* This is not a fatal error */
}
#endif
pool = wl_shm_create_pool(backend->shm, pool_fd, size);
if (pool == NULL) {
LOG_ERR("failed to create SHM pool");
goto err;
}
buf = wl_shm_pool_create_buffer(pool, 0, backend->width, backend->height, stride, WL_SHM_FORMAT_ARGB8888);
buf = wl_shm_pool_create_buffer(
pool, 0, backend->width, backend->height, stride, WL_SHM_FORMAT_ARGB8888);
if (buf == NULL) {
LOG_ERR("failed to create SHM buffer");
goto err;
}
/* We use the entire pool for our single buffer */
wl_shm_pool_destroy(pool);
pool = NULL;
close(pool_fd);
pool_fd = -1;
wl_shm_pool_destroy(pool); pool = NULL;
close(pool_fd); pool_fd = -1;
pix = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, backend->width, backend->height, (uint32_t *)mmapped,
stride);
pix = pixman_image_create_bits_no_clear(
PIXMAN_a8r8g8b8, backend->width, backend->height, (uint32_t *)mmapped, stride);
if (pix == NULL) {
LOG_ERR("failed to create pixman image");
goto err;
}
/* Push to list of available buffers, but marked as 'busy' */
tll_push_back(backend->buffers, ((struct buffer){
.busy = true,
.width = backend->width,
.height = backend->height,
.size = size,
.mmapped = mmapped,
.wl_buf = buf,
.pix = pix,
}));
tll_push_back(
backend->buffers,
((struct buffer){
.busy = true,
.width = backend->width,
.height = backend->height,
.size = size,
.mmapped = mmapped,
.wl_buf = buf,
.pix = pix,
})
);
struct buffer *ret = &tll_back(backend->buffers);
wl_buffer_add_listener(ret->wl_buf, &buffer_listener, ret);
@ -989,8 +1003,7 @@ guess_scale(const struct wayland_backend *backend)
bool all_have_same_scale = true;
int last_scale = -1;
tll_foreach(backend->monitors, it)
{
tll_foreach(backend->monitors, it) {
if (last_scale == -1)
last_scale = it->item.scale;
else if (last_scale != it->item.scale) {
@ -1018,6 +1031,9 @@ update_size(struct wayland_backend *backend)
assert(backend->surface != NULL);
if (backend->scale == scale)
return true;
backend->scale = scale;
int height = bar->height_with_border;
@ -1026,21 +1042,29 @@ update_size(struct wayland_backend *backend)
bar->height = height - bar->border.top_width - bar->border.bottom_width;
bar->height_with_border = height;
zwlr_layer_surface_v1_set_size(backend->layer_surface, 0, bar->height_with_border / scale);
zwlr_layer_surface_v1_set_size(
backend->layer_surface, 0, bar->height_with_border / scale);
zwlr_layer_surface_v1_set_exclusive_zone(
backend->layer_surface,
(bar->height_with_border + (bar->location == BAR_TOP ? bar->border.bottom_margin : bar->border.top_margin))
/ scale);
(bar->height_with_border + (bar->location == BAR_TOP
? bar->border.bottom_margin
: bar->border.top_margin))
/ scale);
zwlr_layer_surface_v1_set_margin(backend->layer_surface, bar->border.top_margin / scale,
bar->border.right_margin / scale, bar->border.bottom_margin / scale,
bar->border.left_margin / scale);
zwlr_layer_surface_v1_set_margin(
backend->layer_surface,
bar->border.top_margin / scale,
bar->border.right_margin / scale,
bar->border.bottom_margin / scale,
bar->border.left_margin / scale
);
/* Trigger a 'configure' event, after which we'll have the width */
wl_surface_commit(backend->surface);
wl_display_roundtrip(backend->display);
if (backend->width == -1 || backend->height != bar->height_with_border) {
if (backend->width == -1 ||
backend->height != bar->height_with_border) {
LOG_ERR("failed to get panel width");
return false;
}
@ -1110,7 +1134,8 @@ setup(struct bar *_bar)
return false;
}
assert(backend->monitor == NULL || backend->width / backend->monitor->scale <= backend->monitor->width_px);
assert(backend->monitor == NULL ||
backend->width / backend->monitor->scale <= backend->monitor->width_px);
if (pipe2(backend->pipe_fds, O_CLOEXEC | O_NONBLOCK) == -1) {
LOG_ERRNO("failed to create pipe");
@ -1132,8 +1157,7 @@ cleanup(struct bar *_bar)
if (backend->pipe_fds[1] >= 0)
close(backend->pipe_fds[1]);
tll_foreach(backend->monitors, it)
{
tll_foreach(backend->monitors, it) {
struct monitor *mon = &it->item;
free(mon->name);
@ -1148,13 +1172,13 @@ cleanup(struct bar *_bar)
if (backend->xdg_output_manager != NULL)
zxdg_output_manager_v1_destroy(backend->xdg_output_manager);
tll_foreach(backend->seats, it) seat_destroy(&it->item);
tll_foreach(backend->seats, it)
seat_destroy(&it->item);
tll_free(backend->seats);
destroy_surface(backend);
tll_foreach(backend->buffers, it)
{
tll_foreach(backend->buffers, it) {
if (it->item.wl_buf != NULL)
wl_buffer_destroy(it->item.wl_buf);
if (it->item.pix != NULL)
@ -1179,11 +1203,14 @@ cleanup(struct bar *_bar)
/* Destroyed when freeing buffer list */
bar->pix = NULL;
}
static void
loop(struct bar *_bar, void (*expose)(const struct bar *bar),
void (*on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y))
loop(struct bar *_bar,
void (*expose)(const struct bar *bar),
void (*on_mouse)(struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y))
{
struct private *bar = _bar->private;
struct wayland_backend *backend = bar->backend.data;
@ -1270,23 +1297,22 @@ out:
if (!send_abort_to_modules)
return;
if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) {
if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t))
!= sizeof(uint64_t))
{
LOG_ERRNO("failed to signal abort to modules");
}
// wl_display_cancel_read(backend->display);
//wl_display_cancel_read(backend->display);
}
static void
surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output)
surface_enter(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output)
{
struct wayland_backend *backend = data;
free(backend->last_mapped_monitor);
backend->last_mapped_monitor = NULL;
tll_foreach(backend->monitors, it)
{
tll_foreach(backend->monitors, it) {
struct monitor *mon = &it->item;
if (mon->output != wl_output)
@ -1306,7 +1332,8 @@ surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_ou
}
static void
surface_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output)
surface_leave(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output)
{
struct wayland_backend *backend = data;
const struct monitor *mon = backend->monitor;
@ -1325,7 +1352,8 @@ static const struct wl_surface_listener surface_listener = {
.leave = &surface_leave,
};
static void frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_data);
static void frame_callback(
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
static const struct wl_callback_listener frame_listener = {
.done = &frame_callback,
@ -1334,7 +1362,7 @@ static const struct wl_callback_listener frame_listener = {
static void
frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_data)
{
// printf("frame callback\n");
//printf("frame callback\n");
struct private *bar = data;
struct wayland_backend *backend = bar->backend.data;
@ -1361,7 +1389,7 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da
backend->pending_buffer = NULL;
backend->render_scheduled = true;
} else
; // printf("nothing more to do\n");
;//printf("nothing more to do\n");
}
static void
@ -1370,7 +1398,7 @@ commit(const struct bar *_bar)
struct private *bar = _bar->private;
struct wayland_backend *backend = bar->backend.data;
// printf("commit: %dxl%d\n", backend->width, backend->height);
//printf("commit: %dxl%d\n", backend->width, backend->height);
if (backend->next_buffer == NULL)
return;
@ -1379,7 +1407,7 @@ commit(const struct bar *_bar)
assert(backend->next_buffer->busy);
if (backend->render_scheduled) {
// printf("already scheduled\n");
//printf("already scheduled\n");
if (backend->pending_buffer != NULL)
backend->pending_buffer->busy = false;
@ -1388,7 +1416,7 @@ commit(const struct bar *_bar)
backend->next_buffer = NULL;
} else {
// printf("scheduling new frame callback\n");
//printf("scheduling new frame callback\n");
struct buffer *buffer = backend->next_buffer;
assert(buffer->busy);
@ -1416,7 +1444,9 @@ refresh(const struct bar *_bar)
const struct private *bar = _bar->private;
const struct wayland_backend *backend = bar->backend.data;
if (write(backend->pipe_fds[1], &(uint8_t){1}, sizeof(uint8_t)) != sizeof(uint8_t)) {
if (write(backend->pipe_fds[1], &(uint8_t){1}, sizeof(uint8_t))
!= sizeof(uint8_t))
{
LOG_ERRNO("failed to signal 'refresh' to main thread");
}
}
@ -1436,7 +1466,8 @@ set_cursor(struct bar *_bar, const char *cursor)
seat->pointer.xcursor = cursor;
seat->pointer.cursor = wl_cursor_theme_get_cursor(seat->pointer.theme, cursor);
seat->pointer.cursor = wl_cursor_theme_get_cursor(
seat->pointer.theme, cursor);
if (seat->pointer.cursor == NULL) {
LOG_ERR("%s: failed to load cursor '%s'", seat->name, cursor);

210
bar/xcb.c
View file

@ -1,16 +1,16 @@
#include "xcb.h"
#include <assert.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>
#include <unistd.h>
#include <pixman.h>
#include <xcb/xcb.h>
#include <xcb/randr.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_cursor.h>
#include <xcb/xcb_event.h>
@ -39,6 +39,7 @@ struct xcb_backend {
void *client_pixmap;
size_t client_pixmap_size;
pixman_image_t *pix;
};
void *
@ -54,8 +55,11 @@ setup(struct bar *_bar)
struct private *bar = _bar->private;
struct xcb_backend *backend = bar->backend.data;
if (bar->border.left_margin != 0 || bar->border.right_margin != 0 || bar->border.top_margin != 0
|| bar->border.bottom_margin) {
if (bar->border.left_margin != 0 ||
bar->border.right_margin != 0 ||
bar->border.top_margin != 0 ||
bar->border.bottom_margin)
{
LOG_WARN("non-zero border margins ignored in X11 backend");
}
@ -72,8 +76,10 @@ setup(struct bar *_bar)
xcb_screen_t *screen = xcb_aux_get_screen(backend->conn, default_screen);
xcb_randr_get_monitors_reply_t *monitors
= xcb_randr_get_monitors_reply(backend->conn, xcb_randr_get_monitors(backend->conn, screen->root, 0), &e);
xcb_randr_get_monitors_reply_t *monitors = xcb_randr_get_monitors_reply(
backend->conn,
xcb_randr_get_monitors(backend->conn, screen->root, 0),
&e);
if (e != NULL) {
LOG_ERR("failed to get monitor list: %s", xcb_error(e));
@ -84,13 +90,17 @@ setup(struct bar *_bar)
/* Find monitor coordinates and width/height */
bool found_monitor = false;
for (xcb_randr_monitor_info_iterator_t it = xcb_randr_get_monitors_monitors_iterator(monitors); it.rem > 0;
xcb_randr_monitor_info_next(&it)) {
for (xcb_randr_monitor_info_iterator_t it =
xcb_randr_get_monitors_monitors_iterator(monitors);
it.rem > 0;
xcb_randr_monitor_info_next(&it))
{
const xcb_randr_monitor_info_t *mon = it.data;
char *name = get_atom_name(backend->conn, mon->name);
LOG_INFO("monitor: %s: %ux%u+%u+%u (%ux%umm)", name, mon->width, mon->height, mon->x, mon->y,
mon->width_in_millimeters, mon->height_in_millimeters);
LOG_INFO("monitor: %s: %ux%u+%u+%u (%ux%umm)", name,
mon->width, mon->height, mon->x, mon->y,
mon->width_in_millimeters, mon->height_in_millimeters);
/* User wants a specific monitor, and this is not the one */
if (bar->monitor != NULL && strcmp(bar->monitor, name) != 0) {
@ -101,11 +111,14 @@ setup(struct bar *_bar)
backend->x = mon->x;
backend->y = mon->y;
bar->width = mon->width;
backend->y += bar->location == BAR_TOP ? 0 : mon->height - bar->height_with_border;
backend->y += bar->location == BAR_TOP ? 0
: screen->height_in_pixels - bar->height_with_border;
found_monitor = true;
if ((bar->monitor != NULL && strcmp(bar->monitor, name) == 0) || (bar->monitor == NULL && mon->primary)) {
if ((bar->monitor != NULL && strcmp(bar->monitor, name) == 0) ||
(bar->monitor == NULL && mon->primary))
{
/* Exact match */
free(name);
break;
@ -142,34 +155,61 @@ setup(struct bar *_bar)
LOG_DBG("using a %hhu-bit visual", depth);
backend->colormap = xcb_generate_id(backend->conn);
xcb_create_colormap(backend->conn, 0, backend->colormap, screen->root, vis->visual_id);
xcb_create_colormap(
backend->conn, 0, backend->colormap, screen->root, vis->visual_id);
backend->win = xcb_generate_id(backend->conn);
xcb_create_window(
backend->conn, depth, backend->win, screen->root, backend->x, backend->y, bar->width, bar->height_with_border,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, vis->visual_id,
(XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP),
(const uint32_t[]){screen->black_pixel, screen->white_pixel,
(XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS
| XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_STRUCTURE_NOTIFY),
backend->colormap});
backend->conn,
depth, backend->win, screen->root,
backend->x, backend->y, bar->width, bar->height_with_border,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, vis->visual_id,
(XCB_CW_BACK_PIXEL |
XCB_CW_BORDER_PIXEL |
XCB_CW_EVENT_MASK |
XCB_CW_COLORMAP),
(const uint32_t []){
screen->black_pixel,
screen->white_pixel,
(XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_STRUCTURE_NOTIFY),
backend->colormap}
);
const char *title = "yambar";
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
strlen(title), title);
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
strlen(title), title);
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1,
(const uint32_t[]){getpid()});
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1,
(const uint32_t[]){_NET_WM_WINDOW_TYPE_DOCK});
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_STATE, XCB_ATOM_ATOM, 32, 2,
(const uint32_t[]){_NET_WM_STATE_ABOVE, _NET_WM_STATE_STICKY});
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1,
(const uint32_t[]){0xffffffff});
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
_NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){getpid()});
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
_NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32,
1, (const uint32_t []){_NET_WM_WINDOW_TYPE_DOCK});
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
_NET_WM_STATE, XCB_ATOM_ATOM, 32,
2, (const uint32_t []){_NET_WM_STATE_ABOVE, _NET_WM_STATE_STICKY});
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
_NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, (const uint32_t []){0xffffffff});
/* Always on top */
xcb_configure_window(backend->conn, backend->win, XCB_CONFIG_WINDOW_STACK_MODE,
(const uint32_t[]){XCB_STACK_MODE_ABOVE});
xcb_configure_window(
backend->conn, backend->win, XCB_CONFIG_WINDOW_STACK_MODE,
(const uint32_t []){XCB_STACK_MODE_ABOVE});
uint32_t top_strut, bottom_strut;
uint32_t top_pair[2], bottom_pair[2];
@ -192,38 +232,42 @@ setup(struct bar *_bar)
uint32_t strut[] = {
/* left/right/top/bottom */
0,
0,
0, 0,
top_strut,
bottom_strut,
/* start/end pairs for left/right/top/bottom */
0,
0,
0,
0,
top_pair[0],
top_pair[1],
bottom_pair[0],
bottom_pair[1],
0, 0,
0, 0,
top_pair[0], top_pair[1],
bottom_pair[0], bottom_pair[1],
};
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4,
strut);
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
_NET_WM_STRUT, XCB_ATOM_CARDINAL, 32,
4, strut);
xcb_change_property(backend->conn, XCB_PROP_MODE_REPLACE, backend->win, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL,
32, 12, strut);
xcb_change_property(
backend->conn,
XCB_PROP_MODE_REPLACE, backend->win,
_NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32,
12, strut);
backend->gc = xcb_generate_id(backend->conn);
xcb_create_gc(backend->conn, backend->gc, backend->win, XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES,
(const uint32_t[]){screen->white_pixel, 0});
xcb_create_gc(backend->conn, backend->gc, backend->win,
XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES,
(const uint32_t []){screen->white_pixel, 0});
const uint32_t stride = stride_for_format_and_width(PIXMAN_a8r8g8b8, bar->width);
const uint32_t stride = stride_for_format_and_width(
PIXMAN_a8r8g8b8, bar->width);
backend->client_pixmap_size = stride * bar->height_with_border;
backend->client_pixmap = malloc(backend->client_pixmap_size);
backend->pix = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, bar->width, bar->height_with_border,
(uint32_t *)backend->client_pixmap, stride);
backend->pix = pixman_image_create_bits_no_clear(
PIXMAN_a8r8g8b8, bar->width, bar->height_with_border,
(uint32_t *)backend->client_pixmap, stride);
bar->pix = backend->pix;
xcb_map_window(backend->conn, backend->win);
@ -266,8 +310,10 @@ cleanup(struct bar *_bar)
}
static void
loop(struct bar *_bar, void (*expose)(const struct bar *bar),
void (*on_mouse)(struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y))
loop(struct bar *_bar,
void (*expose)(const struct bar *bar),
void (*on_mouse)(struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y))
{
struct private *bar = _bar->private;
struct xcb_backend *backend = bar->backend.data;
@ -277,7 +323,10 @@ loop(struct bar *_bar, void (*expose)(const struct bar *bar),
const int fd = xcb_get_file_descriptor(backend->conn);
while (true) {
struct pollfd fds[] = {{.fd = _bar->abort_fd, .events = POLLIN}, {.fd = fd, .events = POLLIN}};
struct pollfd fds[] = {
{.fd = _bar->abort_fd, .events = POLLIN},
{.fd = fd, .events = POLLIN}
};
poll(fds, sizeof(fds) / sizeof(fds[0]), -1);
@ -286,14 +335,18 @@ loop(struct bar *_bar, void (*expose)(const struct bar *bar),
if (fds[1].revents & POLLHUP) {
LOG_WARN("disconnected from XCB");
if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) {
if (write(_bar->abort_fd, &(uint64_t){1}, sizeof(uint64_t))
!= sizeof(uint64_t))
{
LOG_ERRNO("failed to signal abort to modules");
}
break;
}
for (xcb_generic_event_t *e = xcb_wait_for_event(backend->conn); e != NULL;
e = xcb_poll_for_event(backend->conn)) {
for (xcb_generic_event_t *e = xcb_wait_for_event(backend->conn);
e != NULL;
e = xcb_poll_for_event(backend->conn))
{
switch (XCB_EVENT_RESPONSE_TYPE(e)) {
case 0:
LOG_ERR("XCB: %s", xcb_error((const xcb_generic_error_t *)e));
@ -316,12 +369,9 @@ loop(struct bar *_bar, void (*expose)(const struct bar *bar),
const xcb_button_release_event_t *evt = (void *)e;
switch (evt->detail) {
case 1:
case 2:
case 3:
case 4:
case 5:
on_mouse(_bar, ON_MOUSE_CLICK, evt->detail, evt->event_x, evt->event_y);
case 1: case 2: case 3: case 4: case 5:
on_mouse(_bar, ON_MOUSE_CLICK,
evt->detail, evt->event_x, evt->event_y);
break;
}
break;
@ -355,9 +405,10 @@ commit(const struct bar *_bar)
const struct private *bar = _bar->private;
const struct xcb_backend *backend = bar->backend.data;
xcb_put_image(backend->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, backend->win, backend->gc, bar->width,
bar->height_with_border, 0, 0, 0, backend->depth, backend->client_pixmap_size,
backend->client_pixmap);
xcb_put_image(
backend->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, backend->win, backend->gc,
bar->width, bar->height_with_border, 0, 0, 0,
backend->depth, backend->client_pixmap_size, backend->client_pixmap);
xcb_flush(backend->conn);
}
@ -369,19 +420,23 @@ refresh(const struct bar *_bar)
/* Send an event to handle refresh from main thread */
/* Note: docs say that all X11 events are 32 bytes, regardless of
/* Note: docs say that all X11 events are 32 bytes, reglardless of
* the size of the event structure */
xcb_expose_event_t *evt = calloc(32, 1);
*evt = (xcb_expose_event_t){.response_type = XCB_EXPOSE,
.window = backend->win,
.x = 0,
.y = 0,
.width = bar->width,
.height = bar->height,
.count = 1};
*evt = (xcb_expose_event_t){
.response_type = XCB_EXPOSE,
.window = backend->win,
.x = 0,
.y = 0,
.width = bar->width,
.height = bar->height,
.count = 1
};
xcb_send_event(backend->conn, false, backend->win, XCB_EVENT_MASK_EXPOSURE, (char *)evt);
xcb_send_event(
backend->conn, false, backend->win, XCB_EVENT_MASK_EXPOSURE,
(char *)evt);
xcb_flush(backend->conn);
free(evt);
@ -403,7 +458,8 @@ set_cursor(struct bar *_bar, const char *cursor)
xcb_free_cursor(backend->conn, backend->cursor);
backend->cursor = xcb_cursor_load_cursor(backend->cursor_ctx, cursor);
xcb_change_window_attributes(backend->conn, backend->win, XCB_CW_CURSOR, &backend->cursor);
xcb_change_window_attributes(
backend->conn, backend->win, XCB_CW_CURSOR, &backend->cursor);
}
static const char *

View file

@ -1,15 +1,15 @@
#include "char32.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <wchar.h>
#if defined __has_include
#if __has_include(<stdc-predef.h>)
#include <stdc-predef.h>
#endif
#if __has_include (<stdc-predef.h>)
#include <stdc-predef.h>
#endif
#endif
#define LOG_MODULE "char32"
@ -24,13 +24,14 @@
* - both use the same encoding (though we require that encoding to be UTF-32)
*/
_Static_assert(sizeof(wchar_t) == sizeof(char32_t), "wchar_t vs. char32_t size mismatch");
_Static_assert(
sizeof(wchar_t) == sizeof(char32_t), "wchar_t vs. char32_t size mismatch");
#if !defined(__STDC_UTF_32__) || !__STDC_UTF_32__
#error "char32_t does not use UTF-32"
#error "char32_t does not use UTF-32"
#endif
#if (!defined(__STDC_ISO_10646__) || !__STDC_ISO_10646__) && !defined(__FreeBSD__)
#error "wchar_t does not use UTF-32"
#error "wchar_t does not use UTF-32"
#endif
size_t

View file

@ -1,7 +1,7 @@
#pragma once
#include <stddef.h>
#include <uchar.h>
#include <stddef.h>
size_t c32len(const char32_t *s);
char32_t *ambstoc32(const char *src);

View file

@ -8,6 +8,6 @@ _arguments \
'(-c --config)'{-c,--config}'[alternative configuration file]:filename:_files' \
'(-C --validate)'{-C,--validate}'[verify configuration then quit]' \
'(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running]:pidfile:_files' \
'(-d --log-level)'{-d,--log-level}'[log level (warning)]:loglevel:(info warning error none)' \
'(-d --log-level)'{-d,--log-level}'[log level (info)]:loglevel:(info warning error none)' \
'(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \
'(-s --log-no-syslog)'{-s,--log-no-syslog}'[disable syslog logging]'

View file

@ -1,7 +1,7 @@
#include "config.h"
#include <assert.h>
#include <string.h>
#include <assert.h>
#include <tllist.h>
@ -16,9 +16,11 @@ conf_err_prefix(const keychain_t *chain, const struct yml_node *node)
static char msg[4096];
int idx = 0;
idx += snprintf(&msg[idx], sizeof(msg) - idx, "%zu:%zu: ", yml_source_line(node), yml_source_column(node));
idx += snprintf(&msg[idx], sizeof(msg) - idx, "%zu:%zu: ",
yml_source_line(node), yml_source_column(node));
tll_foreach(*chain, key) idx += snprintf(&msg[idx], sizeof(msg) - idx, "%s.", key->item);
tll_foreach(*chain, key)
idx += snprintf(&msg[idx], sizeof(msg) - idx, "%s.", key->item);
/* Remove trailing "." */
msg[idx - 1] = '\0';
@ -43,7 +45,8 @@ conf_verify_int(keychain_t *chain, const struct yml_node *node)
if (yml_value_is_int(node))
return true;
LOG_ERR("%s: value is not an integer: '%s'", conf_err_prefix(chain, node), yml_value_as_string(node));
LOG_ERR("%s: value is not an integer: '%s'",
conf_err_prefix(chain, node), yml_value_as_string(node));
return false;
}
@ -53,7 +56,8 @@ conf_verify_unsigned(keychain_t *chain, const struct yml_node *node)
if (yml_value_is_int(node) && yml_value_as_int(node) >= 0)
return true;
LOG_ERR("%s: value is not a positive integer: '%s'", conf_err_prefix(chain, node), yml_value_as_string(node));
LOG_ERR("%s: value is not a positive integer: '%s'",
conf_err_prefix(chain, node), yml_value_as_string(node));
return false;
}
@ -63,7 +67,8 @@ conf_verify_bool(keychain_t *chain, const struct yml_node *node)
if (yml_value_is_bool(node))
return true;
LOG_ERR("%s: value is not a boolean: '%s'", conf_err_prefix(chain, node), yml_value_as_string(node));
LOG_ERR("%s: value is not a boolean: '%s'",
conf_err_prefix(chain, node), yml_value_as_string(node));
return false;
}
@ -76,7 +81,10 @@ conf_verify_list(keychain_t *chain, const struct yml_node *node,
return false;
}
for (struct yml_list_iter iter = yml_list_iter(node); iter.node != NULL; yml_list_next(&iter)) {
for (struct yml_list_iter iter = yml_list_iter(node);
iter.node != NULL;
yml_list_next(&iter))
{
if (!verify(chain, iter.node))
return false;
}
@ -85,7 +93,8 @@ conf_verify_list(keychain_t *chain, const struct yml_node *node,
}
bool
conf_verify_enum(keychain_t *chain, const struct yml_node *node, const char *values[], size_t count)
conf_verify_enum(keychain_t *chain, const struct yml_node *node,
const char *values[], size_t count)
{
const char *s = yml_value_as_string(node);
if (s == NULL) {
@ -106,7 +115,8 @@ conf_verify_enum(keychain_t *chain, const struct yml_node *node, const char *val
}
bool
conf_verify_dict(keychain_t *chain, const struct yml_node *node, const struct attr_info info[])
conf_verify_dict(keychain_t *chain, const struct yml_node *node,
const struct attr_info info[])
{
if (!yml_is_dict(node)) {
LOG_ERR("%s: must be a dictionary", conf_err_prefix(chain, node));
@ -121,7 +131,10 @@ conf_verify_dict(keychain_t *chain, const struct yml_node *node, const struct at
bool exists[count];
memset(exists, 0, sizeof(exists));
for (struct yml_dict_iter it = yml_dict_iter(node); it.key != NULL; yml_dict_next(&it)) {
for (struct yml_dict_iter it = yml_dict_iter(node);
it.key != NULL;
yml_dict_next(&it))
{
const char *key = yml_value_as_string(it.key);
if (key == NULL) {
LOG_ERR("%s: key must be a string", conf_err_prefix(chain, it.key));
@ -177,7 +190,8 @@ verify_on_click_path(keychain_t *chain, const struct yml_node *node)
const bool is_tilde = path[0] == '~' && path[1] == '/';
if (!is_absolute && !is_tilde) {
LOG_ERR("%s: path must be either absolute, or begin with '~/", conf_err_prefix(chain, node));
LOG_ERR("%s: path must be either absolute, or begin with '~/",
conf_err_prefix(chain, node));
return false;
}
@ -194,10 +208,14 @@ conf_verify_on_click(keychain_t *chain, const struct yml_node *node)
return verify_on_click_path(chain, node);
static const struct attr_info info[] = {
{"left", false, &verify_on_click_path}, {"middle", false, &verify_on_click_path},
{"right", false, &verify_on_click_path}, {"wheel-up", false, &verify_on_click_path},
{"wheel-down", false, &verify_on_click_path}, {"previous", false, &verify_on_click_path},
{"next", false, &verify_on_click_path}, {NULL, false, NULL},
{"left", false, &verify_on_click_path},
{"middle", false, &verify_on_click_path},
{"right", false, &verify_on_click_path},
{"wheel-up", false, &verify_on_click_path},
{"wheel-down", false, &verify_on_click_path},
{"previous", false, &verify_on_click_path},
{"next", false, &verify_on_click_path},
{NULL, false, NULL},
};
return conf_verify_dict(chain, node, info);
@ -216,18 +234,21 @@ conf_verify_color(keychain_t *chain, const struct yml_node *node)
int v = sscanf(s, "%02x%02x%02x%02x", &r, &g, &b, &a);
if (strlen(s) != 8 || v != 4) {
LOG_ERR("%s: value must be a color ('rrggbbaa', e.g ff00ffff)", conf_err_prefix(chain, node));
LOG_ERR("%s: value must be a color ('rrggbbaa', e.g ff00ffff)",
conf_err_prefix(chain, node));
return false;
}
return true;
}
bool
conf_verify_font(keychain_t *chain, const struct yml_node *node)
{
if (!yml_is_scalar(node)) {
LOG_ERR("%s: font must be a fontconfig-formatted string", conf_err_prefix(chain, node));
LOG_ERR("%s: font must be a fontconfig-formatted string",
conf_err_prefix(chain, node));
return false;
}
@ -237,7 +258,8 @@ conf_verify_font(keychain_t *chain, const struct yml_node *node)
bool
conf_verify_font_shaping(keychain_t *chain, const struct yml_node *node)
{
return conf_verify_enum(chain, node, (const char *[]){"full", /*"graphemes",*/ "none"}, 2);
return conf_verify_enum(
chain, node, (const char *[]){"full", /*"graphemes",*/ "none"}, 2);
}
bool
@ -247,8 +269,7 @@ conf_verify_decoration(keychain_t *chain, const struct yml_node *node)
if (yml_dict_length(node) != 1) {
LOG_ERR("%s: decoration must be a dictionary with a single key; "
"the name of the particle",
conf_err_prefix(chain, node));
"the name of the particle", conf_err_prefix(chain, node));
return false;
}
@ -264,7 +285,8 @@ conf_verify_decoration(keychain_t *chain, const struct yml_node *node)
const struct deco_iface *iface = plugin_load_deco(deco_name);
if (iface == NULL) {
LOG_ERR("%s: invalid decoration name: %s", conf_err_prefix(chain, deco), deco_name);
LOG_ERR("%s: invalid decoration name: %s",
conf_err_prefix(chain, deco), deco_name);
return false;
}
@ -281,7 +303,10 @@ conf_verify_particle_list_items(keychain_t *chain, const struct yml_node *node)
{
assert(yml_is_list(node));
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it))
{
if (!conf_verify_particle(chain, it.node))
return false;
}
@ -296,8 +321,7 @@ conf_verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
if (yml_dict_length(node) != 1) {
LOG_ERR("%s: particle must be a dictionary with a single key; "
"the name of the particle",
conf_err_prefix(chain, node));
"the name of the particle", conf_err_prefix(chain, node));
return false;
}
@ -307,13 +331,15 @@ conf_verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
const char *particle_name = yml_value_as_string(particle);
if (particle_name == NULL) {
LOG_ERR("%s: particle name must be a string", conf_err_prefix(chain, particle));
LOG_ERR("%s: particle name must be a string",
conf_err_prefix(chain, particle));
return false;
}
const struct particle_iface *iface = plugin_load_particle(particle_name);
if (iface == NULL) {
LOG_ERR("%s: invalid particle name: %s", conf_err_prefix(chain, particle), particle_name);
LOG_ERR("%s: invalid particle name: %s",
conf_err_prefix(chain, particle), particle_name);
return false;
}
@ -335,18 +361,19 @@ conf_verify_particle(keychain_t *chain, const struct yml_node *node)
else if (yml_is_list(node))
return conf_verify_particle_list_items(chain, node);
else {
LOG_ERR("%s: particle must be either a dictionary or a list", conf_err_prefix(chain, node));
LOG_ERR("%s: particle must be either a dictionary or a list",
conf_err_prefix(chain, node));
return false;
}
}
static bool
verify_module(keychain_t *chain, const struct yml_node *node)
{
if (!yml_is_dict(node) || yml_dict_length(node) != 1) {
LOG_ERR("%s: module must be a dictionary with a single key; "
"the name of the module",
conf_err_prefix(chain, node));
"the name of the module", conf_err_prefix(chain, node));
return false;
}
@ -362,7 +389,8 @@ verify_module(keychain_t *chain, const struct yml_node *node)
const struct module_iface *iface = plugin_load_module(mod_name);
if (iface == NULL) {
LOG_ERR("%s: invalid module name: %s", conf_err_prefix(chain, node), mod_name);
LOG_ERR(
"%s: invalid module name: %s", conf_err_prefix(chain, node), mod_name);
return false;
}
@ -384,7 +412,10 @@ verify_module_list(keychain_t *chain, const struct yml_node *node)
return false;
}
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it))
{
if (!verify_module(chain, it.node))
return false;
}
@ -396,12 +427,18 @@ static bool
verify_bar_border(keychain_t *chain, const struct yml_node *node)
{
static const struct attr_info attrs[] = {
{"width", false, &conf_verify_unsigned}, {"left-width", false, &conf_verify_unsigned},
{"right-width", false, &conf_verify_unsigned}, {"top-width", false, &conf_verify_unsigned},
{"bottom-width", false, &conf_verify_unsigned}, {"color", false, &conf_verify_color},
{"margin", false, &conf_verify_unsigned}, {"left-margin", false, &conf_verify_unsigned},
{"right-margin", false, &conf_verify_unsigned}, {"top-margin", false, &conf_verify_unsigned},
{"bottom-margin", false, &conf_verify_unsigned}, {NULL, false, NULL},
{"width", false, &conf_verify_unsigned},
{"left-width", false, &conf_verify_unsigned},
{"right-width", false, &conf_verify_unsigned},
{"top-width", false, &conf_verify_unsigned},
{"bottom-width", false, &conf_verify_unsigned},
{"color", false, &conf_verify_color},
{"margin", false, &conf_verify_unsigned},
{"left-margin", false, &conf_verify_unsigned},
{"right-margin", false, &conf_verify_unsigned},
{"top-margin", false, &conf_verify_unsigned},
{"bottom-margin", false, &conf_verify_unsigned},
{NULL, false, NULL},
};
return conf_verify_dict(chain, node, attrs);
@ -416,7 +453,7 @@ verify_bar_location(keychain_t *chain, const struct yml_node *node)
static bool
verify_bar_layer(keychain_t *chain, const struct yml_node *node)
{
return conf_verify_enum(chain, node, (const char *[]){"overlay", "top", "bottom", "background"}, 4);
return conf_verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2);
}
bool

View file

@ -26,14 +26,17 @@ chain_pop(keychain_t *chain)
tll_pop_back(*chain);
}
const char *conf_err_prefix(const keychain_t *chain, const struct yml_node *node);
const char *conf_err_prefix(
const keychain_t *chain, const struct yml_node *node);
bool conf_verify_string(keychain_t *chain, const struct yml_node *node);
bool conf_verify_int(keychain_t *chain, const struct yml_node *node);
bool conf_verify_unsigned(keychain_t *chain, const struct yml_node *node);
bool conf_verify_bool(keychain_t *chain, const struct yml_node *node);
bool conf_verify_enum(keychain_t *chain, const struct yml_node *node, const char *values[], size_t count);
bool conf_verify_enum(keychain_t *chain, const struct yml_node *node,
const char *values[], size_t count);
bool conf_verify_list(keychain_t *chain, const struct yml_node *node,
bool (*verify)(keychain_t *chain, const struct yml_node *node));
bool conf_verify_dict(keychain_t *chain, const struct yml_node *node,

119
config.c
View file

@ -1,10 +1,10 @@
#include "config.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
@ -21,7 +21,9 @@
static uint8_t
hex_nibble(char hex)
{
assert((hex >= '0' && hex <= '9') || (hex >= 'a' && hex <= 'f') || (hex >= 'A' && hex <= 'F'));
assert((hex >= '0' && hex <= '9') ||
(hex >= 'a' && hex <= 'f') ||
(hex >= 'A' && hex <= 'F'));
if (hex >= '0' && hex <= '9')
return hex - '0';
@ -55,9 +57,9 @@ conf_to_color(const struct yml_node *node)
alpha |= alpha << 8;
return (pixman_color_t){
.red = (uint32_t)(red << 8 | red) * alpha / 0xffff,
.red = (uint32_t)(red << 8 | red) * alpha / 0xffff,
.green = (uint32_t)(green << 8 | green) * alpha / 0xffff,
.blue = (uint32_t)(blue << 8 | blue) * alpha / 0xffff,
.blue = (uint32_t)(blue << 8 | blue) * alpha / 0xffff,
.alpha = alpha,
};
}
@ -72,7 +74,10 @@ conf_to_font(const struct yml_node *node)
const char **fonts = NULL;
char *copy = strdup(font_spec);
for (const char *font = strtok(copy, ","); font != NULL; font = strtok(NULL, ",")) {
for (const char *font = strtok(copy, ",");
font != NULL;
font = strtok(NULL, ","))
{
/* Trim spaces, strictly speaking not necessary, but looks nice :) */
while (isspace(font[0]))
font++;
@ -107,7 +112,9 @@ conf_to_font_shaping(const struct yml_node *node)
else if (strcmp(v, "graphemes") == 0) {
static bool have_warned = false;
if (!have_warned && !(fcft_capabilities() & FCFT_CAPABILITY_GRAPHEME_SHAPING)) {
if (!have_warned &&
!(fcft_capabilities() & FCFT_CAPABILITY_GRAPHEME_SHAPING))
{
have_warned = true;
LOG_WARN("cannot enable grapheme shaping; no support in fcft");
}
@ -117,7 +124,9 @@ conf_to_font_shaping(const struct yml_node *node)
else if (strcmp(v, "full") == 0) {
static bool have_warned = false;
if (!have_warned && !(fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING)) {
if (!have_warned &&
!(fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING))
{
have_warned = true;
LOG_WARN("cannot enable full text shaping; no support in fcft");
}
@ -145,20 +154,25 @@ conf_to_deco(const struct yml_node *node)
}
static struct particle *
particle_simple_list_from_config(const struct yml_node *node, struct conf_inherit inherited)
particle_simple_list_from_config(const struct yml_node *node,
struct conf_inherit inherited)
{
size_t count = yml_list_length(node);
struct particle *parts[count];
size_t idx = 0;
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it), idx++) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it), idx++)
{
parts[idx] = conf_to_particle(it.node, inherited);
}
/* Lazy-loaded function pointer to particle_list_new() */
static struct particle *(*particle_list_new)(struct particle *common, struct particle *particles[], size_t count,
int left_spacing, int right_spacing)
= NULL;
static struct particle *(*particle_list_new)(
struct particle *common,
struct particle *particles[], size_t count,
int left_spacing, int right_spacing) = NULL;
if (particle_list_new == NULL) {
const struct plugin *plug = plugin_load("list", PLUGIN_PARTICLE);
@ -167,8 +181,9 @@ particle_simple_list_from_config(const struct yml_node *node, struct conf_inheri
assert(particle_list_new != NULL);
}
struct particle *common = particle_common_new(0, 0, NULL, fcft_clone(inherited.font), inherited.font_shaping,
inherited.foreground, NULL);
struct particle *common = particle_common_new(
0, 0, NULL, fcft_clone(inherited.font), inherited.font_shaping,
inherited.foreground, NULL);
return particle_list_new(common, parts, count, 0, 2);
}
@ -191,8 +206,10 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *foreground_node = yml_get_value(pair.value, "foreground");
const struct yml_node *deco_node = yml_get_value(pair.value, "deco");
int left = margin != NULL ? yml_value_as_int(margin) : left_margin != NULL ? yml_value_as_int(left_margin) : 0;
int right = margin != NULL ? yml_value_as_int(margin) : right_margin != NULL ? yml_value_as_int(right_margin) : 0;
int left = margin != NULL ? yml_value_as_int(margin) :
left_margin != NULL ? yml_value_as_int(left_margin) : 0;
int right = margin != NULL ? yml_value_as_int(margin) :
right_margin != NULL ? yml_value_as_int(right_margin) : 0;
char *on_click_templates[MOUSE_BTN_COUNT] = {NULL};
if (on_click != NULL) {
@ -217,7 +234,10 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited)
}
else if (yml_is_dict(on_click)) {
for (struct yml_dict_iter it = yml_dict_iter(on_click); it.key != NULL; yml_dict_next(&it)) {
for (struct yml_dict_iter it = yml_dict_iter(on_click);
it.key != NULL;
yml_dict_next(&it))
{
const char *key = yml_value_as_string(it.key);
const char *yml_template = yml_value_as_string(it.value);
@ -266,14 +286,16 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited)
* clone the font, since each particle takes ownership of its own
* font.
*/
struct fcft_font *font = font_node != NULL ? conf_to_font(font_node) : fcft_clone(inherited.font);
enum font_shaping font_shaping
= font_shaping_node != NULL ? conf_to_font_shaping(font_shaping_node) : inherited.font_shaping;
pixman_color_t foreground = foreground_node != NULL ? conf_to_color(foreground_node) : inherited.foreground;
struct fcft_font *font = font_node != NULL
? conf_to_font(font_node) : fcft_clone(inherited.font);
enum font_shaping font_shaping = font_shaping_node != NULL
? conf_to_font_shaping(font_shaping_node) : inherited.font_shaping;
pixman_color_t foreground = foreground_node != NULL
? conf_to_color(foreground_node) : inherited.foreground;
/* Instantiate base/common particle */
struct particle *common
= particle_common_new(left, right, on_click_templates, font, font_shaping, foreground, deco);
struct particle *common = particle_common_new(
left, right, on_click_templates, font, font_shaping, foreground, deco);
const struct particle_iface *iface = plugin_load_particle(type);
@ -301,7 +323,8 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
conf.height = yml_value_as_int(height);
const struct yml_node *location = yml_get_value(bar, "location");
conf.location = strcmp(yml_value_as_string(location), "top") == 0 ? BAR_TOP : BAR_BOTTOM;
conf.location = strcmp(yml_value_as_string(location), "top") == 0
? BAR_TOP : BAR_BOTTOM;
const struct yml_node *background = yml_get_value(bar, "background");
conf.background = conf_to_color(background);
@ -317,18 +340,15 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
const struct yml_node *layer = yml_get_value(bar, "layer");
if (layer != NULL) {
const char *tmp = yml_value_as_string(layer);
if (strcmp(tmp, "overlay") == 0)
conf.layer = BAR_LAYER_OVERLAY;
else if (strcmp(tmp, "top") == 0)
if (strcmp(tmp, "top") == 0)
conf.layer = BAR_LAYER_TOP;
else if (strcmp(tmp, "bottom") == 0)
conf.layer = BAR_LAYER_BOTTOM;
else if (strcmp(tmp, "background") == 0)
conf.layer = BAR_LAYER_BACKGROUND;
else
assert(false);
}
const struct yml_node *spacing = yml_get_value(bar, "spacing");
if (spacing != NULL)
conf.left_spacing = conf.right_spacing = yml_value_as_int(spacing);
@ -353,8 +373,11 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
if (right_margin != NULL)
conf.right_margin = yml_value_as_int(right_margin);
const struct yml_node *trackpad_sensitivity = yml_get_value(bar, "trackpad-sensitivity");
conf.trackpad_sensitivity = trackpad_sensitivity != NULL ? yml_value_as_int(trackpad_sensitivity) : 30;
const struct yml_node *trackpad_sensitivity =
yml_get_value(bar, "trackpad-sensitivity");
conf.trackpad_sensitivity = trackpad_sensitivity != NULL
? yml_value_as_int(trackpad_sensitivity)
: 30;
const struct yml_node *border = yml_get_value(bar, "border");
if (border != NULL) {
@ -371,8 +394,10 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
const struct yml_node *bottom_margin = yml_get_value(border, "bottom-margin");
if (width != NULL)
conf.border.left_width = conf.border.right_width = conf.border.top_width = conf.border.bottom_width
= yml_value_as_int(width);
conf.border.left_width =
conf.border.right_width =
conf.border.top_width =
conf.border.bottom_width = yml_value_as_int(width);
if (left_width != NULL)
conf.border.left_width = yml_value_as_int(left_width);
@ -387,8 +412,10 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
conf.border.color = conf_to_color(color);
if (margin != NULL)
conf.border.left_margin = conf.border.right_margin = conf.border.top_margin = conf.border.bottom_margin
= yml_value_as_int(margin);
conf.border.left_margin =
conf.border.right_margin =
conf.border.top_margin =
conf.border.bottom_margin = yml_value_as_int(margin);
if (left_margin != NULL)
conf.border.left_margin = yml_value_as_int(left_margin);
@ -443,7 +470,10 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
struct module **mods = calloc(count, sizeof(*mods));
size_t idx = 0;
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it), idx++) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it), idx++)
{
struct yml_dict_iter m = yml_dict_iter(it.node);
const char *mod_name = yml_value_as_string(m.key);
@ -455,13 +485,16 @@ conf_to_bar(const struct yml_node *bar, enum bar_backend backend)
*/
const struct yml_node *mod_font = yml_get_value(m.value, "font");
const struct yml_node *mod_font_shaping = yml_get_value(m.value, "font-shaping");
const struct yml_node *mod_foreground = yml_get_value(m.value, "foreground");
const struct yml_node *mod_foreground = yml_get_value(
m.value, "foreground");
struct conf_inherit mod_inherit = {
.font = mod_font != NULL ? conf_to_font(mod_font) : inherited.font,
.font_shaping
= mod_font_shaping != NULL ? conf_to_font_shaping(mod_font_shaping) : inherited.font_shaping,
.foreground = mod_foreground != NULL ? conf_to_color(mod_foreground) : inherited.foreground,
.font = mod_font != NULL
? conf_to_font(mod_font) : inherited.font,
.font_shaping = mod_font_shaping != NULL
? conf_to_font_shaping(mod_font_shaping) : inherited.font_shaping,
.foreground = mod_foreground != NULL
? conf_to_color(mod_foreground) : inherited.foreground,
};
const struct module_iface *iface = plugin_load_module(mod_name);

View file

@ -1,9 +1,9 @@
#pragma once
#include <fcft/fcft.h>
#include "yml.h"
#include "bar/bar.h"
#include "font-shaping.h"
#include "yml.h"
#include <fcft/fcft.h>
struct bar;
struct particle;
@ -25,5 +25,6 @@ struct conf_inherit {
pixman_color_t foreground;
};
struct particle *conf_to_particle(const struct yml_node *node, struct conf_inherit inherited);
struct particle *conf_to_particle(
const struct yml_node *node, struct conf_inherit inherited);
struct deco *conf_to_deco(const struct yml_node *node);

View file

@ -4,11 +4,10 @@
struct deco {
void *private;
void (*expose)(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height);
void (*expose)(const struct deco *deco, pixman_image_t *pix,
int x, int y, int width, int height);
void (*destroy)(struct deco *deco);
};
#define DECORATION_COMMON_ATTRS \
{ \
NULL, false, NULL \
}
#define DECORATION_COMMON_ATTRS \
{NULL, false, NULL}

View file

@ -1,13 +1,12 @@
#include <stdlib.h>
#include "../config-verify.h"
#include "../config.h"
#include "../config-verify.h"
#include "../decoration.h"
#include "../plugin.h"
struct private
{
// struct rgba color;
struct private {
//struct rgba color;
pixman_color_t color;
};
@ -23,7 +22,9 @@ static void
expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height)
{
const struct private *d = deco->private;
pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 1, &(pixman_rectangle16_t){x, y, width, height});
pixman_image_fill_rectangles(
PIXMAN_OP_OVER, pix, &d->color, 1,
&(pixman_rectangle16_t){x, y, width, height});
}
static struct deco *

View file

@ -1,7 +1,7 @@
#include <stdlib.h>
#include "../config-verify.h"
#include "../config.h"
#include "../config-verify.h"
#include "../decoration.h"
#include "../plugin.h"
@ -12,8 +12,7 @@
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
struct private
{
struct private {
pixman_color_t color;
int size;
};
@ -30,20 +29,21 @@ static void
expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height)
{
const struct private *d = deco->private;
pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 4,
(pixman_rectangle16_t[]){
/* Top */
{x, y, width, min(d->size, height)},
pixman_image_fill_rectangles(
PIXMAN_OP_OVER, pix, &d->color, 4,
(pixman_rectangle16_t []){
/* Top */
{x, y, width, min(d->size, height)},
/* Bottom */
{x, max(y + height - d->size, y), width, min(d->size, height)},
/* Bottom */
{x, max(y + height - d->size, y), width, min(d->size, height)},
/* Left */
{x, y, min(d->size, width), height},
/* Left */
{x, y, min(d->size, width), height},
/* Right */
{max(x + width - d->size, x), y, min(d->size, width), height},
});
/* Right */
{max(x + width - d->size, x), y, min(d->size, width), height},
});
}
static struct deco *
@ -66,7 +66,9 @@ from_conf(const struct yml_node *node)
{
const struct yml_node *color = yml_get_value(node, "color");
const struct yml_node *size = yml_get_value(node, "size");
return border_new(conf_to_color(color), size != NULL ? yml_value_as_int(size) : 1);
return border_new(
conf_to_color(color),
size != NULL ? yml_value_as_int(size) : 1);
}
static bool

View file

@ -1,12 +1,11 @@
#include <stdlib.h>
#include "../config-verify.h"
#include "../config.h"
#include "../config-verify.h"
#include "../decoration.h"
#include "../plugin.h"
struct private
{
struct private {
int size;
pixman_color_t color;
};
@ -23,7 +22,9 @@ static void
expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height)
{
const struct private *d = deco->private;
pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 1, &(pixman_rectangle16_t){x, y, width, d->size});
pixman_image_fill_rectangles(
PIXMAN_OP_OVER, pix, &d->color, 1,
&(pixman_rectangle16_t){x, y, width, d->size});
}
static struct deco *

View file

@ -1,14 +1,13 @@
#include <stdlib.h>
#define LOG_MODULE "stack"
#include "../config-verify.h"
#include "../config.h"
#include "../decoration.h"
#include "../log.h"
#include "../config.h"
#include "../config-verify.h"
#include "../decoration.h"
#include "../plugin.h"
struct private
{
struct private {
struct deco **decos;
size_t count;
};
@ -58,7 +57,10 @@ from_conf(const struct yml_node *node)
struct deco *decos[count];
size_t idx = 0;
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it), idx++) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it), idx++)
{
decos[idx] = conf_to_deco(it.node);
}
@ -73,7 +75,10 @@ verify_conf(keychain_t *chain, const struct yml_node *node)
return false;
}
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it))
{
if (!conf_verify_decoration(chain, it.node))
return false;
}

View file

@ -1,12 +1,11 @@
#include <stdlib.h>
#include "../config-verify.h"
#include "../config.h"
#include "../config-verify.h"
#include "../decoration.h"
#include "../plugin.h"
struct private
{
struct private {
int size;
pixman_color_t color;
};
@ -23,8 +22,9 @@ static void
expose(const struct deco *deco, pixman_image_t *pix, int x, int y, int width, int height)
{
const struct private *d = deco->private;
pixman_image_fill_rectangles(PIXMAN_OP_OVER, pix, &d->color, 1,
&(pixman_rectangle16_t){x, y + height - d->size, width, d->size});
pixman_image_fill_rectangles(
PIXMAN_OP_OVER, pix, &d->color, 1,
&(pixman_rectangle16_t){x, y + height - d->size, width, d->size});
}
static struct deco *

View file

@ -36,7 +36,6 @@ if plugin_mpd_enabled
endif
if plugin_i3_enabled
plugin_pages += ['yambar-modules-i3.5.scd']
plugin_pages += ['yambar-modules-sway.5.scd']
endif
if plugin_label_enabled
plugin_pages += ['yambar-modules-label.5.scd']
@ -44,12 +43,6 @@ endif
if plugin_network_enabled
plugin_pages += ['yambar-modules-network.5.scd']
endif
if plugin_niri_language_enabled
plugin_pages += ['yambar-modules-niri-language.5.scd']
endif
if plugin_niri_workspaces_enabled
plugin_pages += ['yambar-modules-niri-workspaces.5.scd']
endif
if plugin_pipewire_enabled
plugin_pages += ['yambar-modules-pipewire.5.scd']
endif

View file

@ -137,7 +137,7 @@ content:
# STACK
This particle combines multiple decorations.
This particles combines multiple decorations.
## CONFIGURATION

View file

@ -61,16 +61,6 @@ the state *unknown* under other conditions.
(default=*60000*). Set to `0` to disable polling (*warning*: many
batteries do not support asynchronous reporting). Cannot be less
than 250ms.
| battery-scale
: int
: no
: How much to scale down the battery charge amount. Some batteries
report too high resulting in bad discharge estimates. Default=1.
| smoothing-secs
: int
: no
: How many seconds to perform smoothing over for battery discharge
estimates. Default=100s.
# EXAMPLES

View file

@ -17,8 +17,8 @@ currently present in the machine.
for the machine
| is_disk
: boolean
: whether or not the device is a disk (e.g., sda, sdb) or a partition
(e.g., sda1, sda2, ...). "Total" is advertised as a disk.
: whether or not the device is a disk (e.g. sda, sdb) or a partition
(e.g. sda1, sda2, ...). "Total" is advertised as a disk.
| read_speed
: int
: bytes read, in bytes/s

View file

@ -28,7 +28,7 @@ Running multiple instances at the same time may result in
:< *Description*
| id
: int
: dwl tag id.
: Dwl tag id.
| name
: string
: The name of the tag (defaults to _id_ if not set).

View file

@ -26,9 +26,6 @@ with the _application_ and _title_ tags to replace the X11-only
| name
: string
: The workspace name
| output
: string
: The output (monitor) the workspace is on
| visible
: bool
: True if the workspace is currently visible (on any output)

View file

@ -20,9 +20,6 @@ mpd - This module provides MPD status such as currently playing artist/album/son
| consume
: bool
: True if the *consume* flag is set
| single
: bool
: True if the *single* flag is set
| volume
: range
: Volume of MPD in percentage

View file

@ -6,12 +6,11 @@ network - This module monitors network connection state
# DESCRIPTION
This module monitors network connection state; disconnected/connected
state and MAC/IP addresses. It instantiates the provided _content_
particle for each network interface.
state and MAC/IP addresses.
Note: while the module internally tracks all assigned IPv4/IPv6
addresses, it currently exposes only a single IPv4 and a single IPv6
address per network interface.
address.
# TAGS
@ -21,16 +20,6 @@ address per network interface.
| name
: string
: Network interface name
| type
: string
: Interface type (*ether*, *wlan*, *loopback*, or *ARPHRD_NNN*, where
*N* is a number).
| kind
: string
: Interface kind. Empty for non-virtual interfaces. For virtual
interfaces, this value is taken from the _IFLA\_INFO\_KIND_ netlink
attribute. Examples of valid values are *bond*, *bridge*, *gre*, *tun*
and *veth*.
| index
: int
: Network interface index
@ -56,9 +45,6 @@ address per network interface.
| signal
: int
: Signal strength, in dBm (Wi-Fi only)
| quality
: range
: Quality of the signal, in percent (Wi-Fi only)
| rx-bitrate
: int
: RX bitrate, in bits/s
@ -79,45 +65,27 @@ address per network interface.
:[ *Type*
:[ *Req*
:< *Description*
| left-spacing
: int
: no
: Space, in pixels, in the left side of each rendered volume
| right-spacing
: int
: no
: Space, in pixels, on the right side of each rendered volume
| spacing
: int
: no
: Short-hand for setting both _left-spacing_ and _right-spacing_
| name
: string
: yes
: Name of network interface to monitor
| poll-interval
: int
: no
: Periodically (in milliseconds) update the signal, quality, rx+tx bitrate, and
ul+dl speed tags (default=0). Setting it to 0 disables updates. Cannot be less
: Periodically (in milliseconds) update the signal, rx+tx bitrate, and
ul+dl speed tags. Setting it to 0 disables updates. Cannot be less
than 250ms.
# EXAMPLES
Display all Ethernet (including WLAN) devices. This excludes loopback,
bridges etc.
```
bar:
left:
- network:
name: wlp3s0
content:
map:
conditions:
type == ether || type == wlan:
map:
default:
string: {text: "{name}: {state} ({ipv4})"}
conditions:
ipv4 == "":
string: {text: "{name}: {state}"}
string: {text: "{name}: {state} ({ipv4})"}
```
# SEE ALSO

View file

@ -1,34 +0,0 @@
yambar-modules-niri-language(5)
# NAME
niri-language - This module provides information about niri's currently
selected language.
# TAGS
[[ *Name*
:[ *Type*
:< *Description*
| language
: string
: The currently selected language.
# CONFIGURATION
No additional attributes supported, only the generic ones (see
*GENERIC CONFIGURATION* in *yambar-modules*(5))
# EXAMPLES
```
bar:
left:
- niri-language:
content:
string: {text: "{language}"}
```
# SEE ALSO
*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5)

View file

@ -1,60 +0,0 @@
yambar-modules-niri-workspaces(5)
# NAME
niri-workspaces - This module provides information about niri workspaces.
# DESCRIPTION
This module provides a map of each workspace present in niri.
Each workspace has its _id_, _name_, and its status (_focused_,
_active_, _empty_). The workspaces are sorted by their ids.
This module will *only* track the monitor where yambar was launched.
If you have a multi monitor setup, please launch yambar on each
individual monitor to track its workspaces.
# TAGS
[[ *Name*
:[ *Type*
:< *Description*
| id
: int
: The workspace id.
| name
: string
: The name of the workspace.
| active
: bool
: True if the workspace is currently visible on the current output.
| focused
: bool
: True if the workspace is currently focused.
| empty
: bool
: True if the workspace contains no window.
# CONFIGURATION
No additional attributes supported, only the generic ones (see
*GENERIC CONFIGURATION* in *yambar-modules*(5))
# EXAMPLES
```
bar:
left:
- niri-workspaces:
content:
map:
default: {string: {text: "| {id}"}}
conditions:
active: {string: {text: "-> {id}"}}
~empty: {string: {text: "@ {id}"}}
```
# SEE ALSO
*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5)

View file

@ -19,10 +19,10 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change
: Current device description
| form_factor
: string
: Current device form factor (headset, speaker, mic, etc.)
: Current device form factor (headset, speaker, mic, etc)
| bus
: string
: Current device bus (bluetooth, alsa, etc.)
: Current device bus (bluetooth, alsa, etc)
| icon
: string
: Current device icon name
@ -39,16 +39,8 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change
# CONFIGURATION
[[ *Name*
:[ *Type*
:[ *Req*
:< *Description*
| content
: particle
: yes
: Unlike other modules, _content_ is a template particle that will be
expanded twice (i.e. into a list of two elements). The first
element is the 'sink', and the second element the 'source'.
No additional attributes supported, only the generic ones (see
*GENERIC CONFIGURATION* in *yambar-modules*(5))
# EXAMPLES

View file

@ -16,7 +16,7 @@ configurable amount of time.
In continuous mode, the script is executed once. It will typically run
in a loop, sending an updated tag set whenever it needs, or wants
to. The last tag set is used (displayed) by yambar until a new tag set
is received. This mode is intended to be used by scripts that depend
is received. This mode is intended to be used by scripts that depends
on non-polling methods to update their state.
Tag sets, or _transactions_, are separated by an empty line

View file

@ -142,26 +142,14 @@ Available modules have their own pages:
*yambar-modules-clock*(5)
*yambar-modules-cpu*(5)
*yambar-modules-disk-io*(5)
*yambar-modules-dwl*(5)
*yambar-modules-foreign-toplevel*(5)
*yambar-modules-i3*(5)
*yambar-modules-label*(5)
*yambar-modules-mem*(5)
*yambar-modules-mpd*(5)
*yambar-modules-network*(5)
*yambar-modules-pipewire*(5)
*yambar-modules-pulse*(5)
*yambar-modules-removables*(5)
@ -174,10 +162,6 @@ Available modules have their own pages:
*yambar-modules-sway*(5)
*yambar-modules-niri-language*(5)
*yambar-modules-niri-workspaces*(5)
*yambar-modules-xkb*(5)
*yambar-modules-xwindow*(5)

View file

@ -155,7 +155,7 @@ content:
This particle is a list (or sequence, if you like) of other
particles. It can be used to render e.g. _string_ particles with
different font and/or color formatting. Or any other particle
different font and/or color formatting. Or ay other particle
combinations.
But note that this means you *cannot* set any attributes on the _list_
@ -214,11 +214,6 @@ content:
- string: ...
```
Note that the short form has a hard-coded *right-spacing* of 2. This
cannot be changed. If you want a different spacing, you must use an
explicit list particle (i.e. the long form).
# MAP
This particle maps the values of a specific tag to different
@ -265,26 +260,6 @@ To match for empty strings, use ' "" ':
<tag> == ""
```
String glob matching
To perform string matching using globbing with "\*" & "?" characters:
\* Match any zero or more characters. ? Match exactly any one
character.
```
<tag> ~~ "hello*"
```
Will match any string starting with "hello", including "hello",
"hello1", "hello123", etc.
```
<tag> ~~ "hello?"
```
Will match any string starting with "hello" followed by any single
character, including "hello1", "hello-", but not "hello".
Furthermore, you may use the boolean operators:
[- &&
@ -476,7 +451,7 @@ itself when needed.
```
content:
progress-bar:
progres-bar:
tag: tag_name
length: 20
start: {string: {text: ├}}

View file

@ -86,15 +86,11 @@ be used.
: format
: Range tags
: Renders a range tag's value as a percentage value
| /N
: format
: All tag types
: Renders a tag's value (in decimal) divided by N
| kb, mb, gb
: format
: All tag types
: Renders a tag's value (in decimal) divided by 1000, 1000^2 or
1000^3. Note: no unit suffix is appended
1000^3. Note: no unit suffix is appended)
| kib, mib, gib
: format
: All tag types

View file

@ -25,11 +25,11 @@ yambar - modular status panel for X11 and Wayland
*-p*,*--print-pid*=_FILE_|_FD_
Print PID to this file, or FD, when successfully started. The file
(or FD) is closed immediately after writing the PID. When a _FILE_
as been specified, the file is unlinked upon exiting.
as been specified, the file is unlinked exit.
*-d*,*--log-level*={*info*,*warning*,*error*,*none*}
Log level, used both for log output on stderr as well as
syslog. Default: _warning_.
syslog. Default: _info_.
*-l*,*--log-colorize*=[{*never*,*always*,*auto*}]
Enables or disables colorization of log output on stderr.

View file

@ -23,11 +23,6 @@ types that are frequently used:
- 000000ff: black, no transparency
- 00ff00ff: green, no transparency
- ff000099: red, semi-transparent
- *environment reference*: a string that contains format ${VAR}. This will be
replaced by the value of the environment variable VAR. Example:
- ${HOME}
- ${HOME}/.config/yambar
- ENV is ${ENV}, ENV2 is ${ENV2}
# FORMAT
[[ *Name*
@ -54,8 +49,7 @@ types that are frequently used:
| layer
: string
: no
: Layer to put bar on. One of _overlay_, _top_, _bottom_ or
_background_. Wayland only. Default: _bottom_.
: Layer to put bar on. One of _top_ or _bottom_. Wayland only
| left-spacing
: int
: no

View file

@ -169,40 +169,34 @@ bar:
- string: {text: , font: *awesome}
- string: {text: "{layout}"}
- network:
name: enp1s0
content:
map:
default: {empty: {}}
conditions:
name == enp1s0:
~carrier: {empty: {}}
carrier:
map:
default: {string: {text: , font: *awesome, foreground: ffffff66}}
conditions:
~carrier: {empty: {}}
carrier:
map:
default: {string: {text: , font: *awesome, foreground: ffffff66}}
conditions:
state == up && ipv4 != "": {string: {text: , font: *awesome}}
state == up && ipv4 != "": {string: {text: , font: *awesome}}
- network:
name: wlp2s0
poll-interval: 1000
content:
map:
default: {empty: {}}
default: {string: {text: , font: *awesome, foreground: ffffff66}}
conditions:
name == wlp2s0:
state == down: {string: {text: , font: *awesome, foreground: ff0000ff}}
state == up:
map:
default: {string: {text: , font: *awesome, foreground: ffffff66}}
conditions:
state == down: {string: {text: , font: *awesome, foreground: ff0000ff}}
state == up:
map:
default:
- string: {text: , font: *awesome}
- string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"}
default:
- string: {text: , font: *awesome}
- string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"}
conditions:
ipv4 == "":
- string: {text: , font: *awesome, foreground: ffffff66}
- string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66}
conditions:
ipv4 == "":
- string: {text: , font: *awesome, foreground: ffffff66}
- string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66}
- alsa:
card: hw:PCH
mixer: Master

View file

@ -15,20 +15,20 @@ bar:
anchors:
- base: &river_base
left-margin: 10
right-margin: 13
right-margin: 13
default: {string: {text: , font: *hack}}
conditions:
id == 1: {string: {text: ﳐ, font: *hack}}
id == 2: {string: {text: , font: *hack}}
id == 3: {string: {text: , font: *hack}}
id == 4: {string: {text: , font: *hack}}
id == 5: {string: {text: , font: *hack}}
id == 10: {string: {text: "scratchpad", font: *hack}}
id == 11: {string: {text: "work", font: *hack}}
id == 1: {string: {text: ﳐ, font: *hack}}
id == 2: {string: {text: , font: *hack}}
id == 3: {string: {text: , font: *hack}}
id == 4: {string: {text: , font: *hack}}
id == 5: {string: {text: , font: *hack}}
id == 10: {string: {text: "scratchpad", font: *hack}}
id == 11: {string: {text: "work", font: *hack}}
content:
map:
on-click:
on-click:
left: sh -c "riverctl set-focused-tags $((1 << ({id} - 1)))"
right: sh -c "riverctl toggle-focused-tags $((1 << ({id} -1)))"
middle: sh -c "riverctl toggle-view-tags $((1 << ({id} -1)))"

View file

@ -1,69 +0,0 @@
bg_default: &bg_default {stack: [{background: {color: 81A1C1ff}}, {underline: {size: 4, color: D8DEE9ff}}]}
bar:
height: 32
location: top
background: 000000ff
font: NotoSans:pixelsize=16
right:
- clock:
content:
- string: {text: , font: "Font Awesome 6 Free:style=solid:size=12"}
- string: {text: "{date}", right-margin: 5}
- string: {text: , font: "Font Awesome 6 Free:style=solid:size=12"}
- string: {text: "{time} "}
left:
- river:
anchors:
- base: &river_base
left-margin: 10
right-margin: 13
default: {string: {text: }}
conditions:
id == 1: {string: {text: 1}}
id == 2: {string: {text: 2}}
id == 3: {string: {text: 3}}
id == 4: {string: {text: 4}}
id == 5: {string: {text: 5}}
content:
map:
on-click:
left: sh -c "riverctl set-focused-tags $((1 << ({id} - 1)))"
right: sh -c "riverctl toggle-focused-tags $((1 << ({id} -1)))"
middle: sh -c "riverctl toggle-view-tags $((1 << ({id} -1)))"
conditions:
state == urgent:
map:
<<: *river_base
deco: {background: {color: D08770ff}}
state == focused:
map:
<<: *river_base
deco: *bg_default
state == visible && ~occupied:
map:
<<: *river_base
state == visible && occupied:
map:
<<: *river_base
deco: *bg_default
state == unfocused:
map:
<<: *river_base
state == invisible && ~occupied: {empty: {}}
state == invisible && occupied:
map:
<<: *river_base
deco: {underline: {size: 3, color: ea6962ff}}
center:
- foreign-toplevel:
content:
map:
conditions:
~activated: {empty: {}}
activated:
- string: {text: " {app-id}", foreground: ffa0a0ff}
- string: {text: ": {title}"}

View file

@ -19,7 +19,7 @@
#
# Now the fun part
#
# Example configuration:
# Exemple configuration:
#
# - script:
# path: /absolute/path/to/dwl-tags.sh
@ -136,3 +136,4 @@ done
unset -v output title layout activetags selectedtags
unset -v tags name

View file

@ -12,16 +12,16 @@
# {aur} int number of aur packages
# {pkg} int sum of both
#
# Examples configuration:
# Exemples configuration:
# - script:
# path: /absolute/path/to/pacman.sh
# args: []
# args: []
# content: { string: { text: "{pacman} + {aur} = {pkg}" } }
#
# To display a message when there is no update:
# - script:
# path: /absolute/path/to/pacman.sh
# args: []
# args: []
# content:
# map:
# default: { string: { text: "{pacman} + {aur} = {pkg}" } }
@ -47,9 +47,9 @@ while true; do
# Change interval
# NUMBER[SUFFIXE]
# Possible suffix:
# "s" seconds / "m" minutes / "h" hours / "d" days
# "s" seconds / "m" minutes / "h" hours / "d" days
interval="1h"
# Change your aur manager
aur_helper="paru"
@ -62,7 +62,7 @@ while true; do
else
aur_num=$("${aur_helper}" -Qmu | wc -l)
fi
pkg_num=$(( pacman_num + aur_num ))
printf -- '%s\n' "pacman|int|${pacman_num}"
@ -76,3 +76,4 @@ done
unset -v interval aur_helper pacman_num aur_num pkg_num
unset -f _err

51
log.c
View file

@ -1,6 +1,5 @@
#include "log.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
@ -10,12 +9,13 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <assert.h>
#define ALEN(v) (sizeof(v) / sizeof((v)[0]))
#define UNUSED __attribute__((unused))
static bool colorize = false;
static bool do_syslog = false;
static bool do_syslog = true;
static enum log_class log_level = LOG_CLASS_NONE;
static const struct {
@ -32,28 +32,23 @@ static const struct {
};
void
log_init(enum log_colorize _colorize, bool _do_syslog, enum log_facility syslog_facility, enum log_class _log_level)
log_init(enum log_colorize _colorize, bool _do_syslog,
enum log_facility syslog_facility, enum log_class _log_level)
{
static const int facility_map[] = {
[LOG_FACILITY_USER] = LOG_USER,
[LOG_FACILITY_DAEMON] = LOG_DAEMON,
};
/* Don't use colors if NO_COLOR is defined and not empty */
const char *no_color_str = getenv("NO_COLOR");
const bool no_color = no_color_str != NULL && no_color_str[0] != '\0';
colorize = _colorize == LOG_COLORIZE_NEVER
? false
: _colorize == LOG_COLORIZE_ALWAYS
? true
: !no_color && isatty(STDERR_FILENO);
? false : _colorize == LOG_COLORIZE_ALWAYS
? true : isatty(STDERR_FILENO);
do_syslog = _do_syslog;
log_level = _log_level;
int slvl = log_level_map[_log_level].syslog_equivalent;
if (do_syslog && slvl != -1) {
openlog(NULL, /*LOG_PID*/ 0, facility_map[syslog_facility]);
openlog(NULL, /*LOG_PID*/0, facility_map[syslog_facility]);
setlogmask(LOG_UPTO(slvl));
}
}
@ -66,8 +61,8 @@ log_deinit(void)
}
static void
_log(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, int sys_errno,
va_list va)
_log(enum log_class log_class, const char *module, const char *file, int lineno,
const char *fmt, int sys_errno, va_list va)
{
assert(log_class > LOG_CLASS_NONE);
assert(log_class < ALEN(log_level_map));
@ -97,8 +92,9 @@ _log(enum log_class log_class, const char *module, const char *file, int lineno,
}
static void
_sys_log(enum log_class log_class, const char *module, const char UNUSED *file, int UNUSED lineno, const char *fmt,
int sys_errno, va_list va)
_sys_log(enum log_class log_class, const char *module,
const char UNUSED *file, int UNUSED lineno,
const char *fmt, int sys_errno, va_list va)
{
assert(log_class > LOG_CLASS_NONE);
assert(log_class < ALEN(log_level_map));
@ -106,9 +102,6 @@ _sys_log(enum log_class log_class, const char *module, const char UNUSED *file,
if (!do_syslog)
return;
if (log_class > log_level)
return;
/* Map our log level to syslog's level */
int level = log_level_map[log_class].syslog_equivalent;
@ -123,7 +116,8 @@ _sys_log(enum log_class log_class, const char *module, const char UNUSED *file,
}
void
log_msg_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, va_list va)
log_msg_va(enum log_class log_class, const char *module,
const char *file, int lineno, const char *fmt, va_list va)
{
va_list va2;
va_copy(va2, va);
@ -133,7 +127,8 @@ log_msg_va(enum log_class log_class, const char *module, const char *file, int l
}
void
log_msg(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...)
log_msg(enum log_class log_class, const char *module,
const char *file, int lineno, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
@ -142,13 +137,17 @@ log_msg(enum log_class log_class, const char *module, const char *file, int line
}
void
log_errno_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, va_list va)
log_errno_va(enum log_class log_class, const char *module,
const char *file, int lineno,
const char *fmt, va_list va)
{
log_errno_provided_va(log_class, module, file, lineno, errno, fmt, va);
}
void
log_errno(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...)
log_errno(enum log_class log_class, const char *module,
const char *file, int lineno,
const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
@ -157,7 +156,8 @@ log_errno(enum log_class log_class, const char *module, const char *file, int li
}
void
log_errno_provided_va(enum log_class log_class, const char *module, const char *file, int lineno, int errno_copy,
log_errno_provided_va(enum log_class log_class, const char *module,
const char *file, int lineno, int errno_copy,
const char *fmt, va_list va)
{
va_list va2;
@ -168,7 +168,8 @@ log_errno_provided_va(enum log_class log_class, const char *module, const char *
}
void
log_errno_provided(enum log_class log_class, const char *module, const char *file, int lineno, int errno_copy,
log_errno_provided(enum log_class log_class, const char *module,
const char *file, int lineno, int errno_copy,
const char *fmt, ...)
{
va_list va;

71
log.h
View file

@ -1,43 +1,68 @@
#pragma once
#include <stdarg.h>
#include <stdbool.h>
#include <stdarg.h>
enum log_colorize { LOG_COLORIZE_NEVER, LOG_COLORIZE_ALWAYS, LOG_COLORIZE_AUTO };
enum log_facility { LOG_FACILITY_USER, LOG_FACILITY_DAEMON };
enum log_class { LOG_CLASS_NONE, LOG_CLASS_ERROR, LOG_CLASS_WARNING, LOG_CLASS_INFO, LOG_CLASS_DEBUG };
enum log_class {
LOG_CLASS_NONE,
LOG_CLASS_ERROR,
LOG_CLASS_WARNING,
LOG_CLASS_INFO,
LOG_CLASS_DEBUG
};
void log_init(enum log_colorize colorize, bool do_syslog, enum log_facility syslog_facility, enum log_class log_level);
void log_init(enum log_colorize colorize, bool do_syslog,
enum log_facility syslog_facility, enum log_class log_level);
void log_deinit(void);
void log_msg(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
void log_msg(
enum log_class log_class, const char *module,
const char *file, int lineno,
const char *fmt, ...) __attribute__((format (printf, 5, 6)));
void log_errno(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
void log_errno(
enum log_class log_class, const char *module,
const char *file, int lineno,
const char *fmt, ...) __attribute__((format (printf, 5, 6)));
void log_errno_provided(enum log_class log_class, const char *module, const char *file, int lineno, int _errno,
const char *fmt, ...) __attribute__((format(printf, 6, 7)));
void log_errno_provided(
enum log_class log_class, const char *module,
const char *file, int lineno, int _errno,
const char *fmt, ...) __attribute__((format (printf, 6, 7)));
void log_msg_va(
enum log_class log_class, const char *module,
const char *file, int lineno, const char *fmt, va_list va) __attribute__((format (printf, 5, 0)));
void log_errno_va(
enum log_class log_class, const char *module,
const char *file, int lineno,
const char *fmt, va_list va) __attribute__((format (printf, 5, 0)));
void log_errno_provided_va(
enum log_class log_class, const char *module,
const char *file, int lineno, int _errno,
const char *fmt, va_list va) __attribute__((format (printf, 6, 0)));
void log_msg_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, va_list va)
__attribute__((format(printf, 5, 0)));
void log_errno_va(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt,
va_list va) __attribute__((format(printf, 5, 0)));
void log_errno_provided_va(enum log_class log_class, const char *module, const char *file, int lineno, int _errno,
const char *fmt, va_list va) __attribute__((format(printf, 6, 0)));
int log_level_from_string(const char *str);
const char *log_level_string_hint(void);
#define LOG_ERR(...) log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERRNO(...) log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERRNO_P(_errno, ...) \
log_errno_provided(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, _errno, __VA_ARGS__)
#define LOG_WARN(...) log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_INFO(...) log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERR(...) \
log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERRNO(...) \
log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERRNO_P(_errno, ...) \
log_errno_provided(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, \
_errno, __VA_ARGS__)
#define LOG_WARN(...) \
log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_INFO(...) \
log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
#define LOG_DBG(...) log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_DBG(...) \
log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LOG_DBG(...)
#define LOG_DBG(...)
#endif

61
main.c
View file

@ -1,6 +1,4 @@
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <poll.h>
#include <signal.h>
@ -11,12 +9,14 @@
#include <string.h>
#include <threads.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/eventfd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <pwd.h>
#include "bar/bar.h"
#include "config.h"
@ -87,7 +87,7 @@ get_config_path(void)
static struct bar *
load_bar(const char *config_path, enum bar_backend backend)
{
FILE *conf_file = fopen(config_path, "re");
FILE *conf_file = fopen(config_path, "r");
if (conf_file == NULL) {
LOG_ERRNO("%s: failed to open", config_path);
return NULL;
@ -131,7 +131,7 @@ print_usage(const char *prog_name)
" -c,--config=FILE alternative configuration file\n"
" -C,--validate verify configuration then quit\n"
" -p,--print-pid=FILE|FD print PID to file or FD\n"
" -d,--log-level={info|warning|error|none} log level (warning)\n"
" -d,--log-level={info|warning|error|none} log level (info)\n"
" -l,--log-colorize=[never|always|auto] enable/disable colorization of log output on stderr\n"
" -s,--log-no-syslog disable syslog logging\n"
" -v,--version show the version number and quit\n");
@ -147,8 +147,9 @@ print_pid(const char *pid_file, bool *unlink_at_exit)
int pid_fd = strtoul(pid_file, &end, 10);
if (errno != 0 || *end != '\0') {
if ((pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))
< 0) {
if ((pid_fd = open(pid_file,
O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
LOG_ERRNO("%s: failed to open", pid_file);
return false;
} else
@ -177,16 +178,16 @@ int
main(int argc, char *const *argv)
{
static const struct option longopts[] = {
{"backend", required_argument, 0, 'b'},
{"config", required_argument, 0, 'c'},
{"validate", no_argument, 0, 'C'},
{"print-pid", required_argument, 0, 'p'},
{"log-level", required_argument, 0, 'd'},
{"log-colorize", optional_argument, 0, 'l'},
{"log-no-syslog", no_argument, 0, 's'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{NULL, no_argument, 0, 0},
{"backend", required_argument, 0, 'b'},
{"config", required_argument, 0, 'c'},
{"validate", no_argument, 0, 'C'},
{"print-pid", required_argument, 0, 'p'},
{"log-level", required_argument, 0, 'd'},
{"log-colorize", optional_argument, 0, 'l'},
{"log-no-syslog", no_argument, 0, 's'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{NULL, no_argument, 0, 0},
};
bool unlink_pid_file = false;
@ -196,7 +197,7 @@ main(int argc, char *const *argv)
char *config_path = NULL;
enum bar_backend backend = BAR_BACKEND_AUTO;
enum log_class log_level = LOG_CLASS_WARNING;
enum log_class log_level = LOG_CLASS_INFO;
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
bool log_syslog = true;
@ -222,8 +223,9 @@ main(int argc, char *const *argv)
if (stat(optarg, &st) == -1) {
fprintf(stderr, "%s: invalid configuration file: %s\n", optarg, strerror(errno));
return EXIT_FAILURE;
} else if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) {
fprintf(stderr, "%s: invalid configuration file: neither a regular file nor a pipe or FIFO\n", optarg);
} else if (!S_ISREG(st.st_mode)) {
fprintf(stderr, "%s: invalid configuration file: not a regular file\n",
optarg);
return EXIT_FAILURE;
}
@ -242,7 +244,11 @@ main(int argc, char *const *argv)
case 'd': {
int lvl = log_level_from_string(optarg);
if (lvl < 0) {
fprintf(stderr, "-d,--log-level: %s: argument must be one of %s\n", optarg, log_level_string_hint());
fprintf(
stderr,
"-d,--log-level: %s: argument must be one of %s\n",
optarg,
log_level_string_hint());
return EXIT_FAILURE;
}
log_level = lvl;
@ -286,9 +292,12 @@ main(int argc, char *const *argv)
log_init(log_colorize, log_syslog, LOG_FACILITY_DAEMON, log_level);
_Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR, "fcft log level enum offset");
_Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS, "fcft colorize enum mismatch");
fcft_init((enum fcft_log_colorize)log_colorize, log_syslog, (enum fcft_log_class)log_level);
_Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR,
"fcft log level enum offset");
_Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS,
"fcft colorize enum mismatch");
fcft_init((enum fcft_log_colorize)log_colorize, log_syslog,
(enum fcft_log_class)log_level);
atexit(&fcft_fini);
const struct sigaction sa = {.sa_handler = &signal_handler};

View file

@ -1,5 +1,5 @@
project('yambar', 'c',
version: '1.11.0',
version: '1.10.0',
license: 'MIT',
meson_version: '>=0.59.0',
default_options: ['c_std=c18',
@ -12,9 +12,7 @@ plugs_as_libs = get_option('core-plugins-as-shared-libraries')
cc = meson.get_compiler('c')
if cc.has_function('memfd_create',
args: ['-D_GNU_SOURCE=200809L'],
prefix: '#include <sys/mman.h>')
if cc.has_function('memfd_create')
add_project_arguments('-DMEMFD_CREATE', language: 'c')
endif
@ -176,7 +174,7 @@ summary(
'Clock': plugin_clock_enabled,
'CPU monitoring': plugin_cpu_enabled,
'Disk I/O monitoring': plugin_disk_io_enabled,
'dwl (dwm for Wayland)': plugin_dwl_enabled,
'DWL (dwm for Wayland)': plugin_dwl_enabled,
'Foreign toplevel (window tracking for Wayland)': plugin_foreign_toplevel_enabled,
'Memory monitoring': plugin_mem_enabled,
'Music Player Daemon (MPD)': plugin_mpd_enabled,
@ -189,8 +187,6 @@ summary(
'River': plugin_river_enabled,
'Script': plugin_script_enabled,
'Sway XKB keyboard': plugin_sway_xkb_enabled,
'Niri language': plugin_niri_language_enabled,
'Niri workspaces': plugin_niri_workspaces_enabled,
'XKB keyboard (for X11)': plugin_xkb_enabled,
'XWindow (window tracking for X11)': plugin_xwindow_enabled,
},

View file

@ -19,7 +19,7 @@ option('plugin-cpu', type: 'feature', value: 'auto',
option('plugin-disk-io', type: 'feature', value: 'auto',
description: 'Disk I/O support')
option('plugin-dwl', type: 'feature', value: 'auto',
description: 'dwl (dwm for wayland) support')
description: 'DWL (dwm for wayland) support')
option('plugin-foreign-toplevel', type: 'feature', value: 'auto',
description: 'Foreign toplevel (window tracking for Wayland) support')
option('plugin-mem', type: 'feature', value: 'auto',
@ -44,10 +44,6 @@ option('plugin-script', type: 'feature', value: 'auto',
description: 'Script support')
option('plugin-sway-xkb', type: 'feature', value: 'auto',
description: 'keyboard support for Sway')
option('plugin-niri-language', type: 'feature', value: 'auto',
description: 'language support for Niri')
option('plugin-niri-workspaces', type: 'feature', value: 'auto',
description: 'workspaces support for Niri')
option('plugin-xkb', type: 'feature', value: 'auto',
description: 'keyboard support for X11')
option('plugin-xwindow', type: 'feature', value: 'auto',

View file

@ -1,6 +1,6 @@
#include "module.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
struct module *

View file

@ -35,9 +35,9 @@ void module_default_destroy(struct module *mod);
struct exposable *module_begin_expose(struct module *mod);
/* List of attributes *all* modules implement */
#define MODULE_COMMON_ATTRS \
{"content", true, &conf_verify_particle}, {"anchors", false, NULL}, {"font", false, &conf_verify_font}, \
{"foreground", false, &conf_verify_color}, \
{ \
NULL, false, NULL \
}
#define MODULE_COMMON_ATTRS \
{"content", true, &conf_verify_particle}, \
{"anchors", false, NULL}, \
{"font", false, &conf_verify_font}, \
{"foreground", false, &conf_verify_color}, \
{NULL, false, NULL}

View file

@ -1,8 +1,8 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <math.h>
#include <sys/time.h>
#include <sys/inotify.h>
#include <alsa/asoundlib.h>
@ -10,10 +10,10 @@
#define LOG_MODULE "alsa"
#define LOG_ENABLE_DBG 0
#include "../log.h"
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../plugin.h"
enum channel_type { CHANNEL_PLAYBACK, CHANNEL_CAPTURE };
@ -29,8 +29,7 @@ struct channel {
bool muted;
};
struct private
{
struct private {
char *card;
char *mixer;
char *volume_name;
@ -71,8 +70,7 @@ static void
destroy(struct module *mod)
{
struct private *m = mod->private;
tll_foreach(m->channels, it)
{
tll_foreach(m->channels, it) {
channel_free(&it->item);
tll_remove(m->channels, it);
}
@ -131,7 +129,9 @@ content(struct module *mod)
if (use_db) {
bool use_linear = db_max - db_min <= 24 * 100;
if (use_linear) {
percent = db_min - db_max > 0 ? round(100. * (db_cur - db_min) / (db_max - db_min)) : 0;
percent = db_min - db_max > 0
? round(100. * (db_cur - db_min) / (db_max - db_min))
: 0;
} else {
double normalized = pow(10, (double)(db_cur - db_max) / 6000.);
if (db_min != SND_CTL_TLV_DB_GAIN_MUTE) {
@ -141,7 +141,9 @@ content(struct module *mod)
percent = round(100. * normalized);
}
} else {
percent = vol_max - vol_min > 0 ? round(100. * (vol_cur - vol_min) / (vol_max - vol_min)) : 0;
percent = vol_max - vol_min > 0
? round(100. * (vol_cur - vol_min) / (vol_max - vol_min))
: 0;
}
struct tag_set tags = {
@ -171,94 +173,107 @@ update_state(struct module *mod, snd_mixer_elem_t *elem)
/* If volume level can be changed (i.e. this isn't just a switch;
* e.g. a digital channel), get current channel levels */
tll_foreach(m->channels, it)
{
tll_foreach(m->channels, it) {
struct channel *chan = &it->item;
const bool has_volume = chan->type == CHANNEL_PLAYBACK ? m->has_playback_volume : m->has_capture_volume;
const bool has_db = chan->type == CHANNEL_PLAYBACK ? m->has_playback_db : m->has_capture_db;
const bool has_volume = chan->type == CHANNEL_PLAYBACK
? m->has_playback_volume : m->has_capture_volume;
const bool has_db = chan->type == CHANNEL_PLAYBACK
? m->has_playback_db : m->has_capture_db;
if (!has_volume && !has_db)
continue;
if (has_db) {
chan->use_db = true;
const long min = chan->type == CHANNEL_PLAYBACK ? m->playback_db_min : m->capture_db_min;
const long max = chan->type == CHANNEL_PLAYBACK ? m->playback_db_max : m->capture_db_max;
const long min = chan->type == CHANNEL_PLAYBACK
? m->playback_db_min : m->capture_db_min;
const long max = chan->type == CHANNEL_PLAYBACK
? m->playback_db_max : m->capture_db_max;
assert(min <= max);
int r = chan->type == CHANNEL_PLAYBACK ? snd_mixer_selem_get_playback_dB(elem, chan->id, &chan->db_cur)
: snd_mixer_selem_get_capture_dB(elem, chan->id, &chan->db_cur);
int r = chan->type == CHANNEL_PLAYBACK
? snd_mixer_selem_get_playback_dB(elem, chan->id, &chan->db_cur)
: snd_mixer_selem_get_capture_dB(elem, chan->id, &chan->db_cur);
if (r < 0) {
LOG_ERR("%s,%s: %s: failed to get current dB", m->card, m->mixer, chan->name);
LOG_ERR("%s,%s: %s: failed to get current dB",
m->card, m->mixer, chan->name);
}
if (chan->db_cur < min) {
LOG_WARN("%s,%s: %s: current dB is less than the indicated minimum: "
"%ld < %ld",
m->card, m->mixer, chan->name, chan->db_cur, min);
LOG_WARN(
"%s,%s: %s: current dB is less than the indicated minimum: "
"%ld < %ld", m->card, m->mixer, chan->name, chan->db_cur, min);
chan->db_cur = min;
}
if (chan->db_cur > max) {
LOG_WARN("%s,%s: %s: current dB is greater than the indicated maximum: "
"%ld > %ld",
m->card, m->mixer, chan->name, chan->db_cur, max);
LOG_WARN(
"%s,%s: %s: current dB is greater than the indicated maximum: "
"%ld > %ld", m->card, m->mixer, chan->name, chan->db_cur, max);
chan->db_cur = max;
}
assert(chan->db_cur >= min);
assert(chan->db_cur <= max);
assert(chan->db_cur <= max );
LOG_DBG("%s,%s: %s: dB: %ld", m->card, m->mixer, chan->name, chan->db_cur);
LOG_DBG("%s,%s: %s: dB: %ld",
m->card, m->mixer, chan->name, chan->db_cur);
} else
chan->use_db = false;
const long min = chan->type == CHANNEL_PLAYBACK ? m->playback_vol_min : m->capture_vol_min;
const long max = chan->type == CHANNEL_PLAYBACK ? m->playback_vol_max : m->capture_vol_max;
const long min = chan->type == CHANNEL_PLAYBACK
? m->playback_vol_min : m->capture_vol_min;
const long max = chan->type == CHANNEL_PLAYBACK
? m->playback_vol_max : m->capture_vol_max;
assert(min <= max);
int r = chan->type == CHANNEL_PLAYBACK ? snd_mixer_selem_get_playback_volume(elem, chan->id, &chan->vol_cur)
: snd_mixer_selem_get_capture_volume(elem, chan->id, &chan->vol_cur);
int r = chan->type == CHANNEL_PLAYBACK
? snd_mixer_selem_get_playback_volume(elem, chan->id, &chan->vol_cur)
: snd_mixer_selem_get_capture_volume(elem, chan->id, &chan->vol_cur);
if (r < 0) {
LOG_ERR("%s,%s: %s: failed to get current volume", m->card, m->mixer, chan->name);
LOG_ERR("%s,%s: %s: failed to get current volume",
m->card, m->mixer, chan->name);
}
if (chan->vol_cur < min) {
LOG_WARN("%s,%s: %s: current volume is less than the indicated minimum: "
"%ld < %ld",
m->card, m->mixer, chan->name, chan->vol_cur, min);
LOG_WARN(
"%s,%s: %s: current volume is less than the indicated minimum: "
"%ld < %ld", m->card, m->mixer, chan->name, chan->vol_cur, min);
chan->vol_cur = min;
}
if (chan->vol_cur > max) {
LOG_WARN("%s,%s: %s: current volume is greater than the indicated maximum: "
"%ld > %ld",
m->card, m->mixer, chan->name, chan->vol_cur, max);
LOG_WARN(
"%s,%s: %s: current volume is greater than the indicated maximum: "
"%ld > %ld", m->card, m->mixer, chan->name, chan->vol_cur, max);
chan->vol_cur = max;
}
assert(chan->vol_cur >= min);
assert(chan->vol_cur <= max);
assert(chan->vol_cur <= max );
LOG_DBG("%s,%s: %s: volume: %ld", m->card, m->mixer, chan->name, chan->vol_cur);
LOG_DBG("%s,%s: %s: volume: %ld",
m->card, m->mixer, chan->name, chan->vol_cur);
}
/* Get channels muted state */
tll_foreach(m->channels, it)
{
tll_foreach(m->channels, it) {
struct channel *chan = &it->item;
int unmuted;
int r = chan->type == CHANNEL_PLAYBACK ? snd_mixer_selem_get_playback_switch(elem, chan->id, &unmuted)
: snd_mixer_selem_get_capture_switch(elem, chan->id, &unmuted);
int r = chan->type == CHANNEL_PLAYBACK
? snd_mixer_selem_get_playback_switch(elem, chan->id, &unmuted)
: snd_mixer_selem_get_capture_switch(elem, chan->id, &unmuted);
if (r < 0) {
LOG_WARN("%s,%s: %s: failed to get muted state", m->card, m->mixer, chan->name);
LOG_WARN("%s,%s: %s: failed to get muted state",
m->card, m->mixer, chan->name);
unmuted = 1;
}
@ -294,8 +309,10 @@ run_while_online(struct module *mod)
return ret;
}
if (snd_mixer_attach(handle, m->card) != 0 || snd_mixer_selem_register(handle, NULL, NULL) != 0
|| snd_mixer_load(handle) != 0) {
if (snd_mixer_attach(handle, m->card) != 0 ||
snd_mixer_selem_register(handle, NULL, NULL) != 0 ||
snd_mixer_load(handle) != 0)
{
LOG_ERR("failed to attach to card");
ret = RUN_FAILED_CONNECT;
goto err;
@ -306,7 +323,7 @@ run_while_online(struct module *mod)
snd_mixer_selem_id_set_index(sid, 0);
snd_mixer_selem_id_set_name(sid, m->mixer);
snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid);
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
if (elem == NULL) {
LOG_ERR("failed to find mixer");
goto err;
@ -315,24 +332,30 @@ run_while_online(struct module *mod)
/* Get playback volume range */
m->has_playback_volume = snd_mixer_selem_has_playback_volume(elem) > 0;
if (m->has_playback_volume) {
if (snd_mixer_selem_get_playback_volume_range(elem, &m->playback_vol_min, &m->playback_vol_max) < 0) {
LOG_ERR("%s,%s: failed to get playback volume range", m->card, m->mixer);
if (snd_mixer_selem_get_playback_volume_range(
elem, &m->playback_vol_min, &m->playback_vol_max) < 0)
{
LOG_ERR("%s,%s: failed to get playback volume range",
m->card, m->mixer);
assert(m->playback_vol_min == 0);
assert(m->playback_vol_max == 0);
}
if (m->playback_vol_min > m->playback_vol_max) {
LOG_WARN("%s,%s: indicated minimum playback volume is greater than the "
"maximum: %ld > %ld",
m->card, m->mixer, m->playback_vol_min, m->playback_vol_max);
LOG_WARN(
"%s,%s: indicated minimum playback volume is greater than the "
"maximum: %ld > %ld",
m->card, m->mixer, m->playback_vol_min, m->playback_vol_max);
m->playback_vol_min = m->playback_vol_max;
}
}
if (snd_mixer_selem_get_playback_dB_range(elem, &m->playback_db_min, &m->playback_db_max) < 0) {
LOG_WARN("%s,%s: failed to get playback dB range, "
"will use raw volume values instead",
m->card, m->mixer);
if (snd_mixer_selem_get_playback_dB_range(
elem, &m->playback_db_min, &m->playback_db_max) < 0)
{
LOG_WARN(
"%s,%s: failed to get playback dB range, "
"will use raw volume values instead", m->card, m->mixer);
m->has_playback_db = false;
} else
m->has_playback_db = true;
@ -340,24 +363,30 @@ run_while_online(struct module *mod)
/* Get capture volume range */
m->has_capture_volume = snd_mixer_selem_has_capture_volume(elem) > 0;
if (m->has_capture_volume) {
if (snd_mixer_selem_get_capture_volume_range(elem, &m->capture_vol_min, &m->capture_vol_max) < 0) {
LOG_ERR("%s,%s: failed to get capture volume range", m->card, m->mixer);
if (snd_mixer_selem_get_capture_volume_range(
elem, &m->capture_vol_min, &m->capture_vol_max) < 0)
{
LOG_ERR("%s,%s: failed to get capture volume range",
m->card, m->mixer);
assert(m->capture_vol_min == 0);
assert(m->capture_vol_max == 0);
}
if (m->capture_vol_min > m->capture_vol_max) {
LOG_WARN("%s,%s: indicated minimum capture volume is greater than the "
"maximum: %ld > %ld",
m->card, m->mixer, m->capture_vol_min, m->capture_vol_max);
LOG_WARN(
"%s,%s: indicated minimum capture volume is greater than the "
"maximum: %ld > %ld",
m->card, m->mixer, m->capture_vol_min, m->capture_vol_max);
m->capture_vol_min = m->capture_vol_max;
}
}
if (snd_mixer_selem_get_capture_dB_range(elem, &m->capture_db_min, &m->capture_db_max) < 0) {
LOG_WARN("%s,%s: failed to get capture dB range, "
"will use raw volume values instead",
m->card, m->mixer);
if (snd_mixer_selem_get_capture_dB_range(
elem, &m->capture_db_min, &m->capture_db_max) < 0)
{
LOG_WARN(
"%s,%s: failed to get capture dB range, "
"will use raw volume values instead", m->card, m->mixer);
m->has_capture_db = false;
} else
m->has_capture_db = true;
@ -371,7 +400,7 @@ run_while_online(struct module *mod)
struct channel chan = {
.id = i,
.type = is_playback ? CHANNEL_PLAYBACK : CHANNEL_CAPTURE,
.name = strdup(snd_mixer_selem_channel_name(i)),
.name = strdup(snd_mixer_selem_channel_name( i)),
};
tll_push_back(m->channels, chan);
}
@ -384,13 +413,13 @@ run_while_online(struct module *mod)
char channels_str[1024];
int channels_idx = 0;
tll_foreach(m->channels, it)
{
tll_foreach(m->channels, it) {
const struct channel *chan = &it->item;
channels_idx += snprintf(&channels_str[channels_idx], sizeof(channels_str) - channels_idx,
channels_idx == 0 ? "%s (%s)" : ", %s (%s)", chan->name,
chan->type == CHANNEL_PLAYBACK ? "🔊" : "🎤");
channels_idx += snprintf(
&channels_str[channels_idx], sizeof(channels_str) - channels_idx,
channels_idx == 0 ? "%s (%s)" : ", %s (%s)",
chan->name, chan->type == CHANNEL_PLAYBACK ? "🔊" : "🎤");
assert(channels_idx <= sizeof(channels_str));
}
@ -400,8 +429,7 @@ run_while_online(struct module *mod)
bool volume_channel_is_valid = m->volume_name == NULL;
bool muted_channel_is_valid = m->muted_name == NULL;
tll_foreach(m->channels, it)
{
tll_foreach(m->channels, it) {
const struct channel *chan = &it->item;
if (m->volume_name != NULL && strcmp(chan->name, m->volume_name) == 0) {
m->volume_chan = chan;
@ -434,14 +462,26 @@ run_while_online(struct module *mod)
update_state(mod, elem);
LOG_INFO(
"%s,%s: %s range=%ld-%ld, current=%ld%s (sources: volume=%s, muted=%s)", m->card, m->mixer,
"%s,%s: %s range=%ld-%ld, current=%ld%s (sources: volume=%s, muted=%s)",
m->card, m->mixer,
m->volume_chan->use_db ? "dB" : "volume",
(m->volume_chan->type == CHANNEL_PLAYBACK ? (m->volume_chan->use_db ? m->playback_db_min : m->playback_vol_min)
: (m->volume_chan->use_db ? m->capture_db_min : m->capture_vol_min)),
(m->volume_chan->type == CHANNEL_PLAYBACK ? (m->volume_chan->use_db ? m->playback_db_max : m->playback_vol_max)
: (m->volume_chan->use_db ? m->capture_db_max : m->capture_vol_max)),
(m->volume_chan->type == CHANNEL_PLAYBACK
? (m->volume_chan->use_db
? m->playback_db_min
: m->playback_vol_min)
: (m->volume_chan->use_db
? m->capture_db_min
: m->capture_vol_min)),
(m->volume_chan->type == CHANNEL_PLAYBACK
? (m->volume_chan->use_db
? m->playback_db_max
: m->playback_vol_max)
: (m->volume_chan->use_db
? m->capture_db_max
: m->capture_vol_max)),
m->volume_chan->use_db ? m->volume_chan->db_cur : m->volume_chan->vol_cur,
m->muted_chan->muted ? " (muted)" : "", m->volume_chan->name, m->muted_chan->name);
m->muted_chan->muted ? " (muted)" : "",
m->volume_chan->name, m->muted_chan->name);
mod->bar->refresh(mod->bar);
@ -555,7 +595,8 @@ run(struct module *mod)
bool have_create_event = false;
while (!have_create_event) {
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = ifd, .events = POLLIN}};
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN},
{.fd = ifd, .events = POLLIN}};
int r = poll(fds, sizeof(fds) / sizeof(fds[0]), -1);
if (r < 0) {
@ -597,7 +638,7 @@ run(struct module *mod)
break;
/* Consume inotify data */
for (const char *ptr = buf; ptr < buf + len;) {
for (const char *ptr = buf; ptr < buf + len; ) {
const struct inotify_event *e = (const struct inotify_event *)ptr;
if (e->mask & IN_CREATE) {
@ -615,20 +656,23 @@ out:
if (wd >= 0)
inotify_rm_watch(ifd, wd);
if (ifd >= 0)
close(ifd);
close (ifd);
return ret;
}
static struct module *
alsa_new(const char *card, const char *mixer, const char *volume_channel_name, const char *muted_channel_name,
alsa_new(const char *card, const char *mixer,
const char *volume_channel_name, const char *muted_channel_name,
struct particle *label)
{
struct private *priv = calloc(1, sizeof(*priv));
priv->label = label;
priv->card = strdup(card);
priv->mixer = strdup(mixer);
priv->volume_name = volume_channel_name != NULL ? strdup(volume_channel_name) : NULL;
priv->muted_name = muted_channel_name != NULL ? strdup(muted_channel_name) : NULL;
priv->volume_name =
volume_channel_name != NULL ? strdup(volume_channel_name) : NULL;
priv->muted_name =
muted_channel_name != NULL ? strdup(muted_channel_name) : NULL;
struct module *mod = module_common_new();
mod->private = priv;
@ -648,9 +692,12 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *muted = yml_get_value(node, "muted");
const struct yml_node *content = yml_get_value(node, "content");
return alsa_new(yml_value_as_string(card), yml_value_as_string(mixer),
volume != NULL ? yml_value_as_string(volume) : NULL,
muted != NULL ? yml_value_as_string(muted) : NULL, conf_to_particle(content, inherited));
return alsa_new(
yml_value_as_string(card),
yml_value_as_string(mixer),
volume != NULL ? yml_value_as_string(volume) : NULL,
muted != NULL ? yml_value_as_string(muted) : NULL,
conf_to_particle(content, inherited));
}
static bool

View file

@ -1,26 +1,25 @@
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libudev.h>
#define LOG_MODULE "backlight"
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../plugin.h"
struct private
{
struct private {
struct particle *label;
char *device;
@ -112,13 +111,13 @@ readint_from_fd(int fd)
static int
initialize(struct private *m)
{
int backlight_fd = open("/sys/class/backlight", O_RDONLY | O_CLOEXEC);
int backlight_fd = open("/sys/class/backlight", O_RDONLY);
if (backlight_fd == -1) {
LOG_ERRNO("/sys/class/backlight");
return -1;
}
int base_dir_fd = openat(backlight_fd, m->device, O_RDONLY | O_CLOEXEC);
int base_dir_fd = openat(backlight_fd, m->device, O_RDONLY);
close(backlight_fd);
if (base_dir_fd == -1) {
@ -126,7 +125,7 @@ initialize(struct private *m)
return -1;
}
int max_fd = openat(base_dir_fd, "max_brightness", O_RDONLY | O_CLOEXEC);
int max_fd = openat(base_dir_fd, "max_brightness", O_RDONLY);
if (max_fd == -1) {
LOG_ERRNO("/sys/class/backlight/%s/max_brightness", m->device);
close(base_dir_fd);
@ -136,7 +135,7 @@ initialize(struct private *m)
m->max_brightness = readint_from_fd(max_fd);
close(max_fd);
int current_fd = openat(base_dir_fd, "brightness", O_RDONLY | O_CLOEXEC);
int current_fd = openat(base_dir_fd, "brightness", O_RDONLY);
close(base_dir_fd);
if (current_fd == -1) {
@ -146,7 +145,8 @@ initialize(struct private *m)
m->current_brightness = readint_from_fd(current_fd);
LOG_INFO("%s: brightness: %ld (max: %ld)", m->device, m->current_brightness, m->max_brightness);
LOG_INFO("%s: brightness: %ld (max: %ld)", m->device, m->current_brightness,
m->max_brightness);
return current_fd;
}
@ -244,7 +244,8 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *name = yml_get_value(node, "name");
const struct yml_node *c = yml_get_value(node, "content");
return backlight_new(yml_value_as_string(name), conf_to_particle(c, inherited));
return backlight_new(
yml_value_as_string(name), conf_to_particle(c, inherited));
}
static bool

View file

@ -1,49 +1,37 @@
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libudev.h>
#include <tllist.h>
#define LOG_MODULE "battery"
#define LOG_ENABLE_DBG 0
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#define LOG_ENABLE_DBG 1
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../plugin.h"
#define max(x, y) ((x) > (y) ? (x) : (y))
static const long min_poll_interval = 250;
static const long default_poll_interval = 60 * 1000;
static const long one_sec_in_ns = 1000000000;
enum state { STATE_FULL, STATE_NOTCHARGING, STATE_CHARGING, STATE_DISCHARGING, STATE_UNKNOWN };
struct current_state {
long ema;
long current;
struct timespec time;
};
struct private
{
struct private {
struct particle *label;
long poll_interval;
int battery_scale;
long smoothing_scale;
char *battery;
char *manufacturer;
char *model;
@ -57,53 +45,16 @@ struct private
long energy;
long power;
long charge;
struct current_state ema_current;
long current;
long time_to_empty;
long time_to_full;
};
static int64_t
difftimespec_ns(const struct timespec after, const struct timespec before)
{
return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)one_sec_in_ns
+ ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec);
}
// Linear Exponential Moving Average (unevenly spaced time series)
// http://www.eckner.com/papers/Algorithms%20for%20Unevenly%20Spaced%20Time%20Series.pdf
// Adapted from: https://github.com/andreas50/utsAlgorithms/blob/master/ema.c
static void
ema_linear(struct current_state *state, struct current_state curr, long tau)
{
double w, w2, tmp;
if (state->current == -1) {
*state = curr;
return;
}
long time = difftimespec_ns(curr.time, state->time);
tmp = time / (double)tau;
w = exp(-tmp);
if (tmp > 1e-6) {
w2 = (1 - w) / tmp;
} else {
// Use taylor expansion for numerical stability
w2 = 1 - tmp / 2 + tmp * tmp / 6 - tmp * tmp * tmp / 24;
}
double ema = state->ema * w + curr.current * (1 - w2) + state->current * (w2 - w);
state->ema = ema;
state->current = curr.current;
state->time = curr.time;
LOG_DBG("ema current: %ld", (long)ema);
}
static void
timespec_sub(const struct timespec *a, const struct timespec *b, struct timespec *res)
timespec_sub(const struct timespec *a, const struct timespec *b,
struct timespec *res)
{
const long one_sec_in_ns = 1000000000;
res->tv_sec = a->tv_sec - b->tv_sec;
res->tv_nsec = a->tv_nsec - b->tv_nsec;
@ -145,8 +96,11 @@ content(struct module *mod)
mtx_lock(&mod->lock);
assert(m->state == STATE_FULL || m->state == STATE_NOTCHARGING || m->state == STATE_CHARGING
|| m->state == STATE_DISCHARGING || m->state == STATE_UNKNOWN);
assert(m->state == STATE_FULL ||
m->state == STATE_NOTCHARGING ||
m->state == STATE_CHARGING ||
m->state == STATE_DISCHARGING ||
m->state == STATE_UNKNOWN);
unsigned long hours;
unsigned long minutes;
@ -159,8 +113,9 @@ content(struct module *mod)
minutes = m->time_to_full / 60;
hours = minutes / 60;
minutes = minutes % 60;
} else if (m->energy_full >= 0 && m->charge && m->power >= 0) {
unsigned long energy = m->state == STATE_CHARGING ? m->energy_full - m->energy : m->energy;
} else if (m->energy_full >= 0 && m->charge && m->power >= 0) {
unsigned long energy = m->state == STATE_CHARGING
? m->energy_full - m->energy : m->energy;
double hours_as_float;
if (m->state == STATE_FULL || m->state == STATE_NOTCHARGING)
@ -172,14 +127,15 @@ content(struct module *mod)
hours = hours_as_float;
minutes = (hours_as_float - (double)hours) * 60;
} else if (m->charge_full >= 0 && m->charge >= 0 && m->ema_current.current >= 0) {
unsigned long charge = m->state == STATE_CHARGING ? m->charge_full - m->charge : m->charge;
} else if (m->charge_full >= 0 && m->charge >= 0 && m->current >= 0) {
unsigned long charge = m->state == STATE_CHARGING
? m->charge_full - m->charge : m->charge;
double hours_as_float;
if (m->state == STATE_FULL || m->state == STATE_NOTCHARGING)
hours_as_float = 0.0;
else if (m->ema_current.current > 0)
hours_as_float = (double)charge / m->ema_current.current;
else if (m->current > 0)
hours_as_float = (double)charge / m->current;
else
hours_as_float = 99.0;
@ -259,13 +215,13 @@ initialize(struct private *m)
{
char line_buf[512];
int pw_fd = open("/sys/class/power_supply", O_RDONLY | O_CLOEXEC);
int pw_fd = open("/sys/class/power_supply", O_RDONLY);
if (pw_fd < 0) {
LOG_ERRNO("/sys/class/power_supply");
return false;
}
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY | O_CLOEXEC);
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY);
close(pw_fd);
if (base_dir_fd < 0) {
@ -274,9 +230,10 @@ initialize(struct private *m)
}
{
int fd = openat(base_dir_fd, "manufacturer", O_RDONLY | O_CLOEXEC);
int fd = openat(base_dir_fd, "manufacturer", O_RDONLY);
if (fd == -1) {
LOG_WARN("/sys/class/power_supply/%s/manufacturer: %s", m->battery, strerror(errno));
LOG_WARN("/sys/class/power_supply/%s/manufacturer: %s",
m->battery, strerror(errno));
m->manufacturer = NULL;
} else {
m->manufacturer = strdup(readline_from_fd(fd, sizeof(line_buf), line_buf));
@ -285,9 +242,10 @@ initialize(struct private *m)
}
{
int fd = openat(base_dir_fd, "model_name", O_RDONLY | O_CLOEXEC);
int fd = openat(base_dir_fd, "model_name", O_RDONLY);
if (fd == -1) {
LOG_WARN("/sys/class/power_supply/%s/model_name: %s", m->battery, strerror(errno));
LOG_WARN("/sys/class/power_supply/%s/model_name: %s",
m->battery, strerror(errno));
m->model = NULL;
} else {
m->model = strdup(readline_from_fd(fd, sizeof(line_buf), line_buf));
@ -295,10 +253,11 @@ initialize(struct private *m)
}
}
if (faccessat(base_dir_fd, "energy_full_design", O_RDONLY, 0) == 0
&& faccessat(base_dir_fd, "energy_full", O_RDONLY, 0) == 0) {
if (faccessat(base_dir_fd, "energy_full_design", O_RDONLY, 0) == 0 &&
faccessat(base_dir_fd, "energy_full", O_RDONLY, 0) == 0)
{
{
int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY | O_CLOEXEC);
int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY);
if (fd == -1) {
LOG_ERRNO("/sys/class/power_supply/%s/energy_full_design", m->battery);
goto err;
@ -309,7 +268,7 @@ initialize(struct private *m)
}
{
int fd = openat(base_dir_fd, "energy_full", O_RDONLY | O_CLOEXEC);
int fd = openat(base_dir_fd, "energy_full", O_RDONLY);
if (fd == -1) {
LOG_ERRNO("/sys/class/power_supply/%s/energy_full", m->battery);
goto err;
@ -322,27 +281,28 @@ initialize(struct private *m)
m->energy_full = m->energy_full_design = -1;
}
if (faccessat(base_dir_fd, "charge_full_design", O_RDONLY, 0) == 0
&& faccessat(base_dir_fd, "charge_full", O_RDONLY, 0) == 0) {
if (faccessat(base_dir_fd, "charge_full_design", O_RDONLY, 0) == 0 &&
faccessat(base_dir_fd, "charge_full", O_RDONLY, 0) == 0)
{
{
int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY | O_CLOEXEC);
int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY);
if (fd == -1) {
LOG_ERRNO("/sys/class/power_supply/%s/charge_full_design", m->battery);
goto err;
}
m->charge_full_design = readint_from_fd(fd) / m->battery_scale;
m->charge_full_design = readint_from_fd(fd);
close(fd);
}
{
int fd = openat(base_dir_fd, "charge_full", O_RDONLY | O_CLOEXEC);
int fd = openat(base_dir_fd, "charge_full", O_RDONLY);
if (fd == -1) {
LOG_ERRNO("/sys/class/power_supply/%s/charge_full", m->battery);
goto err;
}
m->charge_full = readint_from_fd(fd) / m->battery_scale;
m->charge_full = readint_from_fd(fd);
close(fd);
}
} else {
@ -362,13 +322,13 @@ update_status(struct module *mod)
{
struct private *m = mod->private;
int pw_fd = open("/sys/class/power_supply", O_RDONLY | O_CLOEXEC);
int pw_fd = open("/sys/class/power_supply", O_RDONLY);
if (pw_fd < 0) {
LOG_ERRNO("/sys/class/power_supply");
return false;
}
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY | O_CLOEXEC);
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY);
close(pw_fd);
if (base_dir_fd < 0) {
@ -376,14 +336,14 @@ update_status(struct module *mod)
return false;
}
int status_fd = openat(base_dir_fd, "status", O_RDONLY | O_CLOEXEC);
int status_fd = openat(base_dir_fd, "status", O_RDONLY);
if (status_fd < 0) {
LOG_ERRNO("/sys/class/power_supply/%s/status", m->battery);
close(base_dir_fd);
return false;
}
int capacity_fd = openat(base_dir_fd, "capacity", O_RDONLY | O_CLOEXEC);
int capacity_fd = openat(base_dir_fd, "capacity", O_RDONLY);
if (capacity_fd < 0) {
LOG_ERRNO("/sys/class/power_supply/%s/capacity", m->battery);
close(status_fd);
@ -391,12 +351,12 @@ update_status(struct module *mod)
return false;
}
int energy_fd = openat(base_dir_fd, "energy_now", O_RDONLY | O_CLOEXEC);
int power_fd = openat(base_dir_fd, "power_now", O_RDONLY | O_CLOEXEC);
int charge_fd = openat(base_dir_fd, "charge_now", O_RDONLY | O_CLOEXEC);
int current_fd = openat(base_dir_fd, "current_now", O_RDONLY | O_CLOEXEC);
int time_to_empty_fd = openat(base_dir_fd, "time_to_empty_now", O_RDONLY | O_CLOEXEC);
int time_to_full_fd = openat(base_dir_fd, "time_to_full_now", O_RDONLY | O_CLOEXEC);
int energy_fd = openat(base_dir_fd, "energy_now", O_RDONLY);
int power_fd = openat(base_dir_fd, "power_now", O_RDONLY);
int charge_fd = openat(base_dir_fd, "charge_now", O_RDONLY);
int current_fd = openat(base_dir_fd, "current_now", O_RDONLY);
int time_to_empty_fd = openat(base_dir_fd, "time_to_empty_now", O_RDONLY);
int time_to_full_fd = openat(base_dir_fd, "time_to_full_now", O_RDONLY);
long capacity = readint_from_fd(capacity_fd);
long energy = energy_fd >= 0 ? readint_from_fd(energy_fd) : -1;
@ -406,10 +366,6 @@ update_status(struct module *mod)
long time_to_empty = time_to_empty_fd >= 0 ? readint_from_fd(time_to_empty_fd) : -1;
long time_to_full = time_to_full_fd >= 0 ? readint_from_fd(time_to_full_fd) : -1;
if (charge >= -1) {
charge /= m->battery_scale;
}
char buf[512];
const char *status = readline_from_fd(status_fd, sizeof(buf), buf);
@ -453,23 +409,16 @@ update_status(struct module *mod)
}
LOG_DBG("capacity: %ld, energy: %ld, power: %ld, charge=%ld, current=%ld, "
"time-to-empty: %ld, time-to-full: %ld",
capacity, energy, power, charge, current, time_to_empty, time_to_full);
"time-to-empty: %ld, time-to-full: %ld", capacity, energy, power,
charge, current, time_to_empty, time_to_full);
mtx_lock(&mod->lock);
if (m->state != state) {
m->ema_current = (struct current_state){-1, 0, (struct timespec){0, 0}};
}
m->state = state;
m->capacity = capacity;
m->energy = energy;
m->power = power;
m->charge = charge;
if (current != -1) {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
ema_linear(&m->ema_current, (struct current_state){current, current, t}, m->smoothing_scale);
}
m->current = current;
m->time_to_empty = time_to_empty;
m->time_to_full = time_to_full;
mtx_unlock(&mod->lock);
@ -485,10 +434,13 @@ run(struct module *mod)
if (!initialize(m))
return -1;
LOG_INFO("%s: %s %s (at %.1f%% of original capacity)", m->battery, m->manufacturer, m->model,
(m->energy_full > 0 ? 100.0 * m->energy_full / m->energy_full_design
: m->charge_full > 0 ? 100.0 * m->charge_full / m->charge_full_design
: 0.0));
LOG_INFO("%s: %s %s (at %.1f%% of original capacity)",
m->battery, m->manufacturer, m->model,
(m->energy_full > 0
? 100.0 * m->energy_full / m->energy_full_design
: m->charge_full > 0
? 100.0 * m->charge_full / m->charge_full_design
: 0.0));
int ret = 1;
@ -543,11 +495,12 @@ run(struct module *mod)
struct udev_device *dev = udev_monitor_receive_device(mon);
if (dev != NULL) {
const char *sysname = udev_device_get_sysname(dev);
udev_for_us = sysname != NULL && strcmp(sysname, m->battery) == 0;
udev_for_us =
sysname != NULL && strcmp(sysname, m->battery) == 0;
if (!udev_for_us) {
LOG_DBG("udev notification not for us (%s != %s)", m->battery,
sysname != sysname ? sysname : "NULL");
LOG_DBG("udev notification not for us (%s != %s)",
m->battery, sysname != sysname ? sysname : "NULL");
} else
LOG_DBG("triggering update due to udev notification");
@ -573,9 +526,11 @@ run(struct module *mod)
struct timespec timeout_consumed;
timespec_sub(&time_after_poll, &time_before_poll, &timeout_consumed);
const int timeout_consumed_ms = timeout_consumed.tv_sec * 1000 + timeout_consumed.tv_nsec / 1000000;
const int timeout_consumed_ms =
timeout_consumed.tv_sec * 1000 + timeout_consumed.tv_nsec / 1000000;
LOG_DBG("timeout-left before: %dms, consumed: %dms, updated: %dms", timeout_left_ms, timeout_consumed_ms,
LOG_DBG("timeout-left before: %dms, consumed: %dms, updated: %dms",
timeout_left_ms, timeout_consumed_ms,
max(timeout_left_ms - timeout_consumed_ms, 0));
timeout_left_ms -= timeout_consumed_ms;
@ -593,17 +548,13 @@ out:
}
static struct module *
battery_new(const char *battery, struct particle *label, long poll_interval_msecs, int battery_scale,
long smoothing_secs)
battery_new(const char *battery, struct particle *label, long poll_interval_msecs)
{
struct private *m = calloc(1, sizeof(*m));
m->label = label;
m->poll_interval = poll_interval_msecs;
m->battery_scale = battery_scale;
m->smoothing_scale = smoothing_secs * one_sec_in_ns;
m->battery = strdup(battery);
m->state = STATE_UNKNOWN;
m->ema_current = (struct current_state){-1, 0, (struct timespec){0, 0}};
struct module *mod = module_common_new();
mod->private = m;
@ -620,13 +571,13 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *c = yml_get_value(node, "content");
const struct yml_node *name = yml_get_value(node, "name");
const struct yml_node *poll_interval = yml_get_value(node, "poll-interval");
const struct yml_node *battery_scale = yml_get_value(node, "battery-scale");
const struct yml_node *smoothing_secs = yml_get_value(node, "smoothing-secs");
return battery_new(yml_value_as_string(name), conf_to_particle(c, inherited),
(poll_interval != NULL ? yml_value_as_int(poll_interval) : default_poll_interval),
(battery_scale != NULL ? yml_value_as_int(battery_scale) : 1),
(smoothing_secs != NULL ? yml_value_as_int(smoothing_secs) : 100));
return battery_new(
yml_value_as_string(name),
conf_to_particle(c, inherited),
(poll_interval != NULL
? yml_value_as_int(poll_interval)
: default_poll_interval));
}
static bool
@ -638,7 +589,8 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node)
const long value = yml_value_as_int(node);
if (value != 0 && value < min_poll_interval) {
LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval);
LOG_ERR("%s: interval value cannot be less than %ldms",
conf_err_prefix(chain, node), min_poll_interval);
return false;
}
@ -651,8 +603,6 @@ verify_conf(keychain_t *chain, const struct yml_node *node)
static const struct attr_info attrs[] = {
{"name", true, &conf_verify_string},
{"poll-interval", false, &conf_verify_poll_interval},
{"battery-scale", false, &conf_verify_unsigned},
{"smoothing-secs", false, &conf_verify_unsigned},
MODULE_COMMON_ATTRS,
};

View file

@ -1,22 +1,21 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <sys/time.h>
#define LOG_MODULE "clock"
#define LOG_ENABLE_DBG 0
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../plugin.h"
struct private
{
struct private {
struct particle *label;
enum {
UPDATE_GRANULARITY_SECONDS,
@ -58,7 +57,8 @@ content(struct module *mod)
strftime(time_str, sizeof(time_str), m->time_format, tm);
struct tag_set tags = {
.tags = (struct tag *[]){tag_new_string(mod, "time", time_str), tag_new_string(mod, "date", date_str)},
.tags = (struct tag *[]){tag_new_string(mod, "time", time_str),
tag_new_string(mod, "date", date_str)},
.count = 2,
};
@ -90,12 +90,15 @@ run(struct module *mod)
switch (m->update_granularity) {
case UPDATE_GRANULARITY_SECONDS: {
const struct timeval next_second = {.tv_sec = now.tv_sec + 1, .tv_usec = 0};
const struct timeval next_second = {
.tv_sec = now.tv_sec + 1,
.tv_usec = 0};
struct timeval _timeout;
timersub(&next_second, &now, &_timeout);
assert(_timeout.tv_sec == 0 || (_timeout.tv_sec == 1 && _timeout.tv_usec == 0));
assert(_timeout.tv_sec == 0 ||
(_timeout.tv_sec == 1 && _timeout.tv_usec == 0));
timeout_ms = _timeout.tv_usec / 1000;
break;
}
@ -115,7 +118,8 @@ run(struct module *mod)
/* Add 1ms to account for rounding errors */
timeout_ms++;
LOG_DBG("now: %lds %ldµs -> timeout: %dms", now.tv_sec, now.tv_usec, timeout_ms);
LOG_DBG("now: %lds %ldµs -> timeout: %dms",
now.tv_sec, now.tv_usec, timeout_ms);
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}};
if (poll(fds, 1, timeout_ms) < 0) {
@ -138,7 +142,8 @@ run(struct module *mod)
}
static struct module *
clock_new(struct particle *label, const char *date_format, const char *time_format, bool utc)
clock_new(struct particle *label, const char *date_format,
const char *time_format, bool utc)
{
struct private *m = calloc(1, sizeof(*m));
m->label = label;
@ -147,12 +152,20 @@ clock_new(struct particle *label, const char *date_format, const char *time_form
m->utc = utc;
static const char *const seconds_formatters[] = {
"%c", "%s", "%S", "%T", "%r", "%X",
"%c",
"%s",
"%S",
"%T",
"%r",
"%X",
};
m->update_granularity = UPDATE_GRANULARITY_MINUTES;
for (size_t i = 0; i < sizeof(seconds_formatters) / sizeof(seconds_formatters[0]); i++) {
for (size_t i = 0;
i < sizeof(seconds_formatters) / sizeof(seconds_formatters[0]);
i++)
{
if (strstr(time_format, seconds_formatters[i]) != NULL) {
m->update_granularity = UPDATE_GRANULARITY_SECONDS;
break;
@ -160,7 +173,8 @@ clock_new(struct particle *label, const char *date_format, const char *time_form
}
LOG_DBG("using %s update granularity",
(m->update_granularity == UPDATE_GRANULARITY_MINUTES ? "minutes" : "seconds"));
(m->update_granularity == UPDATE_GRANULARITY_MINUTES
? "minutes" : "seconds"));
struct module *mod = module_common_new();
mod->private = m;
@ -179,9 +193,11 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *time_format = yml_get_value(node, "time-format");
const struct yml_node *utc = yml_get_value(node, "utc");
return clock_new(conf_to_particle(c, inherited), date_format != NULL ? yml_value_as_string(date_format) : "%x",
time_format != NULL ? yml_value_as_string(time_format) : "%H:%M",
utc != NULL ? yml_value_as_bool(utc) : false);
return clock_new(
conf_to_particle(c, inherited),
date_format != NULL ? yml_value_as_string(date_format) : "%x",
time_format != NULL ? yml_value_as_string(time_format) : "%H:%M",
utc != NULL ? yml_value_as_bool(utc) : false);
}
static bool

View file

@ -31,8 +31,7 @@ struct cpu_stats {
uint32_t *cur_cores_nidle;
};
struct private
{
struct private {
struct particle *template;
uint16_t interval;
size_t core_count;
@ -70,22 +69,28 @@ get_cpu_nb_cores()
}
static bool
parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, uint32_t *system, uint32_t *idle,
uint32_t *iowait, uint32_t *irq, uint32_t *softirq, uint32_t *steal, uint32_t *guest,
uint32_t *guestnice)
parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice,
uint32_t *system, uint32_t *idle, uint32_t *iowait,
uint32_t *irq, uint32_t *softirq, uint32_t *steal,
uint32_t *guest, uint32_t *guestnice)
{
int32_t core_id;
if (line[sizeof("cpu") - 1] == ' ') {
int read = sscanf(line,
"cpu %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32,
user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice);
int read = sscanf(
line,
"cpu %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32,
user, nice, system, idle, iowait, irq, softirq, steal, guest,
guestnice);
return read == 10;
} else {
int read = sscanf(line,
"cpu%" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32,
&core_id, user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice);
int read = sscanf(
line,
"cpu%" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32,
&core_id, user, nice, system, idle, iowait, irq, softirq, steal,
guest, guestnice);
return read == 11;
}
}
@ -93,12 +98,18 @@ parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice, uint32_t
static uint8_t
get_cpu_usage_percent(const struct cpu_stats *cpu_stats, int8_t core_idx)
{
uint32_t prev_total = cpu_stats->prev_cores_idle[core_idx + 1] + cpu_stats->prev_cores_nidle[core_idx + 1];
uint32_t prev_total =
cpu_stats->prev_cores_idle[core_idx + 1] +
cpu_stats->prev_cores_nidle[core_idx + 1];
uint32_t cur_total = cpu_stats->cur_cores_idle[core_idx + 1] + cpu_stats->cur_cores_nidle[core_idx + 1];
uint32_t cur_total =
cpu_stats->cur_cores_idle[core_idx + 1] +
cpu_stats->cur_cores_nidle[core_idx + 1];
double totald = cur_total - prev_total;
double nidled = cpu_stats->cur_cores_nidle[core_idx + 1] - cpu_stats->prev_cores_nidle[core_idx + 1];
double nidled =
cpu_stats->cur_cores_nidle[core_idx + 1] -
cpu_stats->prev_cores_nidle[core_idx + 1];
double percent = (nidled * 100) / (totald + 1);
return round(percent);
@ -124,7 +135,7 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats, size_t core_count)
size_t len = 0;
ssize_t read;
fp = fopen("/proc/stat", "re");
fp = fopen("/proc/stat", "r");
if (NULL == fp) {
LOG_ERRNO("unable to open /proc/stat");
return;
@ -132,8 +143,10 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats, size_t core_count)
while ((read = getline(&line, &len, fp)) != -1 && core <= core_count) {
if (strncmp(line, "cpu", sizeof("cpu") - 1) == 0) {
if (!parse_proc_stat_line(line, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest,
&guestnice)) {
if (!parse_proc_stat_line(
line, &user, &nice, &system, &idle, &iowait, &irq, &softirq,
&steal, &guest, &guestnice))
{
LOG_ERR("unable to parse /proc/stat line");
goto exit;
}
@ -238,11 +251,15 @@ cpu_new(uint16_t interval, struct particle *template)
p->interval = interval;
p->core_count = nb_cores;
p->cpu_stats.prev_cores_nidle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_nidle));
p->cpu_stats.prev_cores_idle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_idle));
p->cpu_stats.prev_cores_nidle = calloc(
nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_nidle));
p->cpu_stats.prev_cores_idle = calloc(
nb_cores + 1, sizeof(*p->cpu_stats.prev_cores_idle));
p->cpu_stats.cur_cores_nidle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_nidle));
p->cpu_stats.cur_cores_idle = calloc(nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_idle));
p->cpu_stats.cur_cores_nidle = calloc(
nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_nidle));
p->cpu_stats.cur_cores_idle = calloc(
nb_cores + 1, sizeof(*p->cpu_stats.cur_cores_idle));
struct module *mod = module_common_new();
mod->private = p;
@ -259,7 +276,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *interval = yml_get_value(node, "poll-interval");
const struct yml_node *c = yml_get_value(node, "content");
return cpu_new(interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited));
return cpu_new(
interval == NULL ? min_poll_interval : yml_value_as_int(interval),
conf_to_particle(c, inherited));
}
static bool
@ -269,7 +288,8 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node)
return false;
if (yml_value_as_int(node) < min_poll_interval) {
LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval);
LOG_ERR("%s: interval value cannot be less than %ldms",
conf_err_prefix(chain, node), min_poll_interval);
return false;
}

View file

@ -1,9 +1,9 @@
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <poll.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h>
#include <tllist.h>
@ -34,8 +34,7 @@ struct device_stats {
bool exists;
};
struct private
{
struct private {
struct particle *label;
uint16_t interval;
tll(struct device_stats *) devices;
@ -64,7 +63,7 @@ is_disk(char const *name)
return found;
}
static struct device_stats *
static struct device_stats*
new_device_stats(char const *name)
{
struct device_stats *dev = malloc(sizeof(*dev));
@ -85,7 +84,9 @@ destroy(struct module *mod)
{
struct private *m = mod->private;
m->label->destroy(m->label);
tll_foreach(m->devices, it) { free_device_stats(it->item); }
tll_foreach(m->devices, it) {
free_device_stats(it->item);
}
tll_free(m->devices);
free(m);
module_default_destroy(mod);
@ -105,7 +106,7 @@ refresh_device_stats(struct private *m)
size_t len = 0;
ssize_t read;
fp = fopen("/proc/diskstats", "re");
fp = fopen("/proc/diskstats", "r");
if (NULL == fp) {
LOG_ERRNO("unable to open /proc/diskstats");
return;
@ -125,11 +126,13 @@ refresh_device_stats(struct private *m)
* The 'exists' variable is what keep tracks of whether or not /proc/diskstats
* is still reporting the device (i.e., it is still connected).
*/
tll_foreach(m->devices, it) { it->item->exists = false; }
tll_foreach(m->devices, it) {
it->item->exists = false;
}
while ((read = getline(&line, &len, fp)) != -1) {
/*
* For an explanation of the fields below, see
* For an explanation of the fields bellow, see
* https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
*/
uint8_t major_number = 0;
@ -153,23 +156,25 @@ refresh_device_stats(struct private *m)
uint32_t completed_flushes = 0;
uint32_t flushing_time = 0;
if (!sscanf(line,
" %" SCNu8 " %" SCNu8 " %ms %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32,
&major_number, &minor_number, &device_name, &completed_reads, &merged_reads, &sectors_read,
&reading_time, &completed_writes, &merged_writes, &sectors_written, &writting_time,
&ios_in_progress, &io_time, &io_weighted_time, &completed_discards, &merged_discards,
&sectors_discarded, &discarding_time, &completed_flushes, &flushing_time)) {
" %" SCNu8 " %" SCNu8 " %ms %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32,
&major_number, &minor_number, &device_name, &completed_reads,
&merged_reads, &sectors_read, &reading_time, &completed_writes,
&merged_writes, &sectors_written, &writting_time, &ios_in_progress,
&io_time, &io_weighted_time, &completed_discards, &merged_discards,
&sectors_discarded, &discarding_time, &completed_flushes, &flushing_time))
{
LOG_ERR("unable to parse /proc/diskstats line");
free(device_name);
goto exit;
}
bool found = false;
tll_foreach(m->devices, it)
{
tll_foreach(m->devices, it) {
struct device_stats *dev = it->item;
if (strcmp(dev->name, device_name) == 0) {
if (strcmp(dev->name, device_name) == 0){
dev->prev_sectors_read = dev->cur_sectors_read;
dev->prev_sectors_written = dev->cur_sectors_written;
dev->ios_in_progress = ios_in_progress;
@ -195,9 +200,8 @@ refresh_device_stats(struct private *m)
free(device_name);
}
tll_foreach(m->devices, it)
{
if (!it->item->exists) {
tll_foreach(m->devices, it) {
if (!it->item->exists){
free_device_stats(it->item);
tll_remove(m->devices, it);
}
@ -217,13 +221,12 @@ content(struct module *mod)
mtx_lock(&mod->lock);
struct exposable *tag_parts[p->devices.length + 1];
int i = 0;
tll_foreach(p->devices, it)
{
tll_foreach(p->devices, it) {
struct device_stats *dev = it->item;
uint64_t bytes_read = (dev->cur_sectors_read - dev->prev_sectors_read) * 512;
uint64_t bytes_written = (dev->cur_sectors_written - dev->prev_sectors_written) * 512;
if (dev->is_disk) {
if (dev->is_disk){
total_bytes_read += bytes_read;
total_bytes_written += bytes_written;
total_ios_in_progress += dev->ios_in_progress;
@ -311,8 +314,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *interval = yml_get_value(node, "poll-interval");
const struct yml_node *c = yml_get_value(node, "content");
return disk_io_new(interval == NULL ? min_poll_interval : yml_value_as_int(interval),
conf_to_particle(c, inherited));
return disk_io_new(
interval == NULL ? min_poll_interval : yml_value_as_int(interval),
conf_to_particle(c, inherited));
}
static bool
@ -322,7 +326,9 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node)
return false;
if (yml_value_as_int(node) < min_poll_interval) {
LOG_ERR("%s: poll-interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval);
LOG_ERR(
"%s: poll-interval value cannot be less than %ldms",
conf_err_prefix(chain, node), min_poll_interval);
return false;
}

View file

@ -231,7 +231,7 @@ process_line(char *line, struct module *module)
/* No need to check error IMHO */
*target = strtoul(string, NULL, 10);
/* Populate information */
/* Populate informations */
if (index == 6) {
for (size_t id = 1; id <= private->number_of_tags; ++id) {
uint32_t mask = 1 << (id - 1);
@ -249,16 +249,13 @@ process_line(char *line, struct module *module)
assert(false); /* unreachable */
break;
case LINE_MODE_FULLSCREEN:
private
->fullscreen = (strcmp(string, "0") != 0);
private->fullscreen = (strcmp(string, "0") != 0);
break;
case LINE_MODE_FLOATING:
private
->floating = (strcmp(string, "0") != 0);
private->floating = (strcmp(string, "0") != 0);
break;
case LINE_MODE_SELMON:
private
->selmon = (strcmp(string, "0") != 0);
private->selmon = (strcmp(string, "0") != 0);
break;
case LINE_MODE_LAYOUT:
free(private->layout);
@ -330,7 +327,7 @@ run_init(int *inotify_fd, int *inotify_wd, FILE **file, char *dwl_info_filename)
return 1;
}
*file = fopen(dwl_info_filename, "re");
*file = fopen(dwl_info_filename, "r");
if (*file == NULL) {
inotify_rm_watch(*inotify_fd, *inotify_wd);
close(*inotify_fd);
@ -441,7 +438,8 @@ run(struct module *module)
}
static struct module *
dwl_new(struct particle *label, int number_of_tags, struct yml_node const *name_of_tags, char const *dwl_info_filename)
dwl_new(struct particle *label, int number_of_tags,
struct yml_node const *name_of_tags, char const *dwl_info_filename)
{
struct private *private = calloc(1, sizeof(struct private));
private->label = label;
@ -482,8 +480,8 @@ from_conf(struct yml_node const *node, struct conf_inherit inherited)
struct yml_node const *name_of_tags = yml_get_value(node, "name-of-tags");
struct yml_node const *dwl_info_filename = yml_get_value(node, "dwl-info-filename");
return dwl_new(conf_to_particle(content, inherited), yml_value_as_int(number_of_tags), name_of_tags,
yml_value_as_string(dwl_info_filename));
return dwl_new(conf_to_particle(content, inherited), yml_value_as_int(number_of_tags),
name_of_tags, yml_value_as_string(dwl_info_filename));
}
static bool

View file

@ -1,7 +1,7 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
@ -11,8 +11,8 @@
#define LOG_MODULE "foreign-toplevel"
#define LOG_ENABLE_DBG 0
#include "../log.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
#include "../particles/dynlist.h"
#include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "xdg-output-unstable-v1.h"
@ -46,8 +46,7 @@ struct toplevel {
tll(const struct output *) outputs;
};
struct private
{
struct private {
struct particle *template;
uint32_t manager_wl_name;
struct zwlr_foreign_toplevel_manager_v1 *manager;
@ -111,8 +110,7 @@ content(struct module *mod)
const char *current_output = mod->bar->output_name(mod->bar);
tll_foreach(m->toplevels, it)
{
tll_foreach(m->toplevels, it) {
const struct toplevel *top = &it->item;
bool show = false;
@ -120,10 +118,11 @@ content(struct module *mod)
if (m->all_monitors)
show = true;
else if (current_output != NULL) {
tll_foreach(top->outputs, it2)
{
tll_foreach(top->outputs, it2) {
const struct output *output = it2->item;
if (output->name != NULL && strcmp(output->name, current_output) == 0) {
if (output->name != NULL &&
strcmp(output->name, current_output) == 0)
{
show = true;
break;
}
@ -159,18 +158,22 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted)
if (version >= wanted)
return true;
LOG_ERR("%s: need interface version %u, but compositor only implements %u", iface, wanted, version);
LOG_ERR("%s: need interface version %u, but compositor only implements %u",
iface, wanted, version);
return false;
}
static void
xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y)
xdg_output_handle_logical_position(void *data,
struct zxdg_output_v1 *xdg_output,
int32_t x, int32_t y)
{
}
static void
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height)
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
int32_t width, int32_t height)
{
}
@ -180,7 +183,8 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
}
static void
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name)
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
const char *name)
{
struct output *output = data;
struct module *mod = output->mod;
@ -194,7 +198,8 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char
}
static void
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description)
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
const char *description)
{
}
@ -233,7 +238,8 @@ app_id(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, const char *a
}
static void
output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *wl_output)
output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_output *wl_output)
{
struct toplevel *top = data;
struct module *mod = top->mod;
@ -242,8 +248,7 @@ output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct
mtx_lock(&mod->lock);
const struct output *output = NULL;
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
if (it->item.wl_output == wl_output) {
output = &it->item;
break;
@ -255,8 +260,7 @@ output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct
goto out;
}
tll_foreach(top->outputs, it)
{
tll_foreach(top->outputs, it) {
if (it->item == output) {
LOG_ERR("output-enter event on output we're already on");
goto out;
@ -271,7 +275,8 @@ out:
}
static void
output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *wl_output)
output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_output *wl_output)
{
struct toplevel *top = data;
struct module *mod = top->mod;
@ -280,8 +285,7 @@ output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct
mtx_lock(&mod->lock);
const struct output *output = NULL;
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
if (it->item.wl_output == wl_output) {
output = &it->item;
break;
@ -294,10 +298,10 @@ output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct
}
bool output_removed = false;
tll_foreach(top->outputs, it)
{
tll_foreach(top->outputs, it) {
if (it->item == output) {
LOG_DBG("unmapped: %s:%s from %s", top->app_id, top->title, output->name);
LOG_DBG("unmapped: %s:%s from %s",
top->app_id, top->title, output->name);
tll_remove(top->outputs, it);
output_removed = true;
break;
@ -314,7 +318,8 @@ out:
}
static void
state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_array *states)
state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_array *states)
{
struct toplevel *top = data;
@ -324,21 +329,12 @@ state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_arra
bool fullscreen = false;
enum zwlr_foreign_toplevel_handle_v1_state *state;
wl_array_for_each(state, states)
{
wl_array_for_each(state, states) {
switch (*state) {
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED:
maximized = true;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED:
minimized = true;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED:
activated = true;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN:
fullscreen = true;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED: maximized = true; break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED: minimized = true; break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: activated = true; break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN: fullscreen = true; break;
}
}
@ -368,8 +364,7 @@ closed(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle)
struct private *m = mod->private;
mtx_lock(&mod->lock);
tll_foreach(m->toplevels, it)
{
tll_foreach(m->toplevels, it) {
if (it->item.handle == handle) {
toplevel_free(top);
tll_remove(m->toplevels, it);
@ -383,7 +378,9 @@ closed(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle)
}
static void
parent(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct zwlr_foreign_toplevel_handle_v1 *parent)
parent(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
struct zwlr_foreign_toplevel_handle_v1 *parent)
{
}
@ -399,7 +396,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_listener =
};
static void
toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager, struct zwlr_foreign_toplevel_handle_v1 *handle)
toplevel(void *data,
struct zwlr_foreign_toplevel_manager_v1 *manager,
struct zwlr_foreign_toplevel_handle_v1 *handle)
{
struct module *mod = data;
struct private *m = mod->private;
@ -413,13 +412,15 @@ toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager, struct zw
{
tll_push_back(m->toplevels, toplevel);
zwlr_foreign_toplevel_handle_v1_add_listener(handle, &toplevel_listener, &tll_back(m->toplevels));
zwlr_foreign_toplevel_handle_v1_add_listener(
handle, &toplevel_listener, &tll_back(m->toplevels));
}
mtx_unlock(&mod->lock);
}
static void
finished(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager)
finished(void *data,
struct zwlr_foreign_toplevel_manager_v1 *manager)
{
struct module *mod = data;
struct private *m = mod->private;
@ -444,12 +445,15 @@ output_xdg_output(struct output *output)
if (output->xdg_output != NULL)
return;
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(m->xdg_output_manager, output->wl_output);
zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
m->xdg_output_manager, output->wl_output);
zxdg_output_v1_add_listener(
output->xdg_output, &xdg_output_listener, output);
}
static void
handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct module *mod = data;
struct private *m = mod->private;
@ -469,7 +473,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
struct output output = {
.mod = mod,
.wl_name = name,
.wl_output = wl_registry_bind(registry, name, &wl_output_interface, required),
.wl_output = wl_registry_bind(
registry, name, &wl_output_interface, required),
};
mtx_lock(&mod->lock);
@ -483,10 +488,12 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
m->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, required);
m->xdg_output_manager = wl_registry_bind(
registry, name, &zxdg_output_manager_v1_interface, required);
mtx_lock(&mod->lock);
tll_foreach(m->outputs, it) output_xdg_output(&it->item);
tll_foreach(m->outputs, it)
output_xdg_output(&it->item);
mtx_unlock(&mod->lock);
}
}
@ -499,19 +506,16 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
mtx_lock(&mod->lock);
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
const struct output *output = &it->item;
if (output->wl_name == name) {
/* Loop all toplevels */
tll_foreach(m->toplevels, it2)
{
tll_foreach(m->toplevels, it2) {
/* And remove this output from their list of tracked
* outputs */
tll_foreach(it2->item.outputs, it3)
{
tll_foreach(it2->item.outputs, it3) {
if (it3->item == output) {
tll_remove(it2->item.outputs, it3);
break;
@ -547,8 +551,9 @@ run(struct module *mod)
goto out;
}
if ((registry = wl_display_get_registry(display)) == NULL
|| wl_registry_add_listener(registry, &registry_listener, mod) != 0) {
if ((registry = wl_display_get_registry(display)) == NULL ||
wl_registry_add_listener(registry, &registry_listener, mod) != 0)
{
LOG_ERR("failed to get Wayland registry");
goto out;
}
@ -556,14 +561,18 @@ run(struct module *mod)
wl_display_roundtrip(display);
if (m->manager_wl_name == 0) {
LOG_ERR("compositor does not implement the foreign-toplevel-manager interface");
LOG_ERR(
"compositor does not implement the foreign-toplevel-manager interface");
goto out;
}
m->manager = wl_registry_bind(registry, m->manager_wl_name, &zwlr_foreign_toplevel_manager_v1_interface,
required_manager_interface_version);
m->manager = wl_registry_bind(
registry, m->manager_wl_name,
&zwlr_foreign_toplevel_manager_v1_interface,
required_manager_interface_version);
zwlr_foreign_toplevel_manager_v1_add_listener(m->manager, &manager_listener, mod);
zwlr_foreign_toplevel_manager_v1_add_listener(
m->manager, &manager_listener, mod);
while (true) {
wl_display_flush(display);
@ -597,14 +606,12 @@ run(struct module *mod)
}
out:
tll_foreach(m->toplevels, it)
{
tll_foreach(m->toplevels, it) {
toplevel_free(&it->item);
tll_remove(m->toplevels, it);
}
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
output_free(&it->item);
tll_remove(m->outputs, it);
}
@ -642,7 +649,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *c = yml_get_value(node, "content");
const struct yml_node *all_monitors = yml_get_value(node, "all-monitors");
return ftop_new(conf_to_particle(c, inherited), all_monitors != NULL ? yml_value_as_bool(all_monitors) : false);
return ftop_new(
conf_to_particle(c, inherited),
all_monitors != NULL ? yml_value_as_bool(all_monitors) : false);
}
static bool

View file

@ -1,15 +1,15 @@
#include "i3-common.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <poll.h>
#if defined(ENABLE_X11)
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#endif
#include <json-c/json_tokener.h>
@ -19,7 +19,7 @@
#include "../log.h"
#if defined(ENABLE_X11)
#include "../xcb.h"
#include "../xcb.h"
#endif
#include "i3-ipc.h"
@ -41,11 +41,14 @@ get_socket_address_x11(struct sockaddr_un *addr)
xcb_atom_t atom = get_atom(conn, "I3_SOCKET_PATH");
assert(atom != XCB_ATOM_NONE);
xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(conn, false, screen->root, atom,
XCB_GET_PROPERTY_TYPE_ANY, 0, sizeof(addr->sun_path));
xcb_get_property_cookie_t cookie
= xcb_get_property_unchecked(
conn, false, screen->root, atom,
XCB_GET_PROPERTY_TYPE_ANY, 0, sizeof(addr->sun_path));
xcb_generic_error_t *err = NULL;
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, &err);
xcb_get_property_reply_t *reply =
xcb_get_property_reply(conn, cookie, &err);
bool ret = false;
if (err != NULL) {
@ -99,7 +102,11 @@ bool
i3_send_pkg(int sock, int cmd, char *data)
{
const size_t size = data != NULL ? strlen(data) : 0;
const i3_ipc_header_t hdr = {.magic = I3_IPC_MAGIC, .size = size, .type = cmd};
const i3_ipc_header_t hdr = {
.magic = I3_IPC_MAGIC,
.size = size,
.type = cmd
};
if (write(sock, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr))
return false;
@ -113,7 +120,8 @@ i3_send_pkg(int sock, int cmd, char *data)
}
bool
i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void *data)
i3_receive_loop(int abort_fd, int sock,
const struct i3_ipc_callbacks *cbs, void *data)
{
/* Initial reply typically requires a couple of KB. But we often
* need more later. For example, switching workspaces can result
@ -125,7 +133,10 @@ i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void
bool err = false;
while (!err) {
struct pollfd fds[] = {{.fd = abort_fd, .events = POLLIN}, {.fd = sock, .events = POLLIN}};
struct pollfd fds[] = {
{.fd = abort_fd, .events = POLLIN},
{.fd = sock, .events = POLLIN}
};
int res = poll(fds, 2, -1);
if (res <= 0) {
@ -148,11 +159,13 @@ i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void
/* Grow receive buffer, if necessary */
if (buf_idx == reply_buf_size) {
LOG_DBG("growing reply buffer: %zu -> %zu", reply_buf_size, reply_buf_size * 2);
LOG_DBG("growing reply buffer: %zu -> %zu",
reply_buf_size, reply_buf_size * 2);
char *new_buf = realloc(buf, reply_buf_size * 2);
if (new_buf == NULL) {
LOG_ERR("failed to grow reply buffer from %zu to %zu bytes", reply_buf_size, reply_buf_size * 2);
LOG_ERR("failed to grow reply buffer from %zu to %zu bytes",
reply_buf_size, reply_buf_size * 2);
err = true;
break;
}
@ -175,8 +188,10 @@ i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void
while (!err && buf_idx >= sizeof(i3_ipc_header_t)) {
const i3_ipc_header_t *hdr = (const i3_ipc_header_t *)buf;
if (strncmp(hdr->magic, I3_IPC_MAGIC, sizeof(hdr->magic)) != 0) {
LOG_ERR("i3 IPC header magic mismatch: expected \"%.*s\", got \"%.*s\"", (int)sizeof(hdr->magic),
I3_IPC_MAGIC, (int)sizeof(hdr->magic), hdr->magic);
LOG_ERR(
"i3 IPC header magic mismatch: expected \"%.*s\", got \"%.*s\"",
(int)sizeof(hdr->magic), I3_IPC_MAGIC,
(int)sizeof(hdr->magic), hdr->magic);
err = true;
break;
@ -195,10 +210,10 @@ i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void
char json_str[hdr->size + 1];
memcpy(json_str, &buf[sizeof(*hdr)], hdr->size);
json_str[hdr->size] = '\0';
// printf("raw: %s\n", json_str);
//printf("raw: %s\n", json_str);
LOG_DBG("raw: %s\n", json_str);
// json_tokener *tokener = json_tokener_new();
//json_tokener *tokener = json_tokener_new();
struct json_object *json = json_tokener_parse(json_str);
if (json == NULL) {
LOG_ERR("failed to parse json");
@ -247,13 +262,13 @@ i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void
break;
#endif
/* Sway extensions */
case 100: /* IPC_GET_INPUTS */
case 100: /* IPC_GET_INPUTS */
pkt_handler = cbs->reply_inputs;
break;
/*
* Events
*/
/*
* Events
*/
case I3_IPC_EVENT_WORKSPACE:
pkt_handler = cbs->event_workspace;
@ -280,7 +295,7 @@ i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *cbs, void
pkt_handler = cbs->event_tick;
break;
/* Sway extensions */
/* Sway extensions */
#define SWAY_IPC_EVENT_INPUT ((1u << 31) | 21)
case SWAY_IPC_EVENT_INPUT:
pkt_handler = cbs->event_input;

View file

@ -2,8 +2,8 @@
#include <stdbool.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <json-c/json_util.h>
@ -43,4 +43,6 @@ struct i3_ipc_callbacks {
i3_ipc_callback_t event_input;
};
bool i3_receive_loop(int abort_fd, int sock, const struct i3_ipc_callbacks *callbacks, void *data);
bool i3_receive_loop(
int abort_fd, int sock,
const struct i3_ipc_callbacks *callbacks, void *data);

View file

@ -1,27 +1,27 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <unistd.h>
#include <assert.h>
#include <threads.h>
#include <fcntl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <tllist.h>
#define LOG_MODULE "i3"
#define LOG_ENABLE_DBG 0
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
#include "i3-common.h"
#include "i3-ipc.h"
#include "i3-common.h"
enum sort_mode { SORT_NONE, SORT_NATIVE, SORT_ASCENDING, SORT_DESCENDING };
enum sort_mode {SORT_NONE, SORT_NATIVE, SORT_ASCENDING, SORT_DESCENDING};
struct ws_content {
char *name;
@ -48,8 +48,7 @@ struct workspace {
} window;
};
struct private
{
struct private {
int left_spacing;
int right_spacing;
@ -106,8 +105,10 @@ workspace_from_json(const struct json_object *json, struct workspace *ws)
{
/* Always present */
struct json_object *id, *name, *output;
if (!json_object_object_get_ex(json, "id", &id) || !json_object_object_get_ex(json, "name", &name)
|| !json_object_object_get_ex(json, "output", &output)) {
if (!json_object_object_get_ex(json, "id", &id) ||
!json_object_object_get_ex(json, "name", &name) ||
!json_object_object_get_ex(json, "output", &output))
{
LOG_ERR("workspace reply/event without 'name' and/or 'output' "
"properties");
return false;
@ -125,12 +126,14 @@ workspace_from_json(const struct json_object *json, struct workspace *ws)
const char *name_as_string = json_object_get_string(name);
const size_t node_count = focus != NULL ? json_object_array_length(focus) : 0;
const size_t node_count = focus != NULL
? json_object_array_length(focus)
: 0;
const bool is_empty = node_count == 0;
int name_as_int = workspace_name_as_int(name_as_string);
*ws = (struct workspace){
*ws = (struct workspace) {
.id = json_object_get_int(id),
.name = strdup(name_as_string),
.name_as_int = name_as_int,
@ -149,12 +152,9 @@ workspace_from_json(const struct json_object *json, struct workspace *ws)
static void
workspace_free_persistent(struct workspace *ws)
{
free(ws->output);
ws->output = NULL;
free(ws->window.title);
ws->window.title = NULL;
free(ws->window.application);
ws->window.application = NULL;
free(ws->output); ws->output = NULL;
free(ws->window.title); ws->window.title = NULL;
free(ws->window.application); ws->window.application = NULL;
ws->id = -1;
}
@ -162,15 +162,13 @@ static void
workspace_free(struct workspace *ws)
{
workspace_free_persistent(ws);
free(ws->name);
ws->name = NULL;
free(ws->name); ws->name = NULL;
}
static void
workspaces_free(struct private *m, bool free_persistent)
{
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (free_persistent || !it->item.persistent) {
workspace_free(&it->item);
tll_remove(m->workspaces, it);
@ -178,6 +176,7 @@ workspaces_free(struct private *m, bool free_persistent)
}
}
static void
workspace_add(struct private *m, struct workspace ws)
{
@ -188,8 +187,7 @@ workspace_add(struct private *m, struct workspace ws)
case SORT_NATIVE:
if (ws.name_as_int >= 0) {
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (it->item.name_as_int < 0)
continue;
if (it->item.name_as_int > ws.name_as_int) {
@ -204,8 +202,7 @@ workspace_add(struct private *m, struct workspace ws)
case SORT_ASCENDING:
if (ws.name_as_int >= 0) {
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (it->item.name_as_int < 0)
continue;
if (it->item.name_as_int > ws.name_as_int) {
@ -214,9 +211,10 @@ workspace_add(struct private *m, struct workspace ws)
}
}
} else {
tll_foreach(m->workspaces, it)
{
if (strcoll(it->item.name, ws.name) > 0 || it->item.name_as_int >= 0) {
tll_foreach(m->workspaces, it) {
if (strcoll(it->item.name, ws.name) > 0 ||
it->item.name_as_int >= 0)
{
tll_insert_before(m->workspaces, it, ws);
return;
}
@ -227,16 +225,14 @@ workspace_add(struct private *m, struct workspace ws)
case SORT_DESCENDING:
if (ws.name_as_int >= 0) {
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (it->item.name_as_int < ws.name_as_int) {
tll_insert_before(m->workspaces, it, ws);
return;
}
}
} else {
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (it->item.name_as_int >= 0)
continue;
if (strcoll(it->item.name, ws.name) < 0) {
@ -253,8 +249,7 @@ workspace_add(struct private *m, struct workspace ws)
static void
workspace_del(struct private *m, int id)
{
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
struct workspace *ws = &it->item;
if (ws->id != id)
@ -269,8 +264,7 @@ workspace_del(struct private *m, int id)
static struct workspace *
workspace_lookup(struct private *m, int id)
{
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
struct workspace *ws = &it->item;
if (ws->id == id)
return ws;
@ -281,8 +275,7 @@ workspace_lookup(struct private *m, int id)
static struct workspace *
workspace_lookup_by_name(struct private *m, const char *name)
{
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
struct workspace *ws = &it->item;
if (strcmp(ws->name, name) == 0)
return ws;
@ -346,9 +339,13 @@ workspace_update_or_add(struct private *m, const struct json_object *ws_json)
if (json_object_object_get_ex(ws_json, "name", &_name)) {
const char *name = json_object_get_string(_name);
if (name != NULL) {
struct workspace *maybe_persistent = workspace_lookup_by_name(m, name);
struct workspace *maybe_persistent =
workspace_lookup_by_name(m, name);
if (maybe_persistent != NULL && maybe_persistent->persistent && maybe_persistent->id < 0) {
if (maybe_persistent != NULL &&
maybe_persistent->persistent &&
maybe_persistent->id < 0)
{
already_exists = maybe_persistent;
}
}
@ -421,12 +418,11 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
bool is_rename = strcmp(change_str, "rename") == 0;
bool is_move = strcmp(change_str, "move") == 0;
bool is_urgent = strcmp(change_str, "urgent") == 0;
bool is_reload = strcmp(change_str, "reload") == 0;
struct json_object *current, *_current_id;
if ((!json_object_object_get_ex(json, "current", &current)
|| !json_object_object_get_ex(current, "id", &_current_id))
&& !is_reload) {
if (!json_object_object_get_ex(json, "current", &current) ||
!json_object_object_get_ex(current, "id", &_current_id))
{
LOG_ERR("workspace event without 'current' and/or 'id' properties");
return false;
}
@ -454,8 +450,10 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
else if (is_focused) {
struct json_object *old, *_old_id, *urgent;
if (!json_object_object_get_ex(json, "old", &old) || !json_object_object_get_ex(old, "id", &_old_id)
|| !json_object_object_get_ex(current, "urgent", &urgent)) {
if (!json_object_object_get_ex(json, "old", &old) ||
!json_object_object_get_ex(old, "id", &_old_id) ||
!json_object_object_get_ex(current, "urgent", &urgent))
{
LOG_ERR("workspace 'focused' event without 'old', 'name' and/or 'urgent' property");
mtx_unlock(&mod->lock);
return false;
@ -467,8 +465,7 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
LOG_DBG("w: %s", w->name);
/* Mark all workspaces on current's output invisible */
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
struct workspace *ws = &it->item;
if (ws->output != NULL && strcmp(ws->output, w->output) == 0)
ws->visible = false;
@ -502,8 +499,7 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
/* Re-add the workspace to ensure correct sorting */
struct workspace ws = *w;
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (it->item.id == current_id) {
tll_remove(m->workspaces, it);
break;
@ -514,6 +510,7 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
else if (is_move) {
struct workspace *w = workspace_lookup(m, current_id);
assert(w != NULL);
struct json_object *_current_output;
if (!json_object_object_get_ex(current, "output", &_current_output)) {
@ -521,22 +518,16 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
mtx_unlock(&mod->lock);
return false;
}
const char *current_output_string = json_object_get_string(_current_output);
/* Ignore fallback_output ("For when there's no connected outputs") */
if (strcmp(current_output_string, "FALLBACK") != 0) {
free(w->output);
w->output = strdup(json_object_get_string(_current_output));
assert(w != NULL);
free(w->output);
w->output = strdup(current_output_string);
/*
* If the moved workspace was focused, schedule a full update because
* visibility for other workspaces may have changed.
*/
if (w->focused) {
i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
}
/*
* If the moved workspace was focused, schedule a full update because
* visibility for other workspaces may have changed.
*/
if (w->focused) {
i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
}
}
@ -552,12 +543,6 @@ handle_workspace_event(int sock, int type, const struct json_object *json, void
w->urgent = json_object_get_boolean(urgent);
}
else if (is_reload) {
/* Schedule full update to check if anything was changed
* during reload */
i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
}
else {
LOG_WARN("unimplemented workspace event '%s'", change_str);
}
@ -584,19 +569,19 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m
}
const char *change_str = json_object_get_string(change);
bool is_new = strcmp(change_str, "new") == 0;
bool is_focus = strcmp(change_str, "focus") == 0;
bool is_close = strcmp(change_str, "close") == 0;
bool is_title = strcmp(change_str, "title") == 0;
if (!is_focus && !is_close && !is_title)
if (!is_new && !is_focus && !is_close && !is_title)
return true;
mtx_lock(&mod->lock);
struct workspace *ws = NULL;
size_t focused = 0;
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
if (it->item.focused) {
ws = &it->item;
focused++;
@ -606,20 +591,6 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m
assert(focused == 1);
assert(ws != NULL);
struct json_object *container, *id, *name;
if (!json_object_object_get_ex(json, "container", &container) || !json_object_object_get_ex(container, "id", &id)
|| !json_object_object_get_ex(container, "name", &name)) {
mtx_unlock(&mod->lock);
LOG_ERR("window event without 'container' with 'id' and 'name'");
return false;
}
if ((is_close || is_title) && ws->window.id != json_object_get_int(id)) {
/* Ignore close event and title changed event if it's not current window */
mtx_unlock(&mod->lock);
return true;
}
if (is_close) {
free(ws->window.title);
free(ws->window.application);
@ -628,9 +599,33 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m
ws->window.title = ws->window.application = NULL;
ws->window.pid = -1;
/* May not be true, but e.g. a subsequent “focus” event will
* reset it... */
ws->empty = true;
m->dirty = true;
mtx_unlock(&mod->lock);
return true;
}
/* Non-close event - thus workspace cannot be empty */
ws->empty = false;
struct json_object *container, *id, *name;
if (!json_object_object_get_ex(json, "container", &container) ||
!json_object_object_get_ex(container, "id", &id) ||
!json_object_object_get_ex(container, "name", &name))
{
mtx_unlock(&mod->lock);
LOG_ERR("window event without 'container' with 'id' and 'name'");
return false;
}
if (is_title && ws->window.id != json_object_get_int(id)) {
/* Ignore title changed event if it's not current window */
mtx_unlock(&mod->lock);
return true;
}
free(ws->window.title);
@ -651,24 +646,27 @@ handle_window_event(int sock, int type, const struct json_object *json, void *_m
struct json_object *app_id;
struct json_object *pid;
if (json_object_object_get_ex(container, "app_id", &app_id) && json_object_get_string(app_id) != NULL) {
if (json_object_object_get_ex(container, "app_id", &app_id) &&
json_object_get_string(app_id) != NULL)
{
free(ws->window.application);
ws->window.application = strdup(json_object_get_string(app_id));
LOG_DBG("application: \"%s\", via 'app_id'", ws->window.application);
}
/* If PID has changed, update application name from /proc/<pid>/comm */
else if (json_object_object_get_ex(container, "pid", &pid) && ws->window.pid != json_object_get_int(pid)) {
else if (json_object_object_get_ex(container, "pid", &pid) &&
ws->window.pid != json_object_get_int(pid))
{
ws->window.pid = json_object_get_int(pid);
char path[64];
snprintf(path, sizeof(path), "/proc/%u/comm", ws->window.pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
int fd = open(path, O_RDONLY);
if (fd == -1) {
/* Application may simply have terminated */
free(ws->window.application);
ws->window.application = NULL;
free(ws->window.application); ws->window.application = NULL;
ws->window.pid = -1;
m->dirty = true;
@ -840,8 +838,7 @@ content(struct module *mod)
struct exposable *particles[tll_length(m->workspaces) + 1];
struct exposable *current = NULL;
tll_foreach(m->workspaces, it)
{
tll_foreach(m->workspaces, it) {
struct workspace *ws = &it->item;
const struct ws_content *template = NULL;
@ -857,12 +854,21 @@ content(struct module *mod)
template = ws_content_for_name(m, "");
}
const char *state = ws->urgent ? "urgent" : ws->visible ? ws->focused ? "focused" : "unfocused" : "invisible";
const char *state =
ws->urgent ? "urgent" :
ws->visible ? ws->focused ? "focused" : "unfocused" :
"invisible";
LOG_DBG("name=%s (name-as-int=%d): visible=%s, focused=%s, urgent=%s, empty=%s, state=%s, "
"application=%s, title=%s, mode=%s",
ws->name, ws->name_as_int, ws->visible ? "yes" : "no", ws->focused ? "yes" : "no",
ws->urgent ? "yes" : "no", ws->empty ? "yes" : "no", state, ws->window.application, ws->window.title,
ws->name, ws->name_as_int,
ws->visible ? "yes" : "no",
ws->focused ? "yes" : "no",
ws->urgent ? "yes" : "no",
ws->empty ? "yes" : "no",
state,
ws->window.application,
ws->window.title,
m->mode);
const char *name = ws->name;
@ -876,7 +882,6 @@ content(struct module *mod)
struct tag_set tags = {
.tags = (struct tag *[]){
tag_new_string(mod, "name", name),
tag_new_string(mod, "output", ws->output),
tag_new_bool(mod, "visible", ws->visible),
tag_new_bool(mod, "focused", ws->focused),
tag_new_bool(mod, "urgent", ws->urgent),
@ -888,7 +893,7 @@ content(struct module *mod)
tag_new_string(mod, "mode", m->mode),
},
.count = 10,
.count = 9,
};
if (ws->focused) {
@ -898,9 +903,12 @@ content(struct module *mod)
}
if (template == NULL) {
LOG_WARN("no ws template for %s, and no default template available", ws->name);
LOG_WARN(
"no ws template for %s, and no default template available",
ws->name);
} else {
particles[particle_count++] = template->content->instantiate(template->content, &tags);
particles[particle_count++] = template->content->instantiate(
template->content, &tags);
}
tag_set_destroy(&tags);
@ -910,7 +918,8 @@ content(struct module *mod)
particles[particle_count++] = current;
mtx_unlock(&mod->lock);
return dynlist_exposable_new(particles, particle_count, m->left_spacing, m->right_spacing);
return dynlist_exposable_new(
particles, particle_count, m->left_spacing, m->right_spacing);
}
/* Maps workspace name to a content particle. */
@ -920,8 +929,10 @@ struct i3_workspaces {
};
static struct module *
i3_new(struct i3_workspaces workspaces[], size_t workspace_count, int left_spacing, int right_spacing,
enum sort_mode sort_mode, size_t persistent_count, const char *persistent_workspaces[static persistent_count],
i3_new(struct i3_workspaces workspaces[], size_t workspace_count,
int left_spacing, int right_spacing, enum sort_mode sort_mode,
size_t persistent_count,
const char *persistent_workspaces[static persistent_count],
bool strip_workspace_numbers)
{
struct private *m = calloc(1, sizeof(*m));
@ -942,7 +953,8 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count, int left_spaci
m->sort_mode = sort_mode;
m->persistent_count = persistent_count;
m->persistent_workspaces = calloc(persistent_count, sizeof(m->persistent_workspaces[0]));
m->persistent_workspaces = calloc(
persistent_count, sizeof(m->persistent_workspaces[0]));
for (size_t i = 0; i < persistent_count; i++)
m->persistent_workspaces[i] = strdup(persistent_workspaces[i]);
@ -965,26 +977,31 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *right_spacing = yml_get_value(node, "right-spacing");
const struct yml_node *sort = yml_get_value(node, "sort");
const struct yml_node *persistent = yml_get_value(node, "persistent");
const struct yml_node *strip_workspace_number = yml_get_value(node, "strip-workspace-numbers");
const struct yml_node *strip_workspace_number = yml_get_value(
node, "strip-workspace-numbers");
int left = spacing != NULL ? yml_value_as_int(spacing) : left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
int right = spacing != NULL ? yml_value_as_int(spacing)
: right_spacing != NULL ? yml_value_as_int(right_spacing)
: 0;
int left = spacing != NULL ? yml_value_as_int(spacing) :
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
int right = spacing != NULL ? yml_value_as_int(spacing) :
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
const char *sort_value = sort != NULL ? yml_value_as_string(sort) : NULL;
enum sort_mode sort_mode = sort_value == NULL ? SORT_NONE
: strcmp(sort_value, "none") == 0 ? SORT_NONE
: strcmp(sort_value, "native") == 0 ? SORT_NATIVE
: strcmp(sort_value, "ascending") == 0 ? SORT_ASCENDING
: SORT_DESCENDING;
enum sort_mode sort_mode =
sort_value == NULL ? SORT_NONE :
strcmp(sort_value, "none") == 0 ? SORT_NONE :
strcmp(sort_value, "native") == 0 ? SORT_NATIVE :
strcmp(sort_value, "ascending") == 0 ? SORT_ASCENDING : SORT_DESCENDING;
const size_t persistent_count = persistent != NULL ? yml_list_length(persistent) : 0;
const size_t persistent_count =
persistent != NULL ? yml_list_length(persistent) : 0;
const char *persistent_workspaces[persistent_count];
if (persistent != NULL) {
size_t idx = 0;
for (struct yml_list_iter it = yml_list_iter(persistent); it.node != NULL; yml_list_next(&it), idx++) {
for (struct yml_list_iter it = yml_list_iter(persistent);
it.node != NULL;
yml_list_next(&it), idx++)
{
persistent_workspaces[idx] = yml_value_as_string(it.node);
}
}
@ -992,27 +1009,38 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
struct i3_workspaces workspaces[yml_dict_length(c)];
size_t idx = 0;
for (struct yml_dict_iter it = yml_dict_iter(c); it.key != NULL; yml_dict_next(&it), idx++) {
for (struct yml_dict_iter it = yml_dict_iter(c);
it.key != NULL;
yml_dict_next(&it), idx++)
{
workspaces[idx].name = yml_value_as_string(it.key);
workspaces[idx].content = conf_to_particle(it.value, inherited);
}
return i3_new(workspaces, yml_dict_length(c), left, right, sort_mode, persistent_count, persistent_workspaces,
(strip_workspace_number != NULL ? yml_value_as_bool(strip_workspace_number) : false));
return i3_new(workspaces, yml_dict_length(c), left, right, sort_mode,
persistent_count, persistent_workspaces,
(strip_workspace_number != NULL
? yml_value_as_bool(strip_workspace_number) : false));
}
static bool
verify_content(keychain_t *chain, const struct yml_node *node)
{
if (!yml_is_dict(node)) {
LOG_ERR("%s: must be a dictionary of workspace-name: particle mappings", conf_err_prefix(chain, node));
LOG_ERR(
"%s: must be a dictionary of workspace-name: particle mappings",
conf_err_prefix(chain, node));
return false;
}
for (struct yml_dict_iter it = yml_dict_iter(node); it.key != NULL; yml_dict_next(&it)) {
for (struct yml_dict_iter it = yml_dict_iter(node);
it.key != NULL;
yml_dict_next(&it))
{
const char *key = yml_value_as_string(it.key);
if (key == NULL) {
LOG_ERR("%s: key must be a string (a i3 workspace name)", conf_err_prefix(chain, it.key));
LOG_ERR("%s: key must be a string (a i3 workspace name)",
conf_err_prefix(chain, it.key));
return false;
}
@ -1028,7 +1056,8 @@ verify_content(keychain_t *chain, const struct yml_node *node)
static bool
verify_sort(keychain_t *chain, const struct yml_node *node)
{
return conf_verify_enum(chain, node, (const char *[]){"none", "native", "ascending", "descending"}, 4);
return conf_verify_enum(
chain, node, (const char *[]){"none", "native", "ascending", "descending"}, 4);
}
static bool
@ -1061,5 +1090,5 @@ const struct module_iface module_i3_iface = {
};
#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
extern const struct module_iface iface __attribute__((weak, alias("module_i3_iface")));
extern const struct module_iface iface __attribute__((weak, alias("module_i3_iface"))) ;
#endif

View file

@ -1,14 +1,16 @@
#include <assert.h>
#include <stdlib.h>
#include <assert.h>
#include <poll.h>
#include "../config-verify.h"
#include "../config.h"
#include "../config-verify.h"
#include "../module.h"
#include "../plugin.h"
struct private { struct particle *label; };
struct private {
struct particle *label;
};
static void
destroy(struct module *mod)

View file

@ -24,8 +24,6 @@ struct private
{
struct particle *label;
uint16_t interval;
uint64_t mem_free;
uint64_t mem_total;
};
static void
@ -54,7 +52,7 @@ get_mem_stats(uint64_t *mem_free, uint64_t *mem_total)
size_t len = 0;
ssize_t read = 0;
fp = fopen("/proc/meminfo", "re");
fp = fopen("/proc/meminfo", "r");
if (NULL == fp) {
LOG_ERRNO("unable to open /proc/meminfo");
return false;
@ -81,12 +79,15 @@ static struct exposable *
content(struct module *mod)
{
const struct private *p = mod->private;
uint64_t mem_free = 0;
uint64_t mem_used = 0;
uint64_t mem_total = 0;
mtx_lock(&mod->lock);
if (!get_mem_stats(&mem_free, &mem_total)) {
LOG_ERR("unable to retrieve the memory stats");
}
const uint64_t mem_free = p->mem_free;
const uint64_t mem_total = p->mem_total;
const uint64_t mem_used = mem_total - mem_free;
mem_used = mem_total - mem_free;
double percent_used = ((double)mem_used * 100) / (mem_total + 1);
double percent_free = ((double)mem_free * 100) / (mem_total + 1);
@ -101,7 +102,6 @@ content(struct module *mod)
struct exposable *exposable = p->label->instantiate(p->label, &tags);
tag_set_destroy(&tags);
mtx_unlock(&mod->lock);
return exposable;
}
@ -127,13 +127,6 @@ run(struct module *mod)
if (fds[0].revents & POLLIN)
break;
mtx_lock(&mod->lock);
p->mem_free = 0;
p->mem_total = 0;
if (!get_mem_stats(&p->mem_free, &p->mem_total)) {
LOG_ERR("unable to retrieve the memory stats");
}
mtx_unlock(&mod->lock);
bar->refresh(bar);
}
@ -162,7 +155,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *interval = yml_get_value(node, "poll-interval");
const struct yml_node *c = yml_get_value(node, "content");
return mem_new(interval == NULL ? min_poll_interval : yml_value_as_int(interval), conf_to_particle(c, inherited));
return mem_new(
interval == NULL ? min_poll_interval : yml_value_as_int(interval),
conf_to_particle(c, inherited));
}
static bool
@ -172,7 +167,8 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node)
return false;
if (yml_value_as_int(node) < min_poll_interval) {
LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval);
LOG_ERR("%s: interval value cannot be less than %ldms",
conf_err_prefix(chain, node), min_poll_interval);
return false;
}

View file

@ -45,12 +45,6 @@ plugin_script_enabled = get_option('plugin-script').allowed()
json_sway_xkb = dependency('json-c', required: get_option('plugin-sway-xkb'))
plugin_sway_xkb_enabled = json_sway_xkb.found()
json_niri_language = dependency('json-c', required: get_option('plugin-niri-language'))
plugin_niri_language_enabled = json_niri_language.found()
json_niri_workspaces = dependency('json-c', required: get_option('plugin-niri-workspaces'))
plugin_niri_workspaces_enabled = json_niri_workspaces.found()
xcb_xkb = dependency('xcb-xkb', required: get_option('plugin-xkb'))
plugin_xkb_enabled = backend_x11 and xcb_xkb.found()
@ -104,7 +98,7 @@ if plugin_label_enabled
endif
if plugin_network_enabled
mod_data += {'network': [[], [dynlist]]}
mod_data += {'network': [[], []]}
endif
if plugin_pipewire_enabled
@ -127,14 +121,6 @@ if plugin_sway_xkb_enabled
mod_data += {'sway-xkb': [['i3-common.c', 'i3-common.h'], [dynlist, json_sway_xkb]]}
endif
if plugin_niri_language_enabled
mod_data += {'niri-language': [['niri-common.c', 'niri-common.h'], [dynlist, json_niri_language]]}
endif
if plugin_niri_workspaces_enabled
mod_data += {'niri-workspaces': [['niri-common.c', 'niri-common.h'], [dynlist, json_niri_workspaces]]}
endif
if plugin_xkb_enabled
mod_data += {'xkb': [[], [xcb_stuff, xcb_xkb]]}
endif

View file

@ -1,34 +1,33 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <time.h>
#include <threads.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
#include <poll.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <mpd/client.h>
#define LOG_MODULE "mpd"
#define LOG_ENABLE_DBG 0
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../plugin.h"
struct private
{
struct private {
char *host;
uint16_t port;
struct particle *label;
@ -39,8 +38,7 @@ struct private
bool repeat;
bool random;
bool consume;
bool single;
int volume;
int volume;
char *album;
char *artist;
char *title;
@ -62,9 +60,11 @@ destroy(struct module *mod)
struct private *m = mod->private;
if (m->refresh_thread_id != 0) {
assert(m->refresh_abort_fd != -1);
if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) {
if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t))
!= sizeof(uint64_t))
{
LOG_ERRNO("failed to signal abort to refresher thread");
} else {
} else{
int res;
thrd_join(m->refresh_thread_id, &res);
}
@ -132,11 +132,12 @@ content(struct module *mod)
if (m->state == MPD_STATE_PLAY) {
elapsed += timespec_diff_milli_seconds(&now, &m->elapsed.when);
if (elapsed > m->duration) {
LOG_DBG("dynamic update of elapsed overflowed: "
"elapsed=%" PRIu64 ", duration=%" PRIu64,
elapsed, m->duration);
LOG_DBG(
"dynamic update of elapsed overflowed: "
"elapsed=%"PRIu64", duration=%"PRIu64, elapsed, m->duration);
elapsed = m->duration;
}
}
unsigned elapsed_secs = elapsed / 1000;
@ -153,23 +154,16 @@ content(struct module *mod)
state_str = "offline";
else {
switch (m->state) {
case MPD_STATE_UNKNOWN:
state_str = "unknown";
break;
case MPD_STATE_STOP:
state_str = "stopped";
break;
case MPD_STATE_PAUSE:
state_str = "paused";
break;
case MPD_STATE_PLAY:
state_str = "playing";
break;
case MPD_STATE_UNKNOWN: state_str = "unknown"; break;
case MPD_STATE_STOP: state_str = "stopped"; break;
case MPD_STATE_PAUSE: state_str = "paused"; break;
case MPD_STATE_PLAY: state_str = "playing"; break;
}
}
/* Tell particle to real-time track? */
enum tag_realtime_unit realtime = m->state == MPD_STATE_PLAY ? TAG_REALTIME_MSECS : TAG_REALTIME_NONE;
enum tag_realtime_unit realtime = m->state == MPD_STATE_PLAY
? TAG_REALTIME_MSECS : TAG_REALTIME_NONE;
struct tag_set tags = {
.tags = (struct tag *[]){
@ -177,7 +171,6 @@ content(struct module *mod)
tag_new_bool(mod, "repeat", m->repeat),
tag_new_bool(mod, "random", m->random),
tag_new_bool(mod, "consume", m->consume),
tag_new_bool(mod, "single", m->single),
tag_new_int_range(mod, "volume", m->volume, 0, 100),
tag_new_string(mod, "album", m->album),
tag_new_string(mod, "artist", m->artist),
@ -189,7 +182,7 @@ content(struct module *mod)
tag_new_int_realtime(
mod, "elapsed", elapsed, 0, m->duration, realtime),
},
.count = 14,
.count = 13,
};
mtx_unlock(&mod->lock);
@ -244,7 +237,8 @@ wait_for_socket_create(const struct module *mod)
LOG_DBG("%s: already exists, and is connectable", m->host);
have_mpd_socket = true;
} else {
LOG_DBG("%s: already exists, but isn't connectable: %s", m->host, strerror(errno));
LOG_DBG("%s: already exists, but isn't connectable: %s",
m->host, strerror(errno));
}
close(s);
@ -255,7 +249,10 @@ wait_for_socket_create(const struct module *mod)
bool ret = false;
while (!have_mpd_socket) {
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = fd, .events = POLLIN}};
struct pollfd fds[] = {
{.fd = mod->abort_fd, .events = POLLIN},
{.fd = fd, .events = POLLIN}
};
if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) < 0) {
if (errno == EINTR)
@ -275,7 +272,7 @@ wait_for_socket_create(const struct module *mod)
char buf[1024];
ssize_t len = read(fd, buf, sizeof(buf));
for (const char *ptr = buf; ptr < buf + len;) {
for (const char *ptr = buf; ptr < buf + len; ) {
const struct inotify_event *e = (const struct inotify_event *)ptr;
LOG_DBG("inotify: CREATED: %s/%.*s", directory, e->len, e->name);
@ -285,7 +282,7 @@ wait_for_socket_create(const struct module *mod)
break;
}
ptr += sizeof(*e) + e->len;
ptr += sizeof(*e) + e->len;
}
}
@ -308,7 +305,8 @@ connect_to_mpd(const struct module *mod)
enum mpd_error merr = mpd_connection_get_error(conn);
if (merr != MPD_ERROR_SUCCESS) {
LOG_WARN("failed to connect to MPD: %s", mpd_connection_get_error_message(conn));
LOG_WARN("failed to connect to MPD: %s",
mpd_connection_get_error_message(conn));
mpd_connection_free(conn);
return NULL;
}
@ -326,7 +324,8 @@ update_status(struct module *mod)
struct mpd_status *status = mpd_run_status(m->conn);
if (status == NULL) {
LOG_ERR("failed to get status: %s", mpd_connection_get_error_message(m->conn));
LOG_ERR("failed to get status: %s",
mpd_connection_get_error_message(m->conn));
return false;
}
@ -338,7 +337,6 @@ update_status(struct module *mod)
m->repeat = mpd_status_get_repeat(status);
m->random = mpd_status_get_random(status);
m->consume = mpd_status_get_consume(status);
m->single = mpd_status_get_single_state(status) == MPD_SINGLE_ONESHOT;
m->volume = mpd_status_get_volume(status);
m->duration = mpd_status_get_total_time(status) * 1000;
m->elapsed.value = mpd_status_get_elapsed_ms(status);
@ -349,20 +347,17 @@ update_status(struct module *mod)
struct mpd_song *song = mpd_run_current_song(m->conn);
if (song == NULL && mpd_connection_get_error(m->conn) != MPD_ERROR_SUCCESS) {
LOG_ERR("failed to get current song: %s", mpd_connection_get_error_message(m->conn));
LOG_ERR("failed to get current song: %s",
mpd_connection_get_error_message(m->conn));
return false;
}
if (song == NULL) {
mtx_lock(&mod->lock);
free(m->album);
m->album = NULL;
free(m->artist);
m->artist = NULL;
free(m->title);
m->title = NULL;
free(m->file);
m->file = NULL;
free(m->album); m->album = NULL;
free(m->artist); m->artist = NULL;
free(m->title); m->title = NULL;
free(m->file); m->file = NULL;
mtx_unlock(&mod->lock);
} else {
const char *album = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0);
@ -406,14 +401,10 @@ run(struct module *mod)
/* Reset state */
mtx_lock(&mod->lock);
free(m->album);
m->album = NULL;
free(m->artist);
m->artist = NULL;
free(m->title);
m->title = NULL;
free(m->file);
m->file = NULL;
free(m->album); m->album = NULL;
free(m->artist); m->artist = NULL;
free(m->title); m->title = NULL;
free(m->file); m->file = NULL;
m->state = MPD_STATE_UNKNOWN;
m->elapsed.value = m->duration = 0;
m->elapsed.when.tv_sec = m->elapsed.when.tv_nsec = 0;
@ -440,7 +431,7 @@ run(struct module *mod)
*/
while (!aborted) {
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}};
int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 2 * 1000);
int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 10 * 1000);
if (res < 0) {
if (errno == EINTR)
@ -451,16 +442,10 @@ run(struct module *mod)
break;
}
if (res == 0) {
ret = 0;
break;
}
else if (res == 1) {
if (res == 1) {
assert(fds[0].revents & POLLIN);
aborted = true;
}
}
}
@ -482,7 +467,8 @@ run(struct module *mod)
};
if (!mpd_send_idle(m->conn)) {
LOG_ERR("failed to send IDLE command: %s", mpd_connection_get_error_message(m->conn));
LOG_ERR("failed to send IDLE command: %s",
mpd_connection_get_error_message(m->conn));
break;
}
@ -506,7 +492,8 @@ run(struct module *mod)
}
if (fds[1].revents & POLLIN) {
enum mpd_idle idle __attribute__((unused)) = mpd_recv_idle(m->conn, true);
enum mpd_idle idle __attribute__ ((unused)) =
mpd_recv_idle(m->conn, true);
LOG_DBG("IDLE mask: %d", idle);
@ -578,7 +565,9 @@ refresh_in(struct module *mod, long milli_seconds)
/* Signal abort to thread */
assert(m->refresh_abort_fd != -1);
if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) {
if (write(m->refresh_abort_fd, &(uint64_t){1}, sizeof(uint64_t))
!= sizeof(uint64_t))
{
LOG_ERRNO("failed to signal abort to refresher thread");
return false;
}
@ -618,7 +607,7 @@ refresh_in(struct module *mod, long milli_seconds)
}
/* Detach - we don't want to have to thrd_join() it */
// thrd_detach(tid);
//thrd_detach(tid);
return r == 0;
}
@ -649,8 +638,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *port = yml_get_value(node, "port");
const struct yml_node *c = yml_get_value(node, "content");
return mpd_new(yml_value_as_string(host), port != NULL ? yml_value_as_int(port) : 0,
conf_to_particle(c, inherited));
return mpd_new(
yml_value_as_string(host),
port != NULL ? yml_value_as_int(port) : 0,
conf_to_particle(c, inherited));
}
static bool

File diff suppressed because it is too large Load diff

View file

@ -1,377 +0,0 @@
#include <errno.h>
#include <json-c/json.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <threads.h>
#include <unistd.h>
#include "../log.h"
#include "niri-common.h"
#define LOG_MODULE "niri:common"
#define LOG_ENABLE_DBG 0
static struct niri_socket instance = {
.fd = -1,
.abort_fd = -1,
};
static void
workspace_free(struct niri_workspace *workspace)
{
free(workspace->name);
free(workspace);
}
static void
parser(char *response)
{
enum json_tokener_error error = json_tokener_success;
struct json_object *json = json_tokener_parse_verbose(response, &error);
if (error != json_tokener_success) {
LOG_WARN("failed to parse niri socket's response");
return;
}
enum niri_event events = 0;
struct json_object_iterator it = json_object_iter_begin(json);
struct json_object_iterator end = json_object_iter_end(json);
while (!json_object_iter_equal(&it, &end)) {
char const *key = json_object_iter_peek_name(&it);
// "WorkspacesChanged": {
// "workspaces": [
// {
// "id": 3,
// "idx": 1,
// "name": null,
// "output": "DP-4",
// "is_active": true,
// "is_focused": true,
// "active_window_id": 24
// },
// ...
// ]
// }
if (strcmp(key, "WorkspacesChanged") == 0) {
mtx_lock(&instance.mtx);
tll_foreach(instance.workspaces, it) { tll_remove_and_free(instance.workspaces, it, workspace_free); }
mtx_unlock(&instance.mtx);
json_object *obj = json_object_iter_peek_value(&it);
json_object *workspaces = json_object_object_get(obj, "workspaces");
size_t length = json_object_array_length(workspaces);
for (size_t i = 0; i < length; ++i) {
json_object *ws_obj = json_object_array_get_idx(workspaces, i);
// only add workspaces on the current yambar's monitor
struct json_object *output = json_object_object_get(ws_obj, "output");
if (strcmp(instance.monitor, json_object_get_string(output)) != 0)
continue;
struct niri_workspace *ws = calloc(1, sizeof(*ws));
ws->idx = json_object_get_int(json_object_object_get(ws_obj, "idx"));
ws->id = json_object_get_int(json_object_object_get(ws_obj, "id"));
ws->active = json_object_get_boolean(json_object_object_get(ws_obj, "is_active"));
ws->focused = json_object_get_boolean(json_object_object_get(ws_obj, "is_focused"));
ws->empty = json_object_get_int(json_object_object_get(ws_obj, "active_window_id")) == 0;
char const *name = json_object_get_string(json_object_object_get(ws_obj, "name"));
if (name)
ws->name = strdup(name);
mtx_lock(&instance.mtx);
bool inserted = false;
tll_foreach(instance.workspaces, it)
{
if (it->item->idx > ws->idx) {
tll_insert_before(instance.workspaces, it, ws);
inserted = true;
break;
}
}
if (!inserted)
tll_push_back(instance.workspaces, ws);
mtx_unlock(&instance.mtx);
events |= workspaces_changed;
}
}
// "WorkspaceActivated": {
// "id": 7,
// "focused":true
// }
else if (strcmp(key, "WorkspaceActivated") == 0) {
json_object *obj = json_object_iter_peek_value(&it);
int id = json_object_get_int(json_object_object_get(obj, "id"));
mtx_lock(&instance.mtx);
tll_foreach(instance.workspaces, it)
{
bool b = it->item->id == id;
it->item->focused = b;
it->item->active = b;
}
mtx_unlock(&instance.mtx);
events |= workspace_activated;
}
// "WorkspaceActiveWindowChanged": {
// "workspace_id": 3,
// "active_window_id": 8
// }
else if (strcmp(key, "WorkspaceActiveWindowChanged") == 0) {
json_object *obj = json_object_iter_peek_value(&it);
int id = json_object_get_int(json_object_object_get(obj, "id"));
bool empty = json_object_get_int(json_object_object_get(obj, "active_window_id")) == 0;
mtx_lock(&instance.mtx);
tll_foreach(instance.workspaces, it)
{
if (it->item->id == id) {
it->item->empty = empty;
break;
}
}
mtx_unlock(&instance.mtx);
events |= workspace_active_window_changed;
}
//
// "KeyboardLayoutsChanged": {
// "keyboard_layouts": {
// "names": [
// "English (US)",
// "Russian"
// ],
// "current_idx": 0
// }
// }
else if (strcmp(key, "KeyboardLayoutsChanged") == 0) {
tll_foreach(instance.keyboard_layouts, it) { tll_remove_and_free(instance.keyboard_layouts, it, free); }
json_object *obj = json_object_iter_peek_value(&it);
json_object *kb_layouts = json_object_object_get(obj, "keyboard_layouts");
instance.keyboard_layout_index = json_object_get_int(json_object_object_get(kb_layouts, "current_idx"));
json_object *names = json_object_object_get(kb_layouts, "names");
size_t names_length = json_object_array_length(names);
for (size_t i = 0; i < names_length; ++i) {
char const *name = json_object_get_string(json_object_array_get_idx(names, i));
tll_push_back(instance.keyboard_layouts, strdup(name));
}
events |= keyboard_layouts_changed;
}
// "KeyboardLayoutSwitched": {
// "idx": 1
// }
else if (strcmp(key, "KeyboardLayoutSwitched") == 0) {
json_object *obj = json_object_iter_peek_value(&it);
instance.keyboard_layout_index = json_object_get_int(json_object_object_get(obj, "idx"));
events |= keyboard_layouts_switched;
}
json_object_iter_next(&it);
}
json_object_put(json);
mtx_lock(&instance.mtx);
tll_foreach(instance.subscribers, it)
{
if (it->item->events & events)
if (write(it->item->fd, &(uint64_t){1}, sizeof(uint64_t)) == -1)
LOG_ERRNO("failed to write");
}
mtx_unlock(&instance.mtx);
}
static int
run(void *userdata)
{
static char msg[] = "\"EventStream\"\n";
static char expected[] = "{\"Ok\":\"Handled\"}";
if (write(instance.fd, msg, sizeof(msg) / sizeof(msg[0])) == -1) {
LOG_ERRNO("failed to sent message to niri socket");
return thrd_error;
}
static char buffer[8192];
if (read(instance.fd, buffer, sizeof(buffer) / sizeof(buffer[0]) - 1) == -1) {
LOG_ERRNO("failed to read response of niri socket");
return thrd_error;
}
char *saveptr;
char *response = strtok_r(buffer, "\n", &saveptr);
if (response == NULL || strcmp(expected, response) != 0) {
// unexpected first response, something went wrong
LOG_ERR("unexpected response of niri socket");
return thrd_error;
}
while ((response = strtok_r(NULL, "\n", &saveptr)) != NULL)
parser(response);
while (true) {
struct pollfd fds[] = {
(struct pollfd){.fd = instance.abort_fd, .events = POLLIN},
(struct pollfd){.fd = instance.fd, .events = POLLIN},
};
if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) {
if (errno == EINTR)
continue;
LOG_ERRNO("failed to poll");
break;
}
if (fds[0].revents & POLLIN)
break;
static char buffer[8192];
ssize_t length = read(fds[1].fd, buffer, sizeof(buffer) / sizeof(buffer[0]));
if (length == 0)
break;
if (length == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
LOG_ERRNO("unable to read niri socket");
break;
}
buffer[length] = '\0';
saveptr = NULL;
response = strtok_r(buffer, "\n", &saveptr);
do {
parser(response);
} while ((response = strtok_r(NULL, "\n", &saveptr)) != NULL);
}
return thrd_success;
}
struct niri_socket *
niri_socket_open(char const *monitor)
{
if (instance.fd >= 0)
return &instance;
char const *path = getenv("NIRI_SOCKET");
if (path == NULL) {
LOG_ERR("NIRI_SOCKET is empty. Is niri running?");
return NULL;
}
if ((instance.fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
LOG_ERRNO("failed to create socket");
goto error;
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
if (connect(instance.fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
LOG_ERRNO("failed to connect to niri socket");
goto error;
}
if ((instance.abort_fd = eventfd(0, EFD_CLOEXEC)) == -1) {
LOG_ERRNO("failed to create abort_fd");
goto error;
}
if (mtx_init(&instance.mtx, mtx_plain) != thrd_success) {
LOG_ERR("failed to initialize mutex");
goto error;
}
if (thrd_create(&instance.thrd, run, NULL) != thrd_success) {
LOG_ERR("failed to create thread");
mtx_destroy(&instance.mtx);
goto error;
}
instance.monitor = monitor;
return &instance;
error:
if (instance.fd >= 0)
close(instance.fd);
if (instance.abort_fd >= 0)
close(instance.abort_fd);
instance.fd = -1;
instance.abort_fd = -1;
instance.monitor = NULL;
return NULL;
}
static void
socket_close(void)
{
if (write(instance.abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t))
LOG_ERRNO("failed to write to abort_fd");
thrd_join(instance.thrd, NULL);
close(instance.abort_fd);
close(instance.fd);
instance.abort_fd = -1;
instance.fd = -1;
mtx_destroy(&instance.mtx);
tll_free_and_free(instance.subscribers, free);
tll_free_and_free(instance.workspaces, workspace_free);
tll_free_and_free(instance.keyboard_layouts, free);
}
void
niri_socket_close(void)
{
static once_flag flag = ONCE_FLAG_INIT;
call_once(&flag, socket_close);
}
int
niri_socket_subscribe(enum niri_event events)
{
int fd = eventfd(0, EFD_CLOEXEC);
if (fd == -1) {
LOG_ERRNO("failed to create eventfd");
return -1;
}
struct niri_subscriber *subscriber = calloc(1, sizeof(*subscriber));
subscriber->events = events;
subscriber->fd = fd;
mtx_lock(&instance.mtx);
tll_push_back(instance.subscribers, subscriber);
mtx_unlock(&instance.mtx);
return subscriber->fd;
}

View file

@ -1,45 +0,0 @@
#pragma once
#include <stdbool.h>
#include <threads.h>
#include <tllist.h>
enum niri_event {
workspaces_changed = (1 << 0),
workspace_activated = (1 << 1),
workspace_active_window_changed = (1 << 2),
keyboard_layouts_changed = (1 << 3),
keyboard_layouts_switched = (1 << 4),
};
struct niri_subscriber {
int events;
int fd;
};
struct niri_workspace {
int id;
int idx;
char *name;
bool active;
bool focused;
bool empty;
};
struct niri_socket {
char const *monitor;
int abort_fd;
int fd;
tll(struct niri_subscriber *) subscribers;
tll(struct niri_workspace *) workspaces;
tll(char *) keyboard_layouts;
size_t keyboard_layout_index;
thrd_t thrd;
mtx_t mtx;
};
struct niri_socket *niri_socket_open(char const *monitor);
void niri_socket_close(void);
int niri_socket_subscribe(enum niri_event events);

View file

@ -1,160 +0,0 @@
#include <errno.h>
#include <json-c/json.h>
#include <poll.h>
#include <string.h>
#include <unistd.h>
#define LOG_MODULE "niri-language"
#define LOG_ENABLE_DBG 0
#include "niri-common.h"
#include "../log.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
struct private
{
struct particle *label;
struct niri_socket *niri;
};
static void
destroy(struct module *module)
{
struct private *private = module->private;
private->label->destroy(private->label);
free(private);
module_default_destroy(module);
}
static const char *
description(const struct module *module)
{
return "niri-lang";
}
static struct exposable *
content(struct module *module)
{
const struct private *private = module->private;
if (private->niri == NULL)
return dynlist_exposable_new(&((struct exposable *){0}), 0, 0, 0);
mtx_lock(&module->lock);
mtx_lock(&private->niri->mtx);
char *name = "???";
size_t i = 0;
tll_foreach(private->niri->keyboard_layouts, it)
{
if (i++ == private->niri->keyboard_layout_index)
name = it->item;
}
struct tag_set tags = {
.tags = (struct tag *[]){tag_new_string(module, "language", name)},
.count = 1,
};
struct exposable *exposable = private->label->instantiate(private->label, &tags);
tag_set_destroy(&tags);
mtx_unlock(&private->niri->mtx);
mtx_unlock(&module->lock);
return exposable;
}
static int
run(struct module *module)
{
struct private *private = module->private;
/* Ugly, but I didn't find better way for waiting
* the monitor's name to be set */
char const *monitor;
do {
monitor = module->bar->output_name(module->bar);
usleep(50);
} while (monitor == NULL);
private->niri = niri_socket_open(monitor);
if (private->niri == NULL)
return 1;
int fd = niri_socket_subscribe(keyboard_layouts_changed | keyboard_layouts_switched);
if (fd == -1) {
niri_socket_close();
return 1;
}
module->bar->refresh(module->bar);
while (true) {
struct pollfd fds[] = {
(struct pollfd){.fd = module->abort_fd, .events = POLLIN},
(struct pollfd){.fd = fd, .events = POLLIN},
};
if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) {
if (errno == EINTR)
continue;
LOG_ERRNO("failed to poll");
break;
}
if (fds[0].revents & POLLIN)
break;
if (read(fds[1].fd, &(uint64_t){0}, sizeof(uint64_t)) == -1)
LOG_ERRNO("failed to read from eventfd");
module->bar->refresh(module->bar);
}
niri_socket_close();
return 0;
}
static struct module *
niri_language_new(struct particle *label)
{
struct private *private = calloc(1, sizeof(struct private));
private->label = label;
struct module *module = module_common_new();
module->private = private;
module->run = &run;
module->destroy = &destroy;
module->content = &content;
module->description = &description;
return module;
}
static struct module *
from_conf(struct yml_node const *node, struct conf_inherit inherited)
{
struct yml_node const *content = yml_get_value(node, "content");
return niri_language_new(conf_to_particle(content, inherited));
}
static bool
verify_conf(keychain_t *chain, const struct yml_node *node)
{
static struct attr_info const attrs[] = {
MODULE_COMMON_ATTRS,
};
return conf_verify_dict(chain, node, attrs);
}
const struct module_iface module_niri_language_iface = {
.verify_conf = &verify_conf,
.from_conf = &from_conf,
};
#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
extern const struct module_iface iface __attribute__((weak, alias("module_niri_language_iface")));
#endif

View file

@ -1,163 +0,0 @@
#include <errno.h>
#include <poll.h>
#include <string.h>
#include <unistd.h>
#define LOG_MODULE "niri-workspaces"
#define LOG_ENABLE_DBG 0
#include "niri-common.h"
#include "../log.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
struct private
{
struct particle *label;
struct niri_socket *niri;
};
static void
destroy(struct module *module)
{
struct private *private = module->private;
private->label->destroy(private->label);
free(private);
module_default_destroy(module);
}
static const char *
description(const struct module *module)
{
return "niri-ws";
}
static struct exposable *
content(struct module *module)
{
struct private const *private = module->private;
if (private->niri == NULL)
return dynlist_exposable_new(&((struct exposable *){0}), 0, 0, 0);
mtx_lock(&module->lock);
mtx_lock(&private->niri->mtx);
size_t i = 0;
struct exposable *exposable[tll_length(private->niri->workspaces)];
tll_foreach(private->niri->workspaces, it)
{
struct tag_set tags = {
.tags = (struct tag*[]){
tag_new_int(module, "id", it->item->idx),
tag_new_string(module, "name", it->item->name),
tag_new_bool(module, "active", it->item->active),
tag_new_bool(module, "focused", it->item->focused),
tag_new_bool(module, "empty", it->item->empty),
},
.count = 5,
};
exposable[i++] = private->label->instantiate(private->label, &tags);
tag_set_destroy(&tags);
}
mtx_unlock(&private->niri->mtx);
mtx_unlock(&module->lock);
return dynlist_exposable_new(exposable, i, 0, 0);
}
static int
run(struct module *module)
{
struct private *private = module->private;
/* Ugly, but I didn't find better way for waiting
* the monitor's name to be set */
char const *monitor;
do {
monitor = module->bar->output_name(module->bar);
usleep(50);
} while (monitor == NULL);
private->niri = niri_socket_open(monitor);
if (private->niri == NULL)
return 1;
int fd = niri_socket_subscribe(workspaces_changed | workspace_activated | workspace_active_window_changed);
if (fd == -1) {
niri_socket_close();
return 1;
}
module->bar->refresh(module->bar);
while (true) {
struct pollfd fds[] = {
(struct pollfd){.fd = module->abort_fd, .events = POLLIN},
(struct pollfd){.fd = fd, .events = POLLIN},
};
if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) {
if (errno == EINTR)
continue;
LOG_ERRNO("failed to poll");
break;
}
if (fds[0].revents & POLLIN)
break;
if (read(fds[1].fd, &(uint64_t){0}, sizeof(uint64_t)) == -1)
LOG_ERRNO("failed to read from eventfd");
module->bar->refresh(module->bar);
}
niri_socket_close();
return 0;
}
static struct module *
niri_workspaces_new(struct particle *label)
{
struct private *private = calloc(1, sizeof(struct private));
private->label = label;
struct module *module = module_common_new();
module->private = private;
module->run = &run;
module->destroy = &destroy;
module->content = &content;
module->description = &description;
return module;
}
static struct module *
from_conf(struct yml_node const *node, struct conf_inherit inherited)
{
struct yml_node const *content = yml_get_value(node, "content");
return niri_workspaces_new(conf_to_particle(content, inherited));
}
static bool
verify_conf(keychain_t *chain, const struct yml_node *node)
{
static struct attr_info const attrs[] = {
MODULE_COMMON_ATTRS,
};
return conf_verify_dict(chain, node, attrs);
}
const struct module_iface module_niri_workspaces_iface = {
.verify_conf = &verify_conf,
.from_conf = &from_conf,
};
#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
extern const struct module_iface iface __attribute__((weak, alias("module_niri_workspaces_iface")));
#endif

View file

@ -33,7 +33,7 @@ struct output_informations {
uint32_t device_id;
uint32_t card_profile_device_id;
/* information */
/* informations */
bool muted;
uint16_t linear_volume; /* classic volume */
uint16_t cubic_volume; /* volume a la pulseaudio */
@ -45,16 +45,6 @@ struct output_informations {
};
static struct output_informations const output_informations_null;
static void
output_informations_destroy(struct output_informations *output_informations)
{
free(output_informations->name);
free(output_informations->description);
free(output_informations->icon);
free(output_informations->form_factor);
free(output_informations->bus);
}
struct data;
struct private
{
@ -223,23 +213,18 @@ node_find_route(struct data *data, bool is_sink)
static void
node_unhook_binded_node(struct data *data, bool is_sink)
{
struct private *private = data->module->private;
struct node **target_node = NULL;
struct spa_hook *target_listener = NULL;
void **target_proxy = NULL;
struct output_informations *output_informations = NULL;
if (is_sink) {
target_node = &data->binded_sink;
target_listener = &data->node_sink_listener;
target_proxy = &data->node_sink;
output_informations = &private->sink_informations;
} else {
target_node = &data->binded_source;
target_listener = &data->node_source_listener;
target_proxy = &data->node_source;
output_informations = &private->source_informations;
}
if (*target_node == NULL)
@ -250,9 +235,6 @@ node_unhook_binded_node(struct data *data, bool is_sink)
*target_node = NULL;
*target_proxy = NULL;
output_informations_destroy(output_informations);
*output_informations = output_informations_null;
}
static void
@ -351,7 +333,7 @@ device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32
X_FREE_SET(route->icon_name, X_STRDUP(data.icon_name));
route->direction = data.direction;
/* set missing information if possible */
/* set missing informations if possible */
struct private *private = device->data->module->private;
struct node *binded_node = NULL;
struct output_informations *output_informations = NULL;
@ -368,7 +350,7 @@ device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32
if (binded_node == NULL)
return;
/* Node's device is the same as route's device */
/* Node's device is the the same as route's device */
if (output_informations->device_id != route->device->id)
return;
@ -376,7 +358,7 @@ device_events_param(void *userdata, int seq, uint32_t id, uint32_t index, uint32
if (output_informations->card_profile_device_id != route->profile_device_id)
return;
/* Update missing information */
/* Update missing informations */
X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor));
X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name));
@ -402,7 +384,7 @@ node_events_info(void *userdata, struct pw_node_info const *info)
for (size_t i = 0; i < info->n_params; ++i) {
if (info->params[i].id == SPA_PARAM_Props) {
void *target_node = (node_data->is_sink ? data->node_sink : data->node_source);
/* Found it, will emit a param event, the param will then be handled
/* Found it, will emit a param event, the parem will then be handled
* in node_events_param */
pw_node_enum_params(target_node, 0, info->params[i].id, 0, -1, NULL);
break;
@ -416,18 +398,18 @@ node_events_info(void *userdata, struct pw_node_info const *info)
struct spa_dict_item const *item = NULL;
item = spa_dict_lookup_item(info->props, "node.name");
X_FREE_SET(output_informations->name, item != NULL ? X_STRDUP(item->value) : NULL);
if (item != NULL)
X_FREE_SET(output_informations->name, X_STRDUP(item->value));
item = spa_dict_lookup_item(info->props, "node.description");
X_FREE_SET(output_informations->description, item != NULL ? X_STRDUP(item->value) : NULL);
if (item != NULL)
X_FREE_SET(output_informations->description, X_STRDUP(item->value));
item = spa_dict_lookup_item(info->props, "device.id");
if (item != NULL) {
uint32_t value = 0;
spa_atou32(item->value, &value, 10);
output_informations->device_id = value;
} else {
output_informations->device_id = 0;
}
item = spa_dict_lookup_item(info->props, "card.profile.device");
@ -435,29 +417,30 @@ node_events_info(void *userdata, struct pw_node_info const *info)
uint32_t value = 0;
spa_atou32(item->value, &value, 10);
output_informations->card_profile_device_id = value;
} else {
output_informations->card_profile_device_id = 0;
}
/* Device's information has an more important priority than node's information */
/* Device's informations has an more important priority than node's informations */
/* icon_name */
struct route *route = node_find_route(data, node_data->is_sink);
if (route != NULL && route->icon_name != NULL)
X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name));
output_informations->icon = X_STRDUP(route->icon_name);
else {
item = spa_dict_lookup_item(info->props, "device.icon-name");
X_FREE_SET(output_informations->icon, item != NULL ? X_STRDUP(item->value) : NULL);
if (item != NULL)
X_FREE_SET(output_informations->icon, X_STRDUP(item->value));
}
/* form_factor */
if (route != NULL && route->form_factor != NULL)
X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor));
output_informations->form_factor = X_STRDUP(route->form_factor);
else {
item = spa_dict_lookup_item(info->props, "device.form-factor");
X_FREE_SET(output_informations->form_factor, item != NULL ? X_STRDUP(item->value) : NULL);
if (item != NULL)
X_FREE_SET(output_informations->form_factor, X_STRDUP(item->value));
}
item = spa_dict_lookup_item(info->props, "device.bus");
X_FREE_SET(output_informations->bus, item != NULL ? X_STRDUP(item->value) : NULL);
if (item != NULL)
X_FREE_SET(output_informations->bus, X_STRDUP(item->value));
data->module->bar->refresh(data->module->bar);
}
@ -676,7 +659,7 @@ static void
try_to_bind_node(struct node_data *node_data, char const *target_name, struct node **target_node, void **target_proxy,
struct spa_hook *target_listener)
{
/* profile deactivated */
/* profile deactived */
if (target_name == NULL)
return;
@ -844,8 +827,18 @@ destroy(struct module *module)
pipewire_deinit(private->data);
private->label->destroy(private->label);
output_informations_destroy(&private->sink_informations);
output_informations_destroy(&private->source_informations);
/* sink */
free(private->sink_informations.name);
free(private->sink_informations.description);
free(private->sink_informations.icon);
free(private->sink_informations.form_factor);
free(private->sink_informations.bus);
/* source */
free(private->source_informations.name);
free(private->source_informations.description);
free(private->source_informations.icon);
free(private->source_informations.form_factor);
free(private->source_informations.bus);
free(private);
module_default_destroy(module);
@ -874,7 +867,9 @@ content(struct module *module)
/* sink */
output_informations
= (private->data->target_sink == NULL ? &output_informations_null : &private->sink_informations);
= (private->data->target_sink == NULL
? &output_informations_null
: &private->sink_informations);
struct tag_set sink_tag_set = (struct tag_set){
.tags = (struct tag *[]){
@ -893,7 +888,9 @@ content(struct module *module)
/* source */
output_informations
= (private->data->target_source == NULL ? &output_informations_null : &private->source_informations);
= (private->data->target_source == NULL
? &output_informations_null
: &private->source_informations);
struct tag_set source_tag_set = (struct tag_set){
.tags = (struct tag *[]){

View file

@ -4,8 +4,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <pulse/pulseaudio.h>
@ -17,8 +17,7 @@
#include "../log.h"
#include "../plugin.h"
struct private
{
struct private {
char *sink_name;
char *source_name;
struct particle *label;
@ -70,9 +69,9 @@ content(struct module *mod)
mtx_lock(&mod->lock);
pa_volume_t sink_volume_max = pa_cvolume_max(&priv->sink_volume);
pa_volume_t sink_volume_max = pa_cvolume_max(&priv->sink_volume);
pa_volume_t source_volume_max = pa_cvolume_max(&priv->source_volume);
int sink_percent = round(100.0 * sink_volume_max / PA_VOLUME_NORM);
int sink_percent = round(100.0 * sink_volume_max / PA_VOLUME_NORM);
int source_percent = round(100.0 * source_volume_max / PA_VOLUME_NORM);
struct tag_set tags = {
@ -107,7 +106,11 @@ context_error(pa_context *c)
}
static void
abort_event_cb(pa_mainloop_api *api, pa_io_event *event, int fd, pa_io_event_flags_t flags, void *userdata)
abort_event_cb(pa_mainloop_api *api,
pa_io_event *event,
int fd,
pa_io_event_flags_t flags,
void *userdata)
{
struct module *mod = userdata;
struct private *priv = mod->private;
@ -116,7 +119,11 @@ abort_event_cb(pa_mainloop_api *api, pa_io_event *event, int fd, pa_io_event_fla
}
static void
refresh_timer_cb(pa_mainloop_api *api, pa_io_event *event, int fd, pa_io_event_flags_t flags, void *userdata)
refresh_timer_cb(pa_mainloop_api *api,
pa_io_event *event,
int fd,
pa_io_event_flags_t flags,
void *userdata)
{
struct module *mod = userdata;
struct private *priv = mod->private;
@ -148,8 +155,8 @@ schedule_refresh(struct module *mod)
// Start the refresh timer.
struct itimerspec t = {
.it_interval = {.tv_sec = 0, .tv_nsec = 0},
.it_value = {.tv_sec = 0, .tv_nsec = 50000000},
.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
.it_value = { .tv_sec = 0, .tv_nsec = 50000000 },
};
timerfd_settime(priv->refresh_timer_fd, 0, &t, NULL);
@ -193,10 +200,12 @@ set_sink_info(struct module *mod, const pa_sink_info *sink_info)
free(priv->sink_port);
priv->sink_online = true;
priv->sink_index = sink_info->index;
priv->sink_index = sink_info->index;
priv->sink_volume = sink_info->volume;
priv->sink_muted = sink_info->mute;
priv->sink_port = sink_info->active_port != NULL ? strdup(sink_info->active_port->description) : NULL;
priv->sink_muted = sink_info->mute;
priv->sink_port = sink_info->active_port != NULL
? strdup(sink_info->active_port->description)
: NULL;
mtx_unlock(&mod->lock);
@ -225,10 +234,12 @@ set_source_info(struct module *mod, const pa_source_info *source_info)
free(priv->source_port);
priv->source_online = true;
priv->source_index = source_info->index;
priv->source_index = source_info->index;
priv->source_volume = source_info->volume;
priv->source_muted = source_info->mute;
priv->source_port = source_info->active_port != NULL ? strdup(source_info->active_port->description) : NULL;
priv->source_muted = source_info->mute;
priv->source_port = source_info->active_port != NULL
? strdup(source_info->active_port->description)
: NULL;
mtx_unlock(&mod->lock);
@ -282,28 +293,32 @@ server_info_cb(pa_context *c, const pa_server_info *i, void *userdata)
static void
get_sink_info_by_name(pa_context *c, const char *name, void *userdata)
{
pa_operation *o = pa_context_get_sink_info_by_name(c, name, sink_info_cb, userdata);
pa_operation *o =
pa_context_get_sink_info_by_name(c, name, sink_info_cb, userdata);
pa_operation_unref(o);
}
static void
get_source_info_by_name(pa_context *c, const char *name, void *userdata)
{
pa_operation *o = pa_context_get_source_info_by_name(c, name, source_info_cb, userdata);
pa_operation *o =
pa_context_get_source_info_by_name(c, name, source_info_cb, userdata);
pa_operation_unref(o);
}
static void
get_sink_info_by_index(pa_context *c, uint32_t index, void *userdata)
{
pa_operation *o = pa_context_get_sink_info_by_index(c, index, sink_info_cb, userdata);
pa_operation *o =
pa_context_get_sink_info_by_index(c, index, sink_info_cb, userdata);
pa_operation_unref(o);
}
static void
get_source_info_by_index(pa_context *c, uint32_t index, void *userdata)
{
pa_operation *o = pa_context_get_source_info_by_index(c, index, source_info_cb, userdata);
pa_operation *o =
pa_context_get_source_info_by_index(c, index, source_info_cb, userdata);
pa_operation_unref(o);
}
@ -317,12 +332,15 @@ get_server_info(pa_context *c, void *userdata)
static void
subscribe(pa_context *c, void *userdata)
{
pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SERVER | PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE;
pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SERVER
| PA_SUBSCRIPTION_MASK_SINK
| PA_SUBSCRIPTION_MASK_SOURCE;
pa_operation *o = pa_context_subscribe(c, mask, NULL, userdata);
pa_operation_unref(o);
}
static pa_context *connect_to_server(struct module *mod);
static pa_context *
connect_to_server(struct module *mod);
static void
context_state_change_cb(pa_context *c, void *userdata)
@ -362,13 +380,16 @@ context_state_change_cb(pa_context *c, void *userdata)
}
static void
subscription_event_cb(pa_context *c, pa_subscription_event_type_t event_type, uint32_t index, void *userdata)
subscription_event_cb(pa_context *c,
pa_subscription_event_type_t event_type,
uint32_t index,
void *userdata)
{
struct module *mod = userdata;
struct private *priv = mod->private;
int facility = event_type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
int type = event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
int type = event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
switch (facility) {
case PA_SUBSCRIPTION_EVENT_SERVER:
@ -414,7 +435,8 @@ connect_to_server(struct module *mod)
pa_context_set_subscribe_callback(c, subscription_event_cb, mod);
// Connect to server.
pa_context_flags_t flags = PA_CONTEXT_NOFAIL | PA_CONTEXT_NOAUTOSPAWN;
pa_context_flags_t flags = PA_CONTEXT_NOFAIL
| PA_CONTEXT_NOAUTOSPAWN;
if (pa_context_connect(c, NULL, flags, NULL) < 0) {
LOG_ERR("failed to connect to PulseAudio server: %s", context_error(c));
pa_context_unref(c);
@ -438,7 +460,7 @@ run(struct module *mod)
}
// Create refresh timer.
priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (priv->refresh_timer_fd < 0) {
LOG_ERRNO("failed to create timerfd");
pa_mainloop_free(priv->mainloop);
@ -455,8 +477,10 @@ run(struct module *mod)
// Poll refresh timer and abort event.
pa_mainloop_api *api = pa_mainloop_get_api(priv->mainloop);
api->io_new(api, priv->refresh_timer_fd, PA_IO_EVENT_INPUT, refresh_timer_cb, mod);
api->io_new(api, mod->abort_fd, PA_IO_EVENT_INPUT | PA_IO_EVENT_HANGUP, abort_event_cb, mod);
api->io_new(api, priv->refresh_timer_fd, PA_IO_EVENT_INPUT,
refresh_timer_cb, mod);
api->io_new(api, mod->abort_fd, PA_IO_EVENT_INPUT | PA_IO_EVENT_HANGUP,
abort_event_cb, mod);
// Run main loop.
if (pa_mainloop_run(priv->mainloop, &ret) < 0) {
@ -473,7 +497,9 @@ run(struct module *mod)
}
static struct module *
pulse_new(const char *sink_name, const char *source_name, struct particle *label)
pulse_new(const char *sink_name,
const char *source_name,
struct particle *label)
{
struct private *priv = calloc(1, sizeof *priv);
priv->label = label;
@ -496,9 +522,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *source = yml_get_value(node, "source");
const struct yml_node *content = yml_get_value(node, "content");
return pulse_new(sink != NULL ? yml_value_as_string(sink) : "@DEFAULT_SINK@",
source != NULL ? yml_value_as_string(source) : "@DEFAULT_SOURCE@",
conf_to_particle(content, inherited));
return pulse_new(
sink != NULL ? yml_value_as_string(sink) : "@DEFAULT_SINK@",
source != NULL ? yml_value_as_string(source) : "@DEFAULT_SOURCE@",
conf_to_particle(content, inherited));
}
static bool

View file

@ -1,15 +1,15 @@
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libudev.h>
@ -17,10 +17,10 @@
#define LOG_MODULE "removables"
#define LOG_ENABLE_DBG 0
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
@ -54,8 +54,7 @@ struct block_device {
tll(struct partition) partitions;
};
struct private
{
struct private {
struct particle *label;
int left_spacing;
int right_spacing;
@ -76,7 +75,8 @@ free_partition(struct partition *p)
static void
free_device(struct block_device *b)
{
tll_foreach(b->partitions, it) free_partition(&it->item);
tll_foreach(b->partitions, it)
free_partition(&it->item);
tll_free(b->partitions);
free(b->sys_path);
@ -91,7 +91,8 @@ destroy(struct module *mod)
struct private *m = mod->private;
m->label->destroy(m->label);
tll_foreach(m->devices, it) free_device(&it->item);
tll_foreach(m->devices, it)
free_device(&it->item);
tll_free(m->devices);
tll_free_and_free(m->ignore, free);
@ -112,23 +113,24 @@ content(struct module *mod)
tll(const struct partition *) partitions = tll_init();
tll_foreach(m->devices, dev)
{
tll_foreach(dev->item.partitions, part) { tll_push_back(partitions, &part->item); }
tll_foreach(m->devices, dev) {
tll_foreach(dev->item.partitions, part) {
tll_push_back(partitions, &part->item);
}
}
struct exposable *exposables[max(tll_length(partitions), 1)];
size_t idx = 0;
tll_foreach(partitions, it)
{
tll_foreach(partitions, it) {
const struct partition *p = it->item;
char dummy_label[16];
const char *label = p->label;
if (label == NULL) {
snprintf(dummy_label, sizeof(dummy_label), "%.1f GB", (double)p->size / 1024 / 1024 / 1024 * 512);
snprintf(dummy_label, sizeof(dummy_label),
"%.1f GB", (double)p->size / 1024 / 1024 / 1024 * 512);
label = dummy_label;
}
@ -155,16 +157,20 @@ content(struct module *mod)
}
tll_free(partitions);
return dynlist_exposable_new(exposables, idx, m->left_spacing, m->right_spacing);
return dynlist_exposable_new(
exposables, idx, m->left_spacing, m->right_spacing);
}
static void
find_mount_points(const char *dev_path, mount_point_list_t *mount_points)
{
FILE *f = fopen("/proc/self/mountinfo", "re");
int fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC);
FILE *f = fd >= 0 ? fdopen(fd, "r") : NULL;
if (f == NULL) {
if (fd < 0 || f == NULL) {
LOG_ERRNO("failed to open /proc/self/mountinfo");
if (fd >= 0)
close(fd);
return;
}
@ -172,7 +178,9 @@ find_mount_points(const char *dev_path, mount_point_list_t *mount_points)
while (fgets(line, sizeof(line), f) != NULL) {
char *dev = NULL, *path = NULL;
if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-] - %*s %ms %*s", &path, &dev) != 2) {
if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-] - %*s %ms %*s",
&path, &dev) != 2)
{
LOG_ERR("failed to parse /proc/self/mountinfo: %s", line);
free(dev);
free(path);
@ -199,11 +207,9 @@ update_mount_points(struct partition *partition)
/* Remove mount points that no longer exists (i.e. old mount
* points that aren't in the new list) */
tll_foreach(partition->mount_points, old)
{
tll_foreach(partition->mount_points, old) {
bool gone = true;
tll_foreach(new_mounts, new)
{
tll_foreach(new_mounts, new) {
if (strcmp(new->item, old->item) == 0) {
/* Remove from new list, as it's already in the
* partitions list */
@ -222,8 +228,7 @@ update_mount_points(struct partition *partition)
/* Add new mount points (i.e. mount points in the new list, that
* aren't in the old list) */
tll_foreach(new_mounts, new)
{
tll_foreach(new_mounts, new) {
LOG_DBG("%s: mounted on %s", partition->dev_path, new->item);
tll_push_back(partition->mount_points, new->item);
@ -237,13 +242,14 @@ update_mount_points(struct partition *partition)
}
static struct partition *
add_partition(struct module *mod, struct block_device *block, struct udev_device *dev)
add_partition(struct module *mod, struct block_device *block,
struct udev_device *dev)
{
struct private *m = mod->private;
const char *_size = udev_device_get_sysattr_value(dev, "size");
uint64_t size = 0;
if (_size != NULL)
sscanf(_size, "%" SCNu64, &size);
sscanf(_size, "%"SCNu64, &size);
#if 0
struct udev_list_entry *e = NULL;
@ -254,8 +260,7 @@ add_partition(struct module *mod, struct block_device *block, struct udev_device
const char *devname = udev_device_get_property_value(dev, "DEVNAME");
if (devname != NULL) {
tll_foreach(m->ignore, it)
{
tll_foreach(m->ignore, it) {
if (strcmp(it->item, devname) == 0) {
LOG_DBG("ignoring %s because it is on the ignore list", devname);
return NULL;
@ -267,17 +272,21 @@ add_partition(struct module *mod, struct block_device *block, struct udev_device
if (label == NULL)
label = udev_device_get_property_value(dev, "ID_LABEL");
LOG_INFO("partition: add: %s: label=%s, size=%" PRIu64, udev_device_get_devnode(dev), label, size);
LOG_INFO("partition: add: %s: label=%s, size=%"PRIu64,
udev_device_get_devnode(dev), label, size);
mtx_lock(&mod->lock);
tll_push_back(block->partitions, ((struct partition){.block = block,
.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.label = label != NULL ? strdup(label) : NULL,
.size = size,
.audio_cd = false,
.mount_points = tll_init()}));
tll_push_back(
block->partitions,
((struct partition){
.block = block,
.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.label = label != NULL ? strdup(label) : NULL,
.size = size,
.audio_cd = false,
.mount_points = tll_init()}));
struct partition *p = &tll_back(block->partitions);
update_mount_points(p);
@ -287,13 +296,14 @@ add_partition(struct module *mod, struct block_device *block, struct udev_device
}
static struct partition *
add_audio_cd(struct module *mod, struct block_device *block, struct udev_device *dev)
add_audio_cd(struct module *mod, struct block_device *block,
struct udev_device *dev)
{
struct private *m = mod->private;
const char *_size = udev_device_get_sysattr_value(dev, "size");
uint64_t size = 0;
if (_size != NULL)
sscanf(_size, "%" SCNu64, &size);
sscanf(_size, "%"SCNu64, &size);
#if 0
struct udev_list_entry *e = NULL;
@ -304,8 +314,7 @@ add_audio_cd(struct module *mod, struct block_device *block, struct udev_device
const char *devname = udev_device_get_property_value(dev, "DEVNAME");
if (devname != NULL) {
tll_foreach(m->ignore, it)
{
tll_foreach(m->ignore, it) {
if (strcmp(it->item, devname) == 0) {
LOG_DBG("ignoring %s because it is on the ignore list", devname);
return NULL;
@ -313,24 +322,28 @@ add_audio_cd(struct module *mod, struct block_device *block, struct udev_device
}
}
const char *_track_count = udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
const char *_track_count = udev_device_get_property_value(
dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long track_count = strtoul(_track_count, NULL, 10);
char label[64];
snprintf(label, sizeof(label), "Audio CD - %lu tracks", track_count);
LOG_INFO("audio CD: add: %s: tracks=%lu, label=%s, size=%" PRIu64, udev_device_get_devnode(dev), track_count, label,
size);
LOG_INFO("audio CD: add: %s: tracks=%lu, label=%s, size=%"PRIu64,
udev_device_get_devnode(dev), track_count, label, size);
mtx_lock(&mod->lock);
tll_push_back(block->partitions, ((struct partition){.block = block,
.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.label = label != NULL ? strdup(label) : NULL,
.size = size,
.audio_cd = true,
.mount_points = tll_init()}));
tll_push_back(
block->partitions,
((struct partition){
.block = block,
.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.label = label != NULL ? strdup(label) : NULL,
.size = size,
.audio_cd = true,
.mount_points = tll_init()}));
struct partition *p = &tll_back(block->partitions);
update_mount_points(p);
@ -340,15 +353,17 @@ add_audio_cd(struct module *mod, struct block_device *block, struct udev_device
}
static bool
del_partition(struct module *mod, struct block_device *block, struct udev_device *dev)
del_partition(struct module *mod, struct block_device *block,
struct udev_device *dev)
{
const char *sys_path = udev_device_get_devpath(dev);
mtx_lock(&mod->lock);
tll_foreach(block->partitions, it)
{
tll_foreach(block->partitions, it) {
if (strcmp(it->item.sys_path, sys_path) == 0) {
LOG_INFO("%s: del: %s", it->item.audio_cd ? "audio CD" : "partition", it->item.dev_path);
LOG_INFO("%s: del: %s",
it->item.audio_cd ? "audio CD" : "partition",
it->item.dev_path);
free_partition(&it->item);
tll_remove(block->partitions, it);
@ -377,8 +392,7 @@ add_device(struct module *mod, struct udev_device *dev)
const char *devname = udev_device_get_property_value(dev, "DEVNAME");
if (devname != NULL) {
tll_foreach(m->ignore, it)
{
tll_foreach(m->ignore, it) {
if (strcmp(it->item, devname) == 0) {
LOG_DBG("ignoring %s because it is on the ignore list", devname);
return NULL;
@ -389,12 +403,11 @@ add_device(struct module *mod, struct udev_device *dev)
const char *_size = udev_device_get_sysattr_value(dev, "size");
uint64_t size = 0;
if (_size != NULL)
sscanf(_size, "%" SCNu64, &size);
sscanf(_size, "%"SCNu64, &size);
#if 1
struct udev_list_entry *e = NULL;
udev_list_entry_foreach(e, udev_device_get_properties_list_entry(dev))
{
udev_list_entry_foreach(e, udev_device_get_properties_list_entry(dev)) {
LOG_DBG("%s -> %s", udev_list_entry_get_name(e), udev_list_entry_get_value(e));
}
#endif
@ -411,22 +424,27 @@ add_device(struct module *mod, struct udev_device *dev)
const char *_fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
bool have_fs = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0;
const char *_audio_track_count = udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long audio_track_count = _audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0;
const char *_audio_track_count = udev_device_get_property_value(
dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long audio_track_count =
_audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0;
LOG_DBG("device: add: %s: vendor=%s, model=%s, optical=%d, size=%" PRIu64, udev_device_get_devnode(dev), vendor,
model, optical, size);
LOG_DBG("device: add: %s: vendor=%s, model=%s, optical=%d, size=%"PRIu64,
udev_device_get_devnode(dev), vendor, model, optical, size);
mtx_lock(&mod->lock);
tll_push_back(m->devices, ((struct block_device){.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.size = size,
.vendor = vendor != NULL ? strdup(vendor) : NULL,
.model = model != NULL ? strdup(model) : NULL,
.optical = optical,
.media = media,
.partitions = tll_init()}));
tll_push_back(
m->devices,
((struct block_device){
.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.size = size,
.vendor = vendor != NULL ? strdup(vendor) : NULL,
.model = model != NULL ? strdup(model) : NULL,
.optical = optical,
.media = media,
.partitions = tll_init()}));
mtx_unlock(&mod->lock);
@ -448,8 +466,7 @@ del_device(struct module *mod, struct udev_device *dev)
const char *sys_path = udev_device_get_devpath(dev);
mtx_lock(&mod->lock);
tll_foreach(m->devices, it)
{
tll_foreach(m->devices, it) {
if (strcmp(it->item.sys_path, sys_path) == 0) {
LOG_DBG("device: del: %s", it->item.dev_path);
@ -473,8 +490,7 @@ change_device(struct module *mod, struct udev_device *dev)
struct block_device *block = NULL;
tll_foreach(m->devices, it)
{
tll_foreach(m->devices, it) {
if (strcmp(it->item.sys_path, sys_path) == 0) {
block = &it->item;
break;
@ -495,8 +511,10 @@ change_device(struct module *mod, struct udev_device *dev)
const char *_fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
bool have_fs = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0;
const char *_audio_track_count = udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long audio_track_count = _audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0;
const char *_audio_track_count = udev_device_get_property_value(
dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long audio_track_count =
_audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0;
bool media_change = media != block->media;
@ -504,7 +522,8 @@ change_device(struct module *mod, struct udev_device *dev)
mtx_unlock(&mod->lock);
if (media_change) {
LOG_INFO("device: change: %s: media %s", block->dev_path, media ? "inserted" : "removed");
LOG_INFO("device: change: %s: media %s",
block->dev_path, media ? "inserted" : "removed");
if (media) {
if (have_fs)
@ -550,8 +569,7 @@ handle_udev_event(struct module *mod, struct udev_device *dev)
struct udev_device *parent = udev_device_get_parent(dev);
const char *parent_sys_path = udev_device_get_devpath(parent);
tll_foreach(m->devices, it)
{
tll_foreach(m->devices, it) {
if (strcmp(it->item.sys_path, parent_sys_path) != 0)
continue;
@ -560,7 +578,8 @@ handle_udev_event(struct module *mod, struct udev_device *dev)
else if (del)
return del_partition(mod, &it->item, dev);
else {
LOG_ERR("unimplemented: 'change' event on partition: %s", udev_device_get_devpath(dev));
LOG_ERR("unimplemented: 'change' event on partition: %s",
udev_device_get_devpath(dev));
return false;
}
break;
@ -587,15 +606,15 @@ run(struct module *mod)
udev_enumerate_add_match_subsystem(dev_enum, "block");
/* TODO: verify how an optical presents itself */
// udev_enumerate_add_match_sysattr(dev_enum, "removable", "1");
//udev_enumerate_add_match_sysattr(dev_enum, "removable", "1");
udev_enumerate_add_match_property(dev_enum, "DEVTYPE", "disk");
udev_enumerate_scan_devices(dev_enum);
/* Loop list, and for each device, enumerate its partitions */
struct udev_list_entry *entry = NULL;
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(dev_enum))
{
struct udev_device *dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(entry));
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(dev_enum)) {
struct udev_device *dev = udev_device_new_from_syspath(
udev, udev_list_entry_get_name(entry));
struct block_device *block = add_device(mod, dev);
if (block == NULL) {
@ -612,9 +631,9 @@ run(struct module *mod)
udev_enumerate_scan_devices(part_enum);
struct udev_list_entry *sub_entry = NULL;
udev_list_entry_foreach(sub_entry, udev_enumerate_get_list_entry(part_enum))
{
struct udev_device *partition = udev_device_new_from_syspath(udev, udev_list_entry_get_name(sub_entry));
udev_list_entry_foreach(sub_entry, udev_enumerate_get_list_entry(part_enum)) {
struct udev_device *partition = udev_device_new_from_syspath(
udev, udev_list_entry_get_name(sub_entry));
add_partition(mod, block, partition);
udev_device_unref(partition);
}
@ -654,10 +673,8 @@ run(struct module *mod)
bool update = false;
if (fds[2].revents & POLLPRI) {
tll_foreach(m->devices, dev)
{
tll_foreach(dev->item.partitions, part)
{
tll_foreach(m->devices, dev) {
tll_foreach(dev->item.partitions, part) {
if (update_mount_points(&part->item))
update = true;
}
@ -686,8 +703,8 @@ run(struct module *mod)
}
static struct module *
removables_new(struct particle *label, int left_spacing, int right_spacing, size_t ignore_count,
const char *ignore[static ignore_count])
removables_new(struct particle *label, int left_spacing, int right_spacing,
size_t ignore_count, const char *ignore[static ignore_count])
{
struct private *priv = calloc(1, sizeof(*priv));
priv->label = label;
@ -715,22 +732,26 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *right_spacing = yml_get_value(node, "right-spacing");
const struct yml_node *ignore_list = yml_get_value(node, "ignore");
int left = spacing != NULL ? yml_value_as_int(spacing) : left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
int right = spacing != NULL ? yml_value_as_int(spacing)
: right_spacing != NULL ? yml_value_as_int(right_spacing)
: 0;
int left = spacing != NULL ? yml_value_as_int(spacing) :
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
int right = spacing != NULL ? yml_value_as_int(spacing) :
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
size_t ignore_count = ignore_list != NULL ? yml_list_length(ignore_list) : 0;
const char *ignore[max(ignore_count, 1)];
if (ignore_list != NULL) {
size_t i = 0;
for (struct yml_list_iter iter = yml_list_iter(ignore_list); iter.node != NULL; yml_list_next(&iter), i++) {
for (struct yml_list_iter iter = yml_list_iter(ignore_list);
iter.node != NULL;
yml_list_next(&iter), i++)
{
ignore[i] = yml_value_as_string(iter.node);
}
}
return removables_new(conf_to_particle(content, inherited), left, right, ignore_count, ignore);
return removables_new(
conf_to_particle(content, inherited), left, right, ignore_count, ignore);
}
static bool

View file

@ -1,17 +1,17 @@
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <poll.h>
#include <tllist.h>
#include <wayland-client.h>
#include <tllist.h>
#define LOG_MODULE "river"
#define LOG_ENABLE_DBG 0
#include "../log.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
#include "../particles/dynlist.h"
#include "river-status-unstable-v1.h"
#include "xdg-output-unstable-v1.h"
@ -49,10 +49,8 @@ struct seat {
struct output *output;
};
struct private
{
struct private {
struct module *mod;
bool is_running;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct zriver_status_manager_v1 *status_manager;
struct particle *template;
@ -89,22 +87,18 @@ content(struct module *mod)
mtx_lock(&m->mod->lock);
if (!m->is_running) {
mtx_unlock(&m->mod->lock);
return dynlist_exposable_new(NULL, 0, 0, 0);
}
uint32_t urgent = 0;
uint32_t occupied = 0;
uint32_t output_focused = 0;
uint32_t seat_focused = 0;
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
const struct output *output = &it->item;
if (!m->all_monitors && output_bar_is_on != NULL && output->name != NULL
&& strcmp(output->name, output_bar_is_on) != 0) {
if (!m->all_monitors &&
output_bar_is_on != NULL && output->name != NULL &&
strcmp(output->name, output_bar_is_on) != 0)
{
continue;
}
@ -112,8 +106,7 @@ content(struct module *mod)
urgent |= output->urgent;
occupied |= output->occupied;
tll_foreach(m->seats, it2)
{
tll_foreach(m->seats, it2) {
const struct seat *seat = &it2->item;
if (seat->output == output) {
seat_focused |= output->focused;
@ -134,7 +127,10 @@ content(struct module *mod)
bool is_urgent = urgent & (1u << i);
bool is_occupied = occupied & (1u << i);
const char *state = is_urgent ? "urgent" : is_visible ? is_focused ? "focused" : "unfocused" : "invisible";
const char *state =
is_urgent ? "urgent" :
is_visible ? is_focused ? "focused" : "unfocused" :
"invisible";
#if 0
LOG_DBG("tag: #%u, visible=%d, focused=%d, occupied=%d, state=%s",
@ -159,10 +155,12 @@ content(struct module *mod)
if (m->title != NULL) {
size_t i = 32;
tll_foreach(m->seats, it)
{
tll_foreach(m->seats, it) {
const struct seat *seat = &it->item;
const char *layout = seat->output != NULL && seat->output->layout != NULL ? seat->output->layout : "";
const char *layout =
seat->output != NULL && seat->output->layout != NULL
? seat->output->layout
: "";
struct tag_set tags = {
.tags = (struct tag *[]){
@ -189,15 +187,15 @@ verify_iface_version(const char *iface, uint32_t version, uint32_t wanted)
if (version >= wanted)
return true;
LOG_ERR("%s: need interface version %u, but compositor only implements %u", iface, wanted, version);
LOG_ERR("%s: need interface version %u, but compositor only implements %u",
iface, wanted, version);
return false;
}
static void
output_destroy(struct output *output)
{
tll_foreach(output->m->seats, it)
{
tll_foreach(output->m->seats, it) {
struct seat *seat = &it->item;
if (seat->output == output)
seat->output = NULL;
@ -225,7 +223,8 @@ seat_destroy(struct seat *seat)
}
static void
focused_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, uint32_t tags)
focused_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
uint32_t tags)
{
struct output *output = data;
@ -242,7 +241,8 @@ focused_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1
}
static void
view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, struct wl_array *tags)
view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
struct wl_array *tags)
{
struct output *output = data;
struct module *mod = output->m->mod;
@ -254,7 +254,9 @@ view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, s
/* Each entry in the list is a view, and the value is the tags
* associated with that view */
uint32_t *set;
wl_array_for_each(set, tags) { output->occupied |= *set; }
wl_array_for_each(set, tags) {
output->occupied |= *set;
}
LOG_DBG("output: %s: occupied tags: 0x%0x", output->name, output->occupied);
}
@ -263,7 +265,8 @@ view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, s
}
static void
urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, uint32_t tags)
urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
uint32_t tags)
{
struct output *output = data;
struct module *mod = output->m->mod;
@ -278,7 +281,9 @@ urgent_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
#if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_SINCE_VERSION)
static void
layout_name(void *data, struct zriver_output_status_v1 *zriver_output_status_v1, const char *name)
layout_name(void *data,
struct zriver_output_status_v1 *zriver_output_status_v1,
const char *name)
{
struct output *output = data;
struct module *mod = output->m->mod;
@ -295,7 +300,8 @@ layout_name(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
#if defined(ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_CLEAR_SINCE_VERSION)
static void
layout_name_clear(void *data, struct zriver_output_status_v1 *zriver_output_status_v1)
layout_name_clear(void *data,
struct zriver_output_status_v1 *zriver_output_status_v1)
{
struct output *output = data;
struct module *mod = output->m->mod;
@ -323,12 +329,15 @@ static const struct zriver_output_status_v1_listener river_status_output_listene
};
static void
xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y)
xdg_output_handle_logical_position(void *data,
struct zxdg_output_v1 *xdg_output,
int32_t x, int32_t y)
{
}
static void
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height)
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
int32_t width, int32_t height)
{
}
@ -338,7 +347,8 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
}
static void
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name)
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
const char *name)
{
struct output *output = data;
struct module *mod = output->m->mod;
@ -353,7 +363,8 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char
}
static void
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description)
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
const char *description)
{
}
@ -380,32 +391,36 @@ update_output(struct output *output)
output->status = NULL;
}
output->status = zriver_status_manager_v1_get_river_output_status(output->m->status_manager, output->wl_output);
output->status = zriver_status_manager_v1_get_river_output_status(
output->m->status_manager, output->wl_output);
if (output->status != NULL) {
zriver_output_status_v1_add_listener(output->status, &river_status_output_listener, output);
zriver_output_status_v1_add_listener(
output->status, &river_status_output_listener, output);
}
}
if (output->m->xdg_output_manager != NULL && output->xdg_output == NULL) {
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(output->m->xdg_output_manager, output->wl_output);
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
output->m->xdg_output_manager, output->wl_output);
if (output->xdg_output != NULL) {
zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
zxdg_output_v1_add_listener(
output->xdg_output, &xdg_output_listener, output);
}
}
}
static void
focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, struct wl_output *wl_output)
focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
struct wl_output *wl_output)
{
struct seat *seat = data;
struct private *m = seat->m;
struct module *mod = m->mod;
struct output *output = NULL;
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
if (it->item.wl_output == wl_output) {
output = &it->item;
break;
@ -426,7 +441,8 @@ focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
}
static void
unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, struct wl_output *wl_output)
unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
struct wl_output *wl_output)
{
struct seat *seat = data;
struct private *m = seat->m;
@ -435,8 +451,7 @@ unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1
mtx_lock(&mod->lock);
{
struct output *output = NULL;
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
if (it->item.wl_output == wl_output) {
output = &it->item;
break;
@ -454,7 +469,8 @@ unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1
}
static void
focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *title)
focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
const char *title)
{
struct seat *seat = data;
struct module *mod = seat->m->mod;
@ -469,9 +485,11 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, co
const char *output_bar_is_on = mod->bar->output_name(mod->bar);
if (seat->m->all_monitors
|| (output_bar_is_on != NULL && seat->output != NULL && seat->output->name != NULL
&& strcmp(output_bar_is_on, seat->output->name) == 0)) {
if (seat->m->all_monitors ||
(output_bar_is_on != NULL &&
seat->output != NULL && seat->output->name != NULL &&
strcmp(output_bar_is_on, seat->output->name) == 0))
{
mtx_lock(&mod->lock);
{
free(seat->title);
@ -484,7 +502,8 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, co
#if defined(ZRIVER_SEAT_STATUS_V1_MODE_SINCE_VERSION)
static void
mode(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *name)
mode(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
const char *name)
{
struct seat *seat = data;
struct module *mod = seat->m->mod;
@ -512,7 +531,8 @@ static const struct zriver_seat_status_v1_listener river_seat_status_listener =
};
static void
seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps)
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps)
{
}
@ -549,16 +569,19 @@ update_seat(struct seat *seat)
seat->status = NULL;
}
seat->status = zriver_status_manager_v1_get_river_seat_status(seat->m->status_manager, seat->wl_seat);
seat->status = zriver_status_manager_v1_get_river_seat_status(
seat->m->status_manager, seat->wl_seat);
if (seat->status == NULL)
return;
zriver_seat_status_v1_add_listener(seat->status, &river_seat_status_listener, seat);
zriver_seat_status_v1_add_listener(
seat->status, &river_seat_status_listener, seat);
}
static void
handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct private *m = data;
@ -567,7 +590,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
struct wl_output *wl_output = wl_registry_bind(registry, name, &wl_output_interface, required);
struct wl_output *wl_output = wl_registry_bind(
registry, name, &wl_output_interface, required);
if (wl_output == NULL)
return;
@ -581,7 +605,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
mtx_lock(&m->mod->lock);
tll_push_back(m->outputs, output);
update_output(&tll_back(m->outputs));
tll_foreach(m->seats, it) update_seat(&it->item);
tll_foreach(m->seats, it)
update_seat(&it->item);
mtx_unlock(&m->mod->lock);
}
@ -590,10 +615,12 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
m->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, required);
m->xdg_output_manager = wl_registry_bind(
registry, name, &zxdg_output_manager_v1_interface, required);
mtx_lock(&m->mod->lock);
tll_foreach(m->outputs, it) update_output(&it->item);
tll_foreach(m->outputs, it)
update_output(&it->item);
mtx_unlock(&m->mod->lock);
}
@ -602,7 +629,8 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
struct wl_seat *wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, required);
struct wl_seat *wl_seat = wl_registry_bind(
registry, name, &wl_seat_interface, required);
if (wl_seat == NULL)
return;
@ -621,11 +649,14 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha
if (!verify_iface_version(interface, version, required))
return;
m->status_manager = wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, min(version, 4));
m->status_manager = wl_registry_bind(
registry, name, &zriver_status_manager_v1_interface, min(version, 4));
mtx_lock(&m->mod->lock);
tll_foreach(m->outputs, it) update_output(&it->item);
tll_foreach(m->seats, it) update_seat(&it->item);
tll_foreach(m->outputs, it)
update_output(&it->item);
tll_foreach(m->seats, it)
update_seat(&it->item);
mtx_unlock(&m->mod->lock);
}
}
@ -636,8 +667,7 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
struct private *m = data;
mtx_lock(&m->mod->lock);
tll_foreach(m->outputs, it)
{
tll_foreach(m->outputs, it) {
if (it->item.wl_name == name) {
output_destroy(&it->item);
tll_remove(m->outputs, it);
@ -646,8 +676,7 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
}
}
tll_foreach(m->seats, it)
{
tll_foreach(m->seats, it) {
if (it->item.wl_name == name) {
seat_destroy(&it->item);
tll_remove(m->seats, it);
@ -678,8 +707,9 @@ run(struct module *mod)
goto out;
}
if ((registry = wl_display_get_registry(display)) == NULL
|| wl_registry_add_listener(registry, &registry_listener, m) != 0) {
if ((registry = wl_display_get_registry(display)) == NULL ||
wl_registry_add_listener(registry, &registry_listener, m) != 0)
{
LOG_ERR("failed to get Wayland registry");
goto out;
}
@ -691,8 +721,6 @@ run(struct module *mod)
goto out;
}
m->is_running = true;
wl_display_roundtrip(display);
while (true) {
@ -726,9 +754,11 @@ run(struct module *mod)
ret = 0;
out:
tll_foreach(m->seats, it) seat_destroy(&it->item);
tll_foreach(m->seats, it)
seat_destroy(&it->item);
tll_free(m->seats);
tll_foreach(m->outputs, it) output_destroy(&it->item);
tll_foreach(m->outputs, it)
output_destroy(&it->item);
tll_free(m->outputs);
if (m->xdg_output_manager != NULL)
@ -767,8 +797,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *title = yml_get_value(node, "title");
const struct yml_node *all_monitors = yml_get_value(node, "all-monitors");
return river_new(conf_to_particle(c, inherited), title != NULL ? conf_to_particle(title, inherited) : NULL,
all_monitors != NULL ? yml_value_as_bool(all_monitors) : false);
return river_new(
conf_to_particle(c, inherited),
title != NULL ? conf_to_particle(title, inherited) : NULL,
all_monitors != NULL ? yml_value_as_bool(all_monitors) : false);
}
static bool

View file

@ -1,14 +1,14 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
@ -16,16 +16,15 @@
#define LOG_MODULE "script"
#define LOG_ENABLE_DBG 0
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../config.h"
#include "../config-verify.h"
#include "../module.h"
#include "../plugin.h"
static const long min_poll_interval = 250;
struct private
{
struct private {
char *path;
size_t argc;
char **argv;
@ -111,8 +110,9 @@ process_line(struct module *mod, const char *line, size_t len)
size_t value_len = line + len - _value;
LOG_DBG("%.*s: name=\"%.*s\", type=\"%.*s\", value=\"%.*s\"", (int)len, line, (int)name_len, _name, (int)type_len,
type, (int)value_len, _value);
LOG_DBG("%.*s: name=\"%.*s\", type=\"%.*s\", value=\"%.*s\"",
(int)len, line,
(int)name_len, _name, (int)type_len, type, (int)value_len, _value);
name = malloc(name_len + 1);
memcpy(name, _name, name_len);
@ -165,12 +165,16 @@ process_line(struct module *mod, const char *line, size_t len)
tag = tag_new_float(mod, name, v);
}
else if ((type_len > 6 && memcmp(type, "range:", 6) == 0) || (type_len > 9 && memcmp(type, "realtime:", 9) == 0)) {
else if ((type_len > 6 && memcmp(type, "range:", 6) == 0) ||
(type_len > 9 && memcmp(type, "realtime:", 9) == 0))
{
const char *_start = type + 6;
const char *split = memchr(_start, '-', type_len - 6);
if (split == NULL || split == _start || (split + 1) - type >= type_len) {
LOG_ERR("tag range delimiter ('-') not found in type: %.*s", (int)type_len, type);
LOG_ERR(
"tag range delimiter ('-') not found in type: %.*s",
(int)type_len, type);
goto bad_tag;
}
@ -182,7 +186,9 @@ process_line(struct module *mod, const char *line, size_t len)
long start = 0;
for (size_t i = 0; i < start_len; i++) {
if (!(_start[i] >= '0' && _start[i] <= '9')) {
LOG_ERR("tag range start is not an integer: %.*s", (int)start_len, _start);
LOG_ERR(
"tag range start is not an integer: %.*s",
(int)start_len, _start);
goto bad_tag;
}
@ -193,7 +199,9 @@ process_line(struct module *mod, const char *line, size_t len)
long end = 0;
for (size_t i = 0; i < end_len; i++) {
if (!(_end[i] >= '0' && _end[i] <= '9')) {
LOG_ERR("tag range end is not an integer: %.*s", (int)end_len, _end);
LOG_ERR(
"tag range end is not an integer: %.*s",
(int)end_len, _end);
goto bad_tag;
}
@ -215,7 +223,8 @@ process_line(struct module *mod, const char *line, size_t len)
}
if (v < start || v > end) {
LOG_ERR("tag value is outside range: %ld <= %ld <= %ld", start, v, end);
LOG_ERR("tag value is outside range: %ld <= %ld <= %ld",
start, v, end);
goto bad_tag;
}
@ -289,7 +298,7 @@ data_received(struct module *mod, const char *data, size_t len)
{
struct private *m = mod->private;
while (len > m->recv_buf.sz - m->recv_buf.idx) {
if (len > m->recv_buf.sz - m->recv_buf.idx) {
size_t new_sz = m->recv_buf.sz == 0 ? 1024 : m->recv_buf.sz * 2;
char *new_buf = realloc(m->recv_buf.data, new_sz);
@ -317,7 +326,9 @@ data_received(struct module *mod, const char *data, size_t len)
process_transaction(mod, transaction_size);
assert(m->recv_buf.idx >= transaction_size + 1);
memmove(m->recv_buf.data, &m->recv_buf.data[transaction_size + 1], m->recv_buf.idx - (transaction_size + 1));
memmove(m->recv_buf.data,
&m->recv_buf.data[transaction_size + 1],
m->recv_buf.idx - (transaction_size + 1));
m->recv_buf.idx -= transaction_size + 1;
}
@ -421,8 +432,11 @@ execute_script(struct module *mod)
sigemptyset(&mask);
const struct sigaction sa = {.sa_handler = SIG_DFL};
if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0 || sigaction(SIGCHLD, &sa, NULL) < 0
|| sigprocmask(SIG_SETMASK, &mask, NULL) < 0) {
if (sigaction(SIGINT, &sa, NULL) < 0 ||
sigaction(SIGTERM, &sa, NULL) < 0 ||
sigaction(SIGCHLD, &sa, NULL) < 0 ||
sigprocmask(SIG_SETMASK, &mask, NULL) < 0)
{
goto fail;
}
@ -438,7 +452,9 @@ execute_script(struct module *mod)
if (dev_null < 0)
goto fail;
if (dup2(dev_null, STDIN_FILENO) < 0 || dup2(comm_pipe[1], STDOUT_FILENO) < 0) {
if (dup2(dev_null, STDIN_FILENO) < 0 ||
dup2(comm_pipe[1], STDOUT_FILENO) < 0)
{
goto fail;
}
@ -517,7 +533,9 @@ execute_script(struct module *mod)
usleep(10000);
pid_t waited_pid;
while ((waited_pid = waitpid(pid, NULL, timeout > 0 ? WNOHANG : 0)) == 0) {
while ((waited_pid = waitpid(
pid, NULL, timeout > 0 ? WNOHANG : 0)) == 0)
{
struct timeval now;
gettimeofday(&now, NULL);
@ -529,7 +547,7 @@ execute_script(struct module *mod)
/* Don't spinning */
thrd_yield();
usleep(100000); /* 100ms */
usleep(100000); /* 100ms */
}
if (waited_pid == pid) {
@ -562,7 +580,7 @@ run(struct module *mod)
break;
struct timeval now;
if (gettimeofday(&now, NULL) < 0) {
if (gettimeofday(&now, NULL) < 0) {
LOG_ERRNO("failed to get current time");
break;
}
@ -613,7 +631,8 @@ run(struct module *mod)
}
static struct module *
script_new(char *path, size_t argc, const char *const argv[static argc], int poll_interval, struct particle *_content)
script_new(char *path, size_t argc, const char *const argv[static argc],
int poll_interval, struct particle *_content)
{
struct private *m = calloc(1, sizeof(*m));
m->path = path;
@ -646,7 +665,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
if (args != NULL) {
size_t i = 0;
for (struct yml_list_iter iter = yml_list_iter(args); iter.node != NULL; yml_list_next(&iter), i++) {
for (struct yml_list_iter iter = yml_list_iter(args);
iter.node != NULL;
yml_list_next(&iter), i++)
{
argv[i] = yml_value_as_string(iter.node);
}
}
@ -669,8 +691,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
} else
path = strdup(yml_path);
return script_new(path, argc, argv, poll_interval != NULL ? yml_value_as_int(poll_interval) : 0,
conf_to_particle(c, inherited));
return script_new(
path, argc, argv,
poll_interval != NULL ? yml_value_as_int(poll_interval) : 0,
conf_to_particle(c, inherited));
}
static bool
@ -685,7 +709,8 @@ conf_verify_path(keychain_t *chain, const struct yml_node *node)
const bool is_absolute = path[0] == '/';
if (!is_tilde && !is_absolute) {
LOG_ERR("%s: path must either be absolute, or begin with '~/'", conf_err_prefix(chain, node));
LOG_ERR("%s: path must either be absolute, or begin with '~/'",
conf_err_prefix(chain, node));
return false;
}
@ -705,7 +730,8 @@ conf_verify_poll_interval(keychain_t *chain, const struct yml_node *node)
return false;
if (yml_value_as_int(node) < min_poll_interval) {
LOG_ERR("%s: interval value cannot be less than %ldms", conf_err_prefix(chain, node), min_poll_interval);
LOG_ERR("%s: interval value cannot be less than %ldms",
conf_err_prefix(chain, node), min_poll_interval);
return false;
}

View file

@ -3,15 +3,15 @@
#define LOG_MODULE "sway-xkb"
#define LOG_ENABLE_DBG 0
#include "../log.h"
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
#include "i3-common.h"
#include "i3-ipc.h"
#include "i3-common.h"
#define max(x, y) ((x) > (y) ? (x) : (y))
@ -21,8 +21,7 @@ struct input {
char *layout;
};
struct private
{
struct private {
struct particle *template;
int left_spacing;
int right_spacing;
@ -90,7 +89,8 @@ content(struct module *mod)
}
mtx_unlock(&mod->lock);
return dynlist_exposable_new(particles, m->num_existing_inputs, m->left_spacing, m->right_spacing);
return dynlist_exposable_new(
particles, m->num_existing_inputs, m->left_spacing, m->right_spacing);
}
static bool
@ -121,7 +121,8 @@ handle_input_reply(int sock, int type, const struct json_object *json, void *_mo
struct input *input = NULL;
for (size_t i = 0; i < m->num_inputs; i++) {
struct input *maybe_input = &m->inputs[i];
if (strcmp(maybe_input->identifier, id) == 0 && !maybe_input->exists) {
if (strcmp(maybe_input->identifier, id) == 0 && !maybe_input->exists)
{
input = maybe_input;
LOG_DBG("adding: %s", id);
@ -141,7 +142,8 @@ handle_input_reply(int sock, int type, const struct json_object *json, void *_mo
/* Get current/active layout */
struct json_object *layout;
if (!json_object_object_get_ex(obj, "xkb_active_layout_name", &layout))
if (!json_object_object_get_ex(
obj, "xkb_active_layout_name", &layout))
return false;
const char *new_layout_str = json_object_get_string(layout);
@ -238,7 +240,8 @@ handle_input_event(int sock, int type, const struct json_object *json, void *_mo
/* Get current/active layout */
struct json_object *layout;
if (!json_object_object_get_ex(obj, "xkb_active_layout_name", &layout))
if (!json_object_object_get_ex(
obj, "xkb_active_layout_name", &layout))
return false;
const char *new_layout_str = json_object_get_string(layout);
@ -306,8 +309,8 @@ run(struct module *mod)
}
static struct module *
sway_xkb_new(struct particle *template, const char *identifiers[], size_t num_identifiers, int left_spacing,
int right_spacing)
sway_xkb_new(struct particle *template, const char *identifiers[],
size_t num_identifiers, int left_spacing, int right_spacing)
{
struct private *m = calloc(1, sizeof(*m));
m->template = template;
@ -340,32 +343,40 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
const struct yml_node *left_spacing = yml_get_value(node, "left-spacing");
const struct yml_node *right_spacing = yml_get_value(node, "right-spacing");
int left = spacing != NULL ? yml_value_as_int(spacing) : left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
int right = spacing != NULL ? yml_value_as_int(spacing)
: right_spacing != NULL ? yml_value_as_int(right_spacing)
: 0;
int left = spacing != NULL ? yml_value_as_int(spacing) :
left_spacing != NULL ? yml_value_as_int(left_spacing) : 0;
int right = spacing != NULL ? yml_value_as_int(spacing) :
right_spacing != NULL ? yml_value_as_int(right_spacing) : 0;
const struct yml_node *ids = yml_get_value(node, "identifiers");
const size_t num_ids = yml_list_length(ids);
const char *identifiers[num_ids];
size_t i = 0;
for (struct yml_list_iter it = yml_list_iter(ids); it.node != NULL; yml_list_next(&it), i++) {
for (struct yml_list_iter it = yml_list_iter(ids);
it.node != NULL;
yml_list_next(&it), i++)
{
identifiers[i] = yml_value_as_string(it.node);
}
return sway_xkb_new(conf_to_particle(c, inherited), identifiers, num_ids, left, right);
return sway_xkb_new(
conf_to_particle(c, inherited), identifiers, num_ids, left, right);
}
static bool
verify_identifiers(keychain_t *chain, const struct yml_node *node)
{
if (!yml_is_list(node)) {
LOG_ERR("%s: identifiers must be a list of strings", conf_err_prefix(chain, node));
LOG_ERR("%s: identifiers must be a list of strings",
conf_err_prefix(chain, node));
return false;
}
for (struct yml_list_iter it = yml_list_iter(node); it.node != NULL; yml_list_next(&it)) {
for (struct yml_list_iter it = yml_list_iter(node);
it.node != NULL;
yml_list_next(&it))
{
if (!conf_verify_string(chain, it.node))
return false;
}
@ -393,5 +404,5 @@ const struct module_iface module_sway_xkb_iface = {
};
#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
extern const struct module_iface iface __attribute__((weak, alias("module_sway_xkb_iface")));
extern const struct module_iface iface __attribute__((weak, alias("module_sway_xkb_iface"))) ;
#endif

View file

@ -1,7 +1,7 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
@ -10,10 +10,10 @@
#define LOG_MODULE "xkb"
#define LOG_ENABLE_DBG 0
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../plugin.h"
#include "../xcb.h"
@ -32,8 +32,7 @@ struct indicators {
char **names;
};
struct private
{
struct private {
struct particle *label;
struct indicators indicators;
struct layouts layouts;
@ -118,8 +117,10 @@ xkb_enable(xcb_connection_t *conn)
{
xcb_generic_error_t *err;
xcb_xkb_use_extension_cookie_t cookie = xcb_xkb_use_extension(conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
xcb_xkb_use_extension_reply_t *reply = xcb_xkb_use_extension_reply(conn, cookie, &err);
xcb_xkb_use_extension_cookie_t cookie = xcb_xkb_use_extension(
conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
xcb_xkb_use_extension_reply_t *reply = xcb_xkb_use_extension_reply(
conn, cookie, &err);
if (err != NULL) {
LOG_ERR("failed to query for XKB extension: %s", xcb_error(err));
@ -141,7 +142,8 @@ xkb_enable(xcb_connection_t *conn)
static int
get_xkb_event_base(xcb_connection_t *conn)
{
const struct xcb_query_extension_reply_t *reply = xcb_get_extension_data(conn, &xcb_xkb_id);
const struct xcb_query_extension_reply_t *reply = xcb_get_extension_data(
conn, &xcb_xkb_id);
if (reply == NULL) {
LOG_ERR("failed to get XKB extension data");
@ -157,14 +159,19 @@ get_xkb_event_base(xcb_connection_t *conn)
}
static bool
get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, struct indicators *indicators)
get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
struct indicators *indicators)
{
xcb_generic_error_t *err;
xcb_xkb_get_names_cookie_t cookie = xcb_xkb_get_names(conn, XCB_XKB_ID_USE_CORE_KBD,
XCB_XKB_NAME_DETAIL_GROUP_NAMES | XCB_XKB_NAME_DETAIL_SYMBOLS
| XCB_XKB_NAME_DETAIL_INDICATOR_NAMES);
xcb_xkb_get_names_cookie_t cookie = xcb_xkb_get_names(
conn,
XCB_XKB_ID_USE_CORE_KBD,
XCB_XKB_NAME_DETAIL_GROUP_NAMES |
XCB_XKB_NAME_DETAIL_SYMBOLS |
XCB_XKB_NAME_DETAIL_INDICATOR_NAMES);
xcb_xkb_get_names_reply_t *reply = xcb_xkb_get_names_reply(conn, cookie, &err);
xcb_xkb_get_names_reply_t *reply = xcb_xkb_get_names_reply(
conn, cookie, &err);
if (err != NULL) {
LOG_ERR("failed to get layouts and indicators: %s", xcb_error(err));
@ -174,18 +181,22 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
xcb_xkb_get_names_value_list_t vlist;
void *buf = xcb_xkb_get_names_value_list(reply);
xcb_xkb_get_names_value_list_unpack(buf, reply->nTypes, reply->indicators, reply->virtualMods, reply->groupNames,
reply->nKeys, reply->nKeyAliases, reply->nRadioGroups, reply->which, &vlist);
xcb_xkb_get_names_value_list_unpack(
buf, reply->nTypes, reply->indicators, reply->virtualMods,
reply->groupNames, reply->nKeys, reply->nKeyAliases,
reply->nRadioGroups, reply->which, &vlist);
/* Number of groups (aka layouts) */
layouts->count = xcb_xkb_get_names_value_list_groups_length(reply, &vlist);
layouts->layouts = calloc(layouts->count, sizeof(layouts->layouts[0]));
/* Number of indicators */
indicators->count = xcb_xkb_get_names_value_list_indicator_names_length(reply, &vlist);
indicators->count = xcb_xkb_get_names_value_list_indicator_names_length(
reply, &vlist);
indicators->names = calloc(indicators->count, sizeof(indicators->names[0]));
xcb_get_atom_name_cookie_t symbols_name_cookie = xcb_get_atom_name(conn, vlist.symbolsName);
xcb_get_atom_name_cookie_t symbols_name_cookie = xcb_get_atom_name(
conn, vlist.symbolsName);
xcb_get_atom_name_cookie_t group_name_cookies[layouts->count];
for (size_t i = 0; i < layouts->count; i++)
@ -198,14 +209,17 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
char *symbols = NULL;
/* Get layout short names (e.g. "us") */
xcb_get_atom_name_reply_t *atom_name = xcb_get_atom_name_reply(conn, symbols_name_cookie, &err);
xcb_get_atom_name_reply_t *atom_name = xcb_get_atom_name_reply(
conn, symbols_name_cookie, &err);
if (err != NULL) {
LOG_ERR("failed to get 'symbols' atom name: %s", xcb_error(err));
free(err);
goto err;
}
symbols = strndup(xcb_get_atom_name_name(atom_name), xcb_get_atom_name_name_length(atom_name));
symbols = strndup(
xcb_get_atom_name_name(atom_name),
xcb_get_atom_name_name_length(atom_name));
LOG_DBG("symbols: %s", symbols);
free(atom_name);
@ -218,7 +232,9 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
goto err;
}
layouts->layouts[i].name = strndup(xcb_get_atom_name_name(atom_name), xcb_get_atom_name_name_length(atom_name));
layouts->layouts[i].name = strndup(
xcb_get_atom_name_name(atom_name),
xcb_get_atom_name_name_length(atom_name));
LOG_DBG("layout #%zd: long name: %s", i, layouts->layouts[i].name);
free(atom_name);
@ -233,7 +249,9 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
goto err;
}
indicators->names[i] = strndup(xcb_get_atom_name_name(atom_name), xcb_get_atom_name_name_length(atom_name));
indicators->names[i] = strndup(
xcb_get_atom_name_name(atom_name),
xcb_get_atom_name_name_length(atom_name));
LOG_DBG("indicator #%zd: %s", i, indicators->names[i]);
free(atom_name);
@ -241,7 +259,8 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
/* e.g. pc+us+inet(evdev)+group(..) */
size_t layout_idx = 0;
for (char *tok_ctx = NULL, *tok = strtok_r(symbols, "+", &tok_ctx); tok != NULL;
for (char *tok_ctx = NULL, *tok = strtok_r(symbols, "+", &tok_ctx);
tok != NULL;
tok = strtok_r(NULL, "+", &tok_ctx)) {
char *fname = strtok(tok, "()");
@ -260,7 +279,8 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
continue;
if (layout_idx >= layouts->count) {
LOG_ERR("layout vs group name count mismatch: %zd > %zd", layout_idx + 1, layouts->count);
LOG_ERR("layout vs group name count mismatch: %zd > %zd",
layout_idx + 1, layouts->count);
goto err;
}
@ -270,7 +290,8 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts, stru
}
if (layout_idx != layouts->count) {
LOG_ERR("layout vs group name count mismatch: %zd != %zd", layout_idx, layouts->count);
LOG_ERR("layout vs group name count mismatch: %zd != %zd",
layout_idx, layouts->count);
goto err;
}
@ -291,8 +312,10 @@ get_current_layout(xcb_connection_t *conn)
{
xcb_generic_error_t *err;
xcb_xkb_get_state_cookie_t cookie = xcb_xkb_get_state(conn, XCB_XKB_ID_USE_CORE_KBD);
xcb_xkb_get_state_reply_t *reply = xcb_xkb_get_state_reply(conn, cookie, &err);
xcb_xkb_get_state_cookie_t cookie = xcb_xkb_get_state(
conn, XCB_XKB_ID_USE_CORE_KBD);
xcb_xkb_get_state_reply_t *reply = xcb_xkb_get_state_reply(
conn, cookie, &err);
if (err != NULL) {
LOG_ERR("failed to get XKB state: %s", xcb_error(err));
@ -309,8 +332,10 @@ static uint32_t
get_indicator_state(xcb_connection_t *conn)
{
xcb_generic_error_t *err;
xcb_xkb_get_indicator_state_cookie_t cookie = xcb_xkb_get_indicator_state(conn, XCB_XKB_ID_USE_CORE_KBD);
xcb_xkb_get_indicator_state_reply_t *reply = xcb_xkb_get_indicator_state_reply(conn, cookie, &err);
xcb_xkb_get_indicator_state_cookie_t cookie = xcb_xkb_get_indicator_state(
conn, XCB_XKB_ID_USE_CORE_KBD);
xcb_xkb_get_indicator_state_reply_t *reply = xcb_xkb_get_indicator_state_reply(
conn, cookie, &err);
if (err != NULL) {
LOG_ERR("failed to get indicator state: %s", xcb_error(err));
@ -328,14 +353,23 @@ get_indicator_state(xcb_connection_t *conn)
static bool
register_for_events(xcb_connection_t *conn)
{
xcb_void_cookie_t cookie
= xcb_xkb_select_events_checked(conn, XCB_XKB_ID_USE_CORE_KBD,
(XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY
| XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY),
0,
(XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY
| XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY),
0, 0, NULL);
xcb_void_cookie_t cookie = xcb_xkb_select_events_checked(
conn,
XCB_XKB_ID_USE_CORE_KBD,
(
XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
XCB_XKB_EVENT_TYPE_STATE_NOTIFY |
XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY
),
0,
(
XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
XCB_XKB_EVENT_TYPE_STATE_NOTIFY |
XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
XCB_XKB_EVENT_TYPE_INDICATOR_STATE_NOTIFY
),
0, 0, NULL);
xcb_generic_error_t *err = xcb_request_check(conn, cookie);
if (err != NULL) {
@ -359,7 +393,10 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
assert(xcb_fd >= 0);
while (!has_error) {
struct pollfd pfds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = xcb_fd, .events = POLLIN | POLLHUP}};
struct pollfd pfds[] = {
{.fd = mod->abort_fd, .events = POLLIN },
{.fd = xcb_fd, .events = POLLIN | POLLHUP }
};
/* Use poll() since xcb_wait_for_events() doesn't return on signals */
if (poll(pfds, sizeof(pfds) / sizeof(pfds[0]), -1) < 0) {
@ -388,7 +425,9 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
* not for long though...
*/
for (xcb_generic_event_t *_evt = xcb_wait_for_event(conn); _evt != NULL; _evt = xcb_poll_for_event(conn)) {
for (xcb_generic_event_t *_evt = xcb_wait_for_event(conn);
_evt != NULL;
_evt = xcb_poll_for_event(conn)) {
if (_evt->response_type != xkb_event_base) {
LOG_WARN("non-XKB event ignored: %d", _evt->response_type);
@ -396,7 +435,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
continue;
}
switch (_evt->pad0) {
switch(_evt->pad0) {
default:
LOG_WARN("unimplemented XKB event: %d", _evt->pad0);
break;
@ -424,7 +463,7 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
mtx_unlock(&mod->lock);
bar->refresh(bar);
} else {
/* Can happen while transitioning to a new map */
/* Can happen while transitioning to a new map */
free_layouts(layouts);
free_indicators(indicators);
}
@ -433,7 +472,8 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
}
case XCB_XKB_STATE_NOTIFY: {
const xcb_xkb_state_notify_event_t *evt = (const xcb_xkb_state_notify_event_t *)_evt;
const xcb_xkb_state_notify_event_t *evt =
(const xcb_xkb_state_notify_event_t *)_evt;
if (evt->changed & XCB_XKB_STATE_PART_GROUP_STATE) {
mtx_lock(&mod->lock);
@ -450,8 +490,8 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
break;
case XCB_XKB_INDICATOR_STATE_NOTIFY: {
const xcb_xkb_indicator_state_notify_event_t *evt
= (const xcb_xkb_indicator_state_notify_event_t *)_evt;
const xcb_xkb_indicator_state_notify_event_t *evt =
(const xcb_xkb_indicator_state_notify_event_t *)_evt;
#if 0
size_t idx = __builtin_ctz(evt->stateChanged);
@ -468,7 +508,8 @@ event_loop(struct module *mod, xcb_connection_t *conn, int xkb_event_base)
continue;
bool enabled = (evt->state >> i) & 1;
LOG_DBG("%s: %s", m->indicators.names[i], enabled ? "enabled" : "disabled");
LOG_DBG("%s: %s", m->indicators.names[i],
enabled ? "enabled" : "disabled");
const char *name = m->indicators.names[i];
bool is_caps = strcasecmp(name, "caps lock") == 0;
@ -568,12 +609,18 @@ talk_to_xkb(struct module *mod, xcb_connection_t *conn)
size_t idx = 0;
for (size_t i = 0; i < layouts.count; i++) {
idx += snprintf(&buf[idx], sizeof(buf) - idx, "%s%s (%s)%s", i == m->current ? "*" : "",
layouts.layouts[i].name, layouts.layouts[i].symbol, i + 1 < layouts.count ? ", " : "");
idx += snprintf(&buf[idx], sizeof(buf) - idx, "%s%s (%s)%s",
i == m->current ? "*" : "",
layouts.layouts[i].name,
layouts.layouts[i].symbol,
i + 1 < layouts.count ? ", " : "");
}
LOG_INFO("layouts: %s, caps-lock:%s, num-lock:%s, scroll-lock:%s", buf, caps_lock ? "on" : "off",
num_lock ? "on" : "off", scroll_lock ? "on" : "off");
LOG_INFO("layouts: %s, caps-lock:%s, num-lock:%s, scroll-lock:%s",
buf,
caps_lock ? "on" : "off",
num_lock ? "on" : "off",
scroll_lock ? "on" : "off");
}
mtx_lock(&mod->lock);

View file

@ -1,30 +1,29 @@
#include <assert.h>
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <threads.h>
#include <libgen.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/stat.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_event.h>
#define LOG_MODULE "xwindow"
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
#include "../plugin.h"
#include "../xcb.h"
struct private
{
struct private {
/* Accessed from bar thread only */
struct particle *label;
@ -49,19 +48,23 @@ static void
update_active_window(struct private *m)
{
if (m->active_win != 0) {
xcb_void_cookie_t c = xcb_change_window_attributes_checked(m->conn, m->active_win, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_NO_EVENT});
xcb_void_cookie_t c = xcb_change_window_attributes_checked(
m->conn, m->active_win, XCB_CW_EVENT_MASK,
(const uint32_t []){XCB_EVENT_MASK_NO_EVENT});
xcb_generic_error_t *e = xcb_request_check(m->conn, c);
if (e != NULL) {
LOG_DBG("failed to de-register events on previous active window: %s", xcb_error(e));
LOG_DBG(
"failed to de-register events on previous active window: %s",
xcb_error(e));
free(e);
}
m->active_win = 0;
}
xcb_get_property_cookie_t c = xcb_get_property(m->conn, 0, m->root_win, _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 0, 32);
xcb_get_property_cookie_t c = xcb_get_property(
m->conn, 0, m->root_win, _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 0, 32);
xcb_generic_error_t *e;
xcb_get_property_reply_t *r = xcb_get_property_reply(m->conn, c, &e);
@ -83,8 +86,9 @@ update_active_window(struct private *m)
free(r);
if (m->active_win != 0) {
xcb_change_window_attributes(m->conn, m->active_win, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_PROPERTY_CHANGE});
xcb_change_window_attributes(
m->conn, m->active_win, XCB_CW_EVENT_MASK,
(const uint32_t []){XCB_EVENT_MASK_PROPERTY_CHANGE});
}
}
@ -101,7 +105,8 @@ update_application(struct module *mod)
if (m->active_win == 0)
return;
xcb_get_property_cookie_t c = xcb_get_property(m->conn, 0, m->active_win, _NET_WM_PID, XCB_ATOM_CARDINAL, 0, 32);
xcb_get_property_cookie_t c = xcb_get_property(
m->conn, 0, m->active_win, _NET_WM_PID, XCB_ATOM_CARDINAL, 0, 32);
xcb_generic_error_t *e;
xcb_get_property_reply_t *r = xcb_get_property_reply(m->conn, c, &e);
@ -130,7 +135,7 @@ update_application(struct module *mod)
char path[1024];
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
int fd = open(path, O_RDONLY);
if (fd == -1)
return;
@ -159,11 +164,12 @@ update_title(struct module *mod)
if (m->active_win == 0)
return;
xcb_get_property_cookie_t c1
= xcb_get_property(m->conn, 0, m->active_win, _NET_WM_VISIBLE_NAME, UTF8_STRING, 0, 1000);
xcb_get_property_cookie_t c2 = xcb_get_property(m->conn, 0, m->active_win, _NET_WM_NAME, UTF8_STRING, 0, 1000);
xcb_get_property_cookie_t c3
= xcb_get_property(m->conn, 0, m->active_win, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1000);
xcb_get_property_cookie_t c1 = xcb_get_property(
m->conn, 0, m->active_win, _NET_WM_VISIBLE_NAME, UTF8_STRING, 0, 1000);
xcb_get_property_cookie_t c2 = xcb_get_property(
m->conn, 0, m->active_win, _NET_WM_NAME, UTF8_STRING, 0, 1000);
xcb_get_property_cookie_t c3 = xcb_get_property(
m->conn, 0, m->active_win, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1000);
xcb_generic_error_t *e1, *e2, *e3;
xcb_get_property_reply_t *r1 = xcb_get_property_reply(m->conn, c1, &e1);
@ -201,7 +207,7 @@ update_title(struct module *mod)
free(r1);
free(r2);
free(r3);
}
}
static int
run(struct module *mod)
@ -221,16 +227,19 @@ run(struct module *mod)
/* Need a window(?) to be able to process events */
m->monitor_win = xcb_generate_id(m->conn);
xcb_create_window(m->conn, screen->root_depth, m->monitor_win, screen->root, -1, -1, 1, 1, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, XCB_CW_OVERRIDE_REDIRECT,
(const uint32_t[]){1});
xcb_create_window(m->conn, screen->root_depth, m->monitor_win, screen->root,
-1, -1, 1, 1,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
XCB_CW_OVERRIDE_REDIRECT, (const uint32_t []){1});
xcb_map_window(m->conn, m->monitor_win);
/* Register for property changes on root window. This allows us to
* catch e.g. window switches etc */
xcb_change_window_attributes(m->conn, screen->root, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_PROPERTY_CHANGE});
xcb_change_window_attributes(
m->conn, screen->root, XCB_CW_EVENT_MASK,
(const uint32_t []){XCB_EVENT_MASK_PROPERTY_CHANGE});
xcb_flush(m->conn);
@ -243,7 +252,8 @@ run(struct module *mod)
int xcb_fd = xcb_get_file_descriptor(m->conn);
while (true) {
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}, {.fd = xcb_fd, .events = POLLIN}};
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN},
{.fd = xcb_fd, .events = POLLIN}};
if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) < 0) {
if (errno == EINTR)
continue;
@ -257,7 +267,10 @@ run(struct module *mod)
break;
}
for (xcb_generic_event_t *_e = xcb_wait_for_event(m->conn); _e != NULL; _e = xcb_poll_for_event(m->conn)) {
for (xcb_generic_event_t *_e = xcb_wait_for_event(m->conn);
_e != NULL;
_e = xcb_poll_for_event(m->conn))
{
switch (XCB_EVENT_RESPONSE_TYPE(_e)) {
case 0:
LOG_ERR("XCB: %s", xcb_error((const xcb_generic_error_t *)_e));
@ -265,13 +278,18 @@ run(struct module *mod)
case XCB_PROPERTY_NOTIFY: {
xcb_property_notify_event_t *e = (xcb_property_notify_event_t *)_e;
if (e->atom == _NET_ACTIVE_WINDOW || e->atom == _NET_CURRENT_DESKTOP) {
if (e->atom == _NET_ACTIVE_WINDOW ||
e->atom == _NET_CURRENT_DESKTOP)
{
/* Active desktop and/or window changed */
update_active_window(m);
update_application(mod);
update_title(mod);
mod->bar->refresh(mod->bar);
} else if (e->atom == _NET_WM_VISIBLE_NAME || e->atom == _NET_WM_NAME || e->atom == XCB_ATOM_WM_NAME) {
} else if (e->atom == _NET_WM_VISIBLE_NAME ||
e->atom == _NET_WM_NAME ||
e->atom == XCB_ATOM_WM_NAME)
{
assert(e->window == m->active_win);
update_title(mod);
mod->bar->refresh(mod->bar);

View file

@ -1,21 +1,21 @@
#include "particle.h"
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#define LOG_MODULE "particle"
#define LOG_ENABLE_DBG 0
#include "bar/bar.h"
#include "log.h"
#include "bar/bar.h"
void
particle_default_destroy(struct particle *particle)
@ -29,8 +29,10 @@ particle_default_destroy(struct particle *particle)
}
struct particle *
particle_common_new(int left_margin, int right_margin, char **on_click_templates, struct fcft_font *font,
enum font_shaping font_shaping, pixman_color_t foreground, struct deco *deco)
particle_common_new(int left_margin, int right_margin,
char **on_click_templates,
struct fcft_font *font, enum font_shaping font_shaping,
pixman_color_t foreground, struct deco *deco)
{
struct particle *p = calloc(1, sizeof(*p));
p->left_margin = left_margin;
@ -61,11 +63,13 @@ exposable_default_destroy(struct exposable *exposable)
}
void
exposable_render_deco(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height)
exposable_render_deco(const struct exposable *exposable,
pixman_image_t *pix, int x, int y, int height)
{
const struct deco *deco = exposable->particle->deco;
if (deco != NULL)
deco->expose(deco, pix, x, y, exposable->width, height);
}
static bool
@ -110,7 +114,9 @@ tokenize_cmdline(char *cmdline, char ***argv)
return false;
}
if (!push_argv(argv, &argv_size, p, &idx) || !push_argv(argv, &argv_size, NULL, &idx)) {
if (!push_argv(argv, &argv_size, p, &idx) ||
!push_argv(argv, &argv_size, NULL, &idx))
{
goto err;
} else
return true;
@ -146,7 +152,8 @@ err:
}
void
exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn,
exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
enum mouse_event event, enum mouse_button btn,
int x, int y)
{
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
@ -161,13 +168,17 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mo
[MOUSE_BTN_PREVIOUS] = "previous",
[MOUSE_BTN_NEXT] = "next",
};
LOG_DBG("on_mouse: exposable=%p, event=%s, btn=%s, x=%d, y=%d (on-click=%s)", exposable,
event == ON_MOUSE_MOTION ? "motion" : "click", button_name[btn], x, y, exposable->on_click[btn]);
LOG_DBG("on_mouse: exposable=%p, event=%s, btn=%s, x=%d, y=%d (on-click=%s)",
exposable, event == ON_MOUSE_MOTION ? "motion" : "click",
button_name[btn], x, y, exposable->on_click[btn]);
#endif
/* If we have a handler, change cursor to a hand */
const char *cursor
= (exposable->particle != NULL && exposable->particle->have_on_click_template) ? "hand2" : "left_ptr";
const char *cursor =
(exposable->particle != NULL &&
exposable->particle->have_on_click_template)
? "hand2"
: "left_ptr";
bar->set_cursor(bar, cursor);
/* If this is a mouse click, and we have a handler, execute it */
@ -235,7 +246,7 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mo
case 0:
/* Child */
close(pipe_fds[0]); /* Close read end */
close(pipe_fds[0]); /* Close read end */
LOG_DBG("executing on-click handler: %s", cmd);
@ -243,8 +254,11 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mo
sigemptyset(&mask);
const struct sigaction sa = {.sa_handler = SIG_DFL};
if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0
|| sigaction(SIGCHLD, &sa, NULL) < 0 || sigprocmask(SIG_SETMASK, &mask, NULL) < 0) {
if (sigaction(SIGINT, &sa, NULL) < 0 ||
sigaction(SIGTERM, &sa, NULL) < 0 ||
sigaction(SIGCHLD, &sa, NULL) < 0 ||
sigprocmask(SIG_SETMASK, &mask, NULL) < 0)
{
goto fail;
}
@ -257,8 +271,10 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mo
goto fail;
}
if (dup2(dev_null_r, STDIN_FILENO) == -1 || dup2(dev_null_w, STDOUT_FILENO) == -1
|| dup2(dev_null_w, STDERR_FILENO) == -1) {
if (dup2(dev_null_r, STDIN_FILENO) == -1 ||
dup2(dev_null_w, STDOUT_FILENO) == -1 ||
dup2(dev_null_w, STDERR_FILENO) == -1)
{
LOG_ERRNO("failed to redirect stdin/stdout/stderr");
goto fail;
}
@ -300,7 +316,10 @@ exposable_common_new(const struct particle *particle, const struct tag_set *tags
exposable->particle = particle;
if (particle != NULL && particle->have_on_click_template) {
tags_expand_templates(exposable->on_click, (const char **)particle->on_click_templates, MOUSE_BTN_COUNT, tags);
tags_expand_templates(
exposable->on_click,
(const char **)particle->on_click_templates,
MOUSE_BTN_COUNT, tags);
}
exposable->destroy = &exposable_default_destroy;
exposable->on_mouse = &exposable_default_on_mouse;

View file

@ -42,9 +42,11 @@ struct particle {
struct deco *deco;
void (*destroy)(struct particle *particle);
struct exposable *(*instantiate)(const struct particle *particle, const struct tag_set *tags);
struct exposable *(*instantiate)(const struct particle *particle,
const struct tag_set *tags);
};
struct exposable {
const struct particle *particle;
void *private;
@ -54,31 +56,38 @@ struct exposable {
void (*destroy)(struct exposable *exposable);
int (*begin_expose)(struct exposable *exposable);
void (*expose)(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height);
void (*expose)(const struct exposable *exposable, pixman_image_t *pix,
int x, int y, int height);
void (*on_mouse)(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x,
int y);
void (*on_mouse)(struct exposable *exposable, struct bar *bar,
enum mouse_event event, enum mouse_button btn, int x, int y);
};
struct particle *particle_common_new(int left_margin, int right_margin, char *on_click_templates[],
struct fcft_font *font, enum font_shaping font_shaping, pixman_color_t foreground,
struct deco *deco);
struct particle *particle_common_new(
int left_margin, int right_margin, char *on_click_templates[],
struct fcft_font *font, enum font_shaping font_shaping,
pixman_color_t foreground, struct deco *deco);
void particle_default_destroy(struct particle *particle);
struct exposable *exposable_common_new(const struct particle *particle, const struct tag_set *tags);
struct exposable *exposable_common_new(
const struct particle *particle, const struct tag_set *tags);
void exposable_default_destroy(struct exposable *exposable);
void exposable_render_deco(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height);
void exposable_render_deco(
const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height);
void exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y);
void exposable_default_on_mouse(
struct exposable *exposable, struct bar *bar,
enum mouse_event event, enum mouse_button btn, int x, int y);
/* List of attributes *all* particles implement */
#define PARTICLE_COMMON_ATTRS \
{"margin", false, &conf_verify_unsigned}, {"left-margin", false, &conf_verify_unsigned}, \
{"right-margin", false, &conf_verify_unsigned}, {"on-click", false, &conf_verify_on_click}, \
{"font", false, &conf_verify_font}, {"font-shaping", false, &conf_verify_font_shaping}, \
{"foreground", false, &conf_verify_color}, {"deco", false, &conf_verify_decoration}, \
{ \
NULL, false, NULL \
}
#define PARTICLE_COMMON_ATTRS \
{"margin", false, &conf_verify_unsigned}, \
{"left-margin", false, &conf_verify_unsigned}, \
{"right-margin", false, &conf_verify_unsigned}, \
{"on-click", false, &conf_verify_on_click}, \
{"font", false, &conf_verify_font}, \
{"font-shaping", false, &conf_verify_font_shaping}, \
{"foreground", false, &conf_verify_color}, \
{"deco", false, &conf_verify_decoration}, \
{NULL, false, NULL}

View file

@ -1,14 +1,13 @@
#include "dynlist.h"
#include <assert.h>
#include <stdlib.h>
#include <assert.h>
#define LOG_MODULE "dynlist"
#include "../log.h"
#include "../particle.h"
struct private
{
struct private {
int left_spacing;
int right_spacing;
@ -72,13 +71,13 @@ dynlist_expose(const struct exposable *exposable, pixman_image_t *pix, int x, in
for (size_t i = 0; i < e->count; i++) {
const struct exposable *ee = e->exposables[i];
ee->expose(ee, pix, x + left_spacing, y, height);
if (e->widths[i] > 0)
x += left_spacing + e->widths[i] + right_spacing;
x += left_spacing + e->widths[i] + right_spacing;
}
}
static void
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)
on_mouse(struct exposable *exposable, struct bar *bar,
enum mouse_event event, enum mouse_button btn, int x, int y)
{
const struct private *e = exposable->private;
@ -87,16 +86,17 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, e
return;
}
int px = /*p->left_margin;*/ 0;
int px = /*p->left_margin;*/0;
for (size_t i = 0; i < e->count; i++) {
if (x >= px && x < px + e->exposables[i]->width) {
if (e->exposables[i]->on_mouse != NULL) {
e->exposables[i]->on_mouse(e->exposables[i], bar, event, btn, x - px, y);
e->exposables[i]->on_mouse(
e->exposables[i], bar, event, btn, x - px, y);
}
return;
}
if (e->exposables[i]->width > 0)
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
}
LOG_DBG("on_mouse missed all sub-particles");
@ -104,7 +104,8 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, e
}
struct exposable *
dynlist_exposable_new(struct exposable **exposables, size_t count, int left_spacing, int right_spacing)
dynlist_exposable_new(struct exposable **exposables, size_t count,
int left_spacing, int right_spacing)
{
struct private *e = calloc(1, sizeof(*e));
e->count = count;

View file

@ -3,5 +3,5 @@
#include <stddef.h>
struct particle;
struct exposable *dynlist_exposable_new(struct exposable **exposables, size_t count, int left_spacing,
int right_spacing);
struct exposable *dynlist_exposable_new(
struct exposable **exposables, size_t count, int left_spacing, int right_spacing);

View file

@ -1,14 +1,15 @@
#include <stdlib.h>
#include "../config-verify.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particle.h"
#include "../plugin.h"
static int
begin_expose(struct exposable *exposable)
{
exposable->width = exposable->particle->left_margin + exposable->particle->right_margin;
exposable->width = exposable->particle->left_margin +
exposable->particle->right_margin;
return exposable->width;
}

View file

@ -2,14 +2,13 @@
#define LOG_MODULE "list"
#define LOG_ENABLE_DBG 0
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particle.h"
#include "../plugin.h"
struct private
{
struct private {
struct particle **particles;
size_t count;
int left_spacing, right_spacing;
@ -22,6 +21,7 @@ struct eprivate {
int left_spacing, right_spacing;
};
static void
exposable_destroy(struct exposable *exposable)
{
@ -80,18 +80,21 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
for (size_t i = 0; i < e->count; i++) {
const struct exposable *ee = e->exposables[i];
ee->expose(ee, pix, x + left_spacing, y, height);
if (e->widths[i] > 0)
x += left_spacing + e->widths[i] + right_spacing;
x += left_spacing + e->widths[i] + right_spacing;
}
}
static void
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)
on_mouse(struct exposable *exposable, struct bar *bar,
enum mouse_event event, enum mouse_button btn, int x, int y)
{
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
if ((event == ON_MOUSE_MOTION && exposable->particle->have_on_click_template) || exposable->on_click[btn] != NULL) {
if ((event == ON_MOUSE_MOTION &&
exposable->particle->have_on_click_template) ||
exposable->on_click[btn] != NULL)
{
/* We have our own handler */
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
@ -101,12 +104,13 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, e
for (size_t i = 0; i < e->count; i++) {
if (x >= px && x < px + e->exposables[i]->width) {
if (e->exposables[i]->on_mouse != NULL) {
e->exposables[i]->on_mouse(e->exposables[i], bar, event, btn, x - px, y);
e->exposables[i]->on_mouse(
e->exposables[i], bar, event, btn, x - px, y);
}
return;
}
if (e->exposables[i]->width > 0)
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
}
/* We're between sub-particles (or in the left/right margin) */
@ -152,8 +156,9 @@ particle_destroy(struct particle *particle)
}
struct particle *
particle_list_new(struct particle *common, struct particle *particles[], size_t count, int left_spacing,
int right_spacing)
particle_list_new(struct particle *common,
struct particle *particles[], size_t count,
int left_spacing, int right_spacing)
{
struct private *p = calloc(1, sizeof(*p));
p->particles = malloc(count * sizeof(p->particles[0]));
@ -178,20 +183,21 @@ from_conf(const struct yml_node *node, struct particle *common)
const struct yml_node *_left_spacing = yml_get_value(node, "left-spacing");
const struct yml_node *_right_spacing = yml_get_value(node, "right-spacing");
int left_spacing = spacing != NULL ? yml_value_as_int(spacing)
: _left_spacing != NULL ? yml_value_as_int(_left_spacing)
: 0;
int right_spacing = spacing != NULL ? yml_value_as_int(spacing)
: _right_spacing != NULL ? yml_value_as_int(_right_spacing)
: 2;
int left_spacing = spacing != NULL ? yml_value_as_int(spacing) :
_left_spacing != NULL ? yml_value_as_int(_left_spacing) : 0;
int right_spacing = spacing != NULL ? yml_value_as_int(spacing) :
_right_spacing != NULL ? yml_value_as_int(_right_spacing) : 2;
size_t count = yml_list_length(items);
struct particle *parts[count];
size_t idx = 0;
for (struct yml_list_iter it = yml_list_iter(items); it.node != NULL; yml_list_next(&it), idx++) {
parts[idx]
= conf_to_particle(it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground});
for (struct yml_list_iter it = yml_list_iter(items);
it.node != NULL;
yml_list_next(&it), idx++)
{
parts[idx] = conf_to_particle(
it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground});
}
return particle_list_new(common, parts, count, left_spacing, right_spacing);

View file

@ -1,93 +1,30 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#define LOG_MODULE "map"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particle.h"
#include "../plugin.h"
#include "dynlist.h"
#include "map.h"
// String globbing match.
// Note: Uses "non-greedy" implementation for "*" wildcard matching
static bool
string_like(const char* name, const char* pattern)
{
LOG_DBG("pattern:%s name:%s", pattern, name);
int px = 0, nx = 0;
int nextpx = 0, nextnx = 0;
while (px < strlen(pattern) || nx < strlen(name)) {
if (px < strlen(pattern)) {
char c = pattern[px];
switch (c) {
case '?': {
// single character
px++;
nx++;
continue;
}
case '*': {
// zero or more glob
nextpx=px;
nextnx=nx+1;
px++;
continue;
}
default: {
// normal character
if (nx < strlen(name) && name[nx] == c)
{
px++;
nx++;
continue;
}
}
}
}
// mismatch
if (0 < nextnx && nextnx <= strlen(name)) {
px = nextpx;
nx = nextnx;
continue;
}
return false;
}
LOG_DBG("map: name %s matched all the pattern %s", name, pattern);
// Matched all of pattern to all of name. Success.
return true;
}
static bool
int_condition(const long tag_value, const long cond_value, enum map_op op)
{
switch (op) {
case MAP_OP_EQ:
return tag_value == cond_value;
case MAP_OP_NE:
return tag_value != cond_value;
case MAP_OP_LE:
return tag_value <= cond_value;
case MAP_OP_LT:
return tag_value < cond_value;
case MAP_OP_GE:
return tag_value >= cond_value;
case MAP_OP_GT:
return tag_value > cond_value;
case MAP_OP_SELF:
LOG_WARN("using int tag as bool");
default:
return false;
case MAP_OP_EQ: return tag_value == cond_value;
case MAP_OP_NE: return tag_value != cond_value;
case MAP_OP_LE: return tag_value <= cond_value;
case MAP_OP_LT: return tag_value < cond_value;
case MAP_OP_GE: return tag_value >= cond_value;
case MAP_OP_GT: return tag_value > cond_value;
case MAP_OP_SELF: LOG_WARN("using int tag as bool");
default: return false;
}
}
@ -95,52 +32,34 @@ static bool
float_condition(const double tag_value, const double cond_value, enum map_op op)
{
switch (op) {
case MAP_OP_EQ:
return tag_value == cond_value;
case MAP_OP_NE:
return tag_value != cond_value;
case MAP_OP_LE:
return tag_value <= cond_value;
case MAP_OP_LT:
return tag_value < cond_value;
case MAP_OP_GE:
return tag_value >= cond_value;
case MAP_OP_GT:
return tag_value > cond_value;
case MAP_OP_SELF:
LOG_WARN("using float tag as bool");
default:
return false;
case MAP_OP_EQ: return tag_value == cond_value;
case MAP_OP_NE: return tag_value != cond_value;
case MAP_OP_LE: return tag_value <= cond_value;
case MAP_OP_LT: return tag_value < cond_value;
case MAP_OP_GE: return tag_value >= cond_value;
case MAP_OP_GT: return tag_value > cond_value;
case MAP_OP_SELF: LOG_WARN("using float tag as bool");
default: return false;
}
}
static bool
str_condition(const char *tag_value, const char *cond_value, enum map_op op)
str_condition(const char* tag_value, const char* cond_value, enum map_op op)
{
switch (op) {
case MAP_OP_EQ:
return strcmp(tag_value, cond_value) == 0;
case MAP_OP_NE:
return strcmp(tag_value, cond_value) != 0;
case MAP_OP_LE:
return strcmp(tag_value, cond_value) <= 0;
case MAP_OP_LT:
return strcmp(tag_value, cond_value) < 0;
case MAP_OP_GE:
return strcmp(tag_value, cond_value) >= 0;
case MAP_OP_GT:
return strcmp(tag_value, cond_value) > 0;
case MAP_OP_LIKE:
return string_like(tag_value, cond_value) != 0;
case MAP_OP_SELF:
LOG_WARN("using String tag as bool");
default:
return false;
case MAP_OP_EQ: return strcmp(tag_value, cond_value) == 0;
case MAP_OP_NE: return strcmp(tag_value, cond_value) != 0;
case MAP_OP_LE: return strcmp(tag_value, cond_value) <= 0;
case MAP_OP_LT: return strcmp(tag_value, cond_value) < 0;
case MAP_OP_GE: return strcmp(tag_value, cond_value) >= 0;
case MAP_OP_GT: return strcmp(tag_value, cond_value) > 0;
case MAP_OP_SELF: LOG_WARN("using String tag as bool");
default: return false;
}
}
static bool
eval_comparison(const struct map_condition *map_cond, const struct tag_set *tags)
eval_comparison(const struct map_condition* map_cond, const struct tag_set *tags)
{
const struct tag *tag = tag_for_name(tags, map_cond->tag);
if (tag == NULL) {
@ -189,7 +108,7 @@ eval_comparison(const struct map_condition *map_cond, const struct tag_set *tags
return false;
}
case TAG_TYPE_STRING: {
const char *tag_value = tag->as_string(tag);
const char* tag_value = tag->as_string(tag);
return str_condition(tag_value, map_cond->value, map_cond->op);
}
}
@ -197,17 +116,19 @@ eval_comparison(const struct map_condition *map_cond, const struct tag_set *tags
}
static bool
eval_map_condition(const struct map_condition *map_cond, const struct tag_set *tags)
eval_map_condition(const struct map_condition* map_cond, const struct tag_set *tags)
{
switch (map_cond->op) {
switch(map_cond->op) {
case MAP_OP_NOT:
return !eval_map_condition(map_cond->cond1, tags);
case MAP_OP_AND:
return eval_map_condition(map_cond->cond1, tags) && eval_map_condition(map_cond->cond2, tags);
return eval_map_condition(map_cond->cond1, tags) &&
eval_map_condition(map_cond->cond2, tags);
case MAP_OP_OR:
return eval_map_condition(map_cond->cond1, tags) || eval_map_condition(map_cond->cond2, tags);
return eval_map_condition(map_cond->cond1, tags) ||
eval_map_condition(map_cond->cond2, tags);
default:
return eval_comparison(map_cond, tags);
@ -215,28 +136,28 @@ eval_map_condition(const struct map_condition *map_cond, const struct tag_set *t
}
void
free_map_condition(struct map_condition *c)
free_map_condition(struct map_condition* c)
{
switch (c->op) {
case MAP_OP_EQ:
case MAP_OP_NE:
case MAP_OP_LE:
case MAP_OP_LT:
case MAP_OP_GE:
case MAP_OP_LIKE:
case MAP_OP_GT:
free(c->value);
/* FALLTHROUGH */
case MAP_OP_SELF:
free(c->tag);
break;
case MAP_OP_AND:
case MAP_OP_OR:
free_map_condition(c->cond2);
/* FALLTHROUGH */
case MAP_OP_NOT:
free_map_condition(c->cond1);
break;
switch (c->op)
{
case MAP_OP_EQ:
case MAP_OP_NE:
case MAP_OP_LE:
case MAP_OP_LT:
case MAP_OP_GE:
case MAP_OP_GT:
free(c->value);
/* FALLTHROUGH */
case MAP_OP_SELF:
free(c->tag);
break;
case MAP_OP_AND:
case MAP_OP_OR:
free_map_condition(c->cond2);
/* FALLTHROUGH */
case MAP_OP_NOT:
free_map_condition(c->cond1);
break;
}
free(c);
}
@ -246,8 +167,7 @@ struct particle_map {
struct particle *particle;
};
struct private
{
struct private {
struct particle *default_particle;
struct particle_map *map;
size_t count;
@ -288,16 +208,21 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
struct eprivate *e = exposable->private;
exposable_render_deco(exposable, pix, x, y, height);
e->exposable->expose(e->exposable, pix, x + exposable->particle->left_margin, y, height);
e->exposable->expose(
e->exposable, pix, x + exposable->particle->left_margin, y, height);
}
static void
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y)
{
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
if ((event == ON_MOUSE_MOTION && exposable->particle->have_on_click_template) || exposable->on_click[btn] != NULL) {
if ((event == ON_MOUSE_MOTION &&
exposable->particle->have_on_click_template) ||
exposable->on_click[btn] != NULL)
{
/* We have our own handler */
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
@ -370,8 +295,8 @@ particle_destroy(struct particle *particle)
}
static struct particle *
map_new(struct particle *common, const struct particle_map particle_map[], size_t count,
struct particle *default_particle)
map_new(struct particle *common, const struct particle_map particle_map[],
size_t count, struct particle *default_particle)
{
struct private *priv = calloc(1, sizeof(*priv));
priv->default_particle = default_particle;
@ -389,16 +314,22 @@ map_new(struct particle *common, const struct particle_map particle_map[], size_
return common;
}
static bool
verify_map_conditions(keychain_t *chain, const struct yml_node *node)
{
if (!yml_is_dict(node)) {
LOG_ERR("%s: must be a dictionary of workspace-name: particle mappings", conf_err_prefix(chain, node));
LOG_ERR(
"%s: must be a dictionary of workspace-name: particle mappings",
conf_err_prefix(chain, node));
return false;
}
bool result = true;
for (struct yml_dict_iter it = yml_dict_iter(node); it.key != NULL; yml_dict_next(&it)) {
for (struct yml_dict_iter it = yml_dict_iter(node);
it.key != NULL;
yml_dict_next(&it))
{
const char *key = yml_value_as_string(it.key);
if (key == NULL) {
LOG_ERR("%s: key must be a string", conf_err_prefix(chain, it.key));
@ -432,11 +363,17 @@ from_conf(const struct yml_node *node, struct particle *common)
struct particle_map particle_map[yml_dict_length(conditions)];
struct conf_inherit inherited
= {.font = common->font, .font_shaping = common->font_shaping, .foreground = common->foreground};
struct conf_inherit inherited = {
.font = common->font,
.font_shaping = common->font_shaping,
.foreground = common->foreground
};
size_t idx = 0;
for (struct yml_dict_iter it = yml_dict_iter(conditions); it.key != NULL; yml_dict_next(&it), idx++) {
for (struct yml_dict_iter it = yml_dict_iter(conditions);
it.key != NULL;
yml_dict_next(&it), idx++)
{
/* Note we can skip the error checking here */
char *key_clone = strdup(yml_value_as_string(it.key));
YY_BUFFER_STATE buffer = yy_scan_string(key_clone);
@ -447,7 +384,8 @@ from_conf(const struct yml_node *node, struct particle *common)
particle_map[idx].particle = conf_to_particle(it.value, inherited);
}
struct particle *default_particle = def != NULL ? conf_to_particle(def, inherited) : NULL;
struct particle *default_particle = def != NULL
? conf_to_particle(def, inherited) : NULL;
return map_new(common, particle_map, yml_dict_length(conditions), default_particle);
}

View file

@ -9,7 +9,6 @@ enum map_op {
MAP_OP_GT,
MAP_OP_SELF,
MAP_OP_NOT,
MAP_OP_LIKE,
MAP_OP_AND,
MAP_OP_OR,
@ -29,7 +28,7 @@ struct map_condition {
void free_map_condition(struct map_condition *c);
typedef struct yy_buffer_state *YY_BUFFER_STATE;
typedef struct yy_buffer_state* YY_BUFFER_STATE;
YY_BUFFER_STATE yy_scan_string(const char *str);
int yyparse();
void yy_delete_buffer(YY_BUFFER_STATE buffer);

View file

@ -2,74 +2,19 @@
#include <string.h>
#include "map.h"
#include "map.tab.h"
void yyerror(const char *s);
%}
%option warn nodefault nounput noinput noyywrap
char *quoted = NULL;
size_t quote_len = 0;
%x QUOTE
%%
[[:alnum:]_-]+ yylval.str = strdup(yytext); return WORD;
\" {
BEGIN(QUOTE);
quoted = calloc(1, sizeof(quoted[0]));
}
<QUOTE>[^\\\"]* {
/* printf("CAT: %s\n", yytext); */
const size_t yy_length = strlen(yytext);
quoted = realloc(quoted, quote_len + yy_length + 1);
strcat(quoted, yytext);
quote_len += yy_length;
}
<QUOTE>\\\" {
/* printf("escaped quote\n"); */
quoted = realloc(quoted, quote_len + 1 + 1);
strcat(quoted, "\"");
quote_len++;
}
<QUOTE>\\. {
/* printf("CAT: %s\n", yytext); */
const size_t yy_length = strlen(yytext);
quoted = realloc(quoted, quote_len + yy_length + 1);
strcat(quoted, yytext);
quote_len += yy_length;
}
<QUOTE>\\ {
/* quoted string that ends with a backslash: "string\ */
quoted = realloc(quoted, quote_len + 1 + 1);
strcat(quoted, "\\");
quote_len++;
}
<QUOTE>\" {
/* printf("QUOTED=%s\n", quoted); */
yylval.str = strdup(quoted);
free(quoted);
quoted = NULL;
quote_len = 0;
BEGIN(INITIAL);
return STRING;
}
\".*\" yylval.str = strndup(yytext + 1, strlen(yytext) - 2); return STRING;
== yylval.op = MAP_OP_EQ; return CMP_OP;
!= yylval.op = MAP_OP_NE; return CMP_OP;
\<= yylval.op = MAP_OP_LE; return CMP_OP;
\< yylval.op = MAP_OP_LT; return CMP_OP;
>= yylval.op = MAP_OP_GE; return CMP_OP;
> yylval.op = MAP_OP_GT; return CMP_OP;
~~ yylval.op = MAP_OP_LIKE; return CMP_OP;
&& yylval.op = MAP_OP_AND; return BOOL_OP;
\|\| yylval.op = MAP_OP_OR; return BOOL_OP;
~ return NOT;

View file

@ -35,27 +35,27 @@ result: condition { MAP_CONDITION_PARSE_RESULT = $<condition>1; };
condition:
WORD {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->tag = $<str>1;
$<condition>$->tag = $<str>1;
$<condition>$->op = MAP_OP_SELF;
}
|
WORD CMP_OP WORD {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->tag = $<str>1;
$<condition>$->tag = $<str>1;
$<condition>$->op = $<op>2;
$<condition>$->value = $<str>3;
$<condition>$->value = $<str>3;
}
|
WORD CMP_OP STRING {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->tag = $<str>1;
$<condition>$->tag = $<str>1;
$<condition>$->op = $<op>2;
$<condition>$->value = $<str>3;
$<condition>$->value = $<str>3;
}
|
L_PAR condition R_PAR { $<condition>$ = $<condition>2; }
|
NOT condition {
NOT condition {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->cond1 = $<condition>2;
$<condition>$->op = MAP_OP_NOT;
@ -79,7 +79,7 @@ static char const*
token_to_str(yysymbol_kind_t tkn)
{
switch (tkn) {
case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >, ~~";
case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >";
case YYSYMBOL_BOOL_OP: return "||, &&";
case YYSYMBOL_L_PAR: return "(";
case YYSYMBOL_R_PAR: return ")";

View file

@ -1,17 +1,16 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define LOG_MODULE "progress_bar"
#define LOG_ENABLE_DBG 0
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particle.h"
#include "../plugin.h"
struct private
{
struct private {
char *tag;
int width;
@ -75,7 +74,8 @@ begin_expose(struct exposable *exposable)
/* Margins */
if (have_at_least_one) {
exposable->width += exposable->particle->left_margin + exposable->particle->right_margin;
exposable->width += exposable->particle->left_margin +
exposable->particle->right_margin;
} else
assert(exposable->width == 0);
@ -97,7 +97,8 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
}
static void
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y)
{
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
@ -160,14 +161,18 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, e
original[i] = exposable->on_click[i];
if (event == ON_MOUSE_CLICK) {
long where = clickable_width > 0 ? 100 * (x - x_offset) / clickable_width : 0;
long where = clickable_width > 0
? 100 * (x - x_offset) / clickable_width
: 0;
struct tag_set tags = {
.tags = (struct tag *[]){tag_new_int(NULL, "where", where)},
.count = 1,
};
tags_expand_templates(exposable->on_click, (const char **)exposable->on_click, MOUSE_BTN_COUNT, &tags);
tags_expand_templates(
exposable->on_click, (const char **)exposable->on_click,
MOUSE_BTN_COUNT, &tags);
tag_set_destroy(&tags);
}
@ -193,17 +198,19 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
long min = tag != NULL ? tag->min(tag) : 0;
long max = tag != NULL ? tag->max(tag) : 0;
LOG_DBG("%s: value=%ld, min=%ld, max=%ld", tag != NULL ? tag->name(tag) : "<no tag>", value, min, max);
LOG_DBG("%s: value=%ld, min=%ld, max=%ld",
tag != NULL ? tag->name(tag) : "<no tag>", value, min, max);
long fill_count = max == min ? 0 : p->width * value / (max - min);
long empty_count = p->width - fill_count;
struct eprivate *epriv = calloc(1, sizeof(*epriv));
epriv->count = (1 + /* Start marker */
fill_count + /* Before current position */
1 + /* Current position indicator */
empty_count + /* After current position */
1); /* End marker */
epriv->count = (
1 + /* Start marker */
fill_count + /* Before current position */
1 + /* Current position indicator */
empty_count + /* After current position */
1); /* End marker */
epriv->exposables = malloc(epriv->count * sizeof(epriv->exposables[0]));
@ -252,7 +259,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
LOG_DBG("tag: %s, value: %ld, "
"units-per-segment: %f, units-filled: %f, units-til-next: %f",
tag->name(tag), value, units_per_segment, units_filled, units_til_next_segment);
tag->name(tag), value,
units_per_segment, units_filled, units_til_next_segment);
#endif
@ -263,8 +271,10 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
}
static struct particle *
progress_bar_new(struct particle *common, const char *tag, int width, struct particle *start_marker,
struct particle *end_marker, struct particle *fill, struct particle *empty, struct particle *indicator)
progress_bar_new(struct particle *common, const char *tag, int width,
struct particle *start_marker, struct particle *end_marker,
struct particle *fill, struct particle *empty,
struct particle *indicator)
{
struct private *priv = calloc(1, sizeof(*priv));
priv->tag = strdup(tag);
@ -298,10 +308,15 @@ from_conf(const struct yml_node *node, struct particle *common)
.foreground = common->foreground,
};
return progress_bar_new(common, yml_value_as_string(tag), yml_value_as_int(length),
conf_to_particle(start, inherited), conf_to_particle(end, inherited),
conf_to_particle(fill, inherited), conf_to_particle(empty, inherited),
conf_to_particle(indicator, inherited));
return progress_bar_new(
common,
yml_value_as_string(tag),
yml_value_as_int(length),
conf_to_particle(start, inherited),
conf_to_particle(end, inherited),
conf_to_particle(fill, inherited),
conf_to_particle(empty, inherited),
conf_to_particle(indicator, inherited));
}
static bool

View file

@ -1,19 +1,18 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#define LOG_MODULE "ramp"
#define LOG_ENABLE_DBG 0
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particle.h"
#include "../plugin.h"
struct private
{
struct private {
char *tag;
bool use_custom_min;
long min;
@ -58,16 +57,21 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
struct eprivate *e = exposable->private;
exposable_render_deco(exposable, pix, x, y, height);
e->exposable->expose(e->exposable, pix, x + exposable->particle->left_margin, y, height);
e->exposable->expose(
e->exposable, pix, x + exposable->particle->left_margin, y, height);
}
static void
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event, enum mouse_button btn, int x, int y)
on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
enum mouse_button btn, int x, int y)
{
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
if ((event == ON_MOUSE_MOTION && exposable->particle->have_on_click_template) || exposable->on_click[btn] != NULL) {
if ((event == ON_MOUSE_MOTION &&
exposable->particle->have_on_click_template) ||
exposable->on_click[btn] != NULL)
{
/* We have our own handler */
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
@ -114,22 +118,22 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
max = p->use_custom_max ? p->max : max;
if (min > max) {
LOG_WARN("tag's minimum value is greater than its maximum: "
"tag=\"%s\", min=%ld, max=%ld",
p->tag, min, max);
LOG_WARN(
"tag's minimum value is greater than its maximum: "
"tag=\"%s\", min=%ld, max=%ld", p->tag, min, max);
min = max;
}
if (value < min) {
LOG_WARN("tag's value is less than its minimum value: "
"tag=\"%s\", min=%ld, value=%ld",
p->tag, min, value);
LOG_WARN(
"tag's value is less than its minimum value: "
"tag=\"%s\", min=%ld, value=%ld", p->tag, min, value);
value = min;
}
if (value > max) {
LOG_WARN("tag's value is greater than its maximum value: "
"tag=\"%s\", max=%ld, value=%ld",
p->tag, max, value);
LOG_WARN(
"tag's value is greater than its maximum value: "
"tag=\"%s\", max=%ld, value=%ld", p->tag, max, value);
value = max;
}
@ -164,8 +168,10 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
}
static struct particle *
ramp_new(struct particle *common, const char *tag, struct particle *particles[], size_t count, bool use_custom_min,
long min, bool use_custom_max, long max)
ramp_new(struct particle *common, const char *tag,
struct particle *particles[], size_t count,
bool use_custom_min, long min,
bool use_custom_max, long max)
{
struct private *priv = calloc(1, sizeof(*priv));
@ -198,15 +204,19 @@ from_conf(const struct yml_node *node, struct particle *common)
struct particle *parts[count];
size_t idx = 0;
for (struct yml_list_iter it = yml_list_iter(items); it.node != NULL; yml_list_next(&it), idx++) {
parts[idx]
= conf_to_particle(it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground});
for (struct yml_list_iter it = yml_list_iter(items);
it.node != NULL;
yml_list_next(&it), idx++)
{
parts[idx] = conf_to_particle(
it.node, (struct conf_inherit){common->font, common->font_shaping, common->foreground});
}
long min_v = min != NULL ? yml_value_as_int(min) : 0;
long max_v = max != NULL ? yml_value_as_int(max) : 0;
return ramp_new(common, yml_value_as_string(tag), parts, count, min != NULL, min_v, max != NULL, max_v);
return ramp_new(common, yml_value_as_string(tag), parts, count, min != NULL,
min_v, max != NULL, max_v);
}
static bool

View file

@ -1,13 +1,13 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define LOG_MODULE "string"
#define LOG_ENABLE_DBG 0
#include "../char32.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../char32.h"
#include "../config.h"
#include "../config-verify.h"
#include "../particle.h"
#include "../plugin.h"
@ -18,8 +18,7 @@ struct text_run_cache {
bool in_use;
};
struct private
{
struct private {
char *text;
size_t max_len;
@ -52,7 +51,9 @@ begin_expose(struct exposable *exposable)
struct eprivate *e = exposable->private;
struct private *p = exposable->particle->private;
exposable->width = exposable->particle->left_margin + exposable->particle->right_margin;
exposable->width =
exposable->particle->left_margin +
exposable->particle->right_margin;
if (e->cache_idx >= 0) {
exposable->width += p->cache[e->cache_idx].width;
@ -96,8 +97,9 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
* any real facts, but works very well with e.g. the "Awesome 6"
* font family.
*/
const double baseline
= (double)y + (double)(height + font->ascent + font->descent) / 2.0 - (font->descent > 0 ? font->descent : 0);
const double baseline = (double)y +
(double)(height + font->ascent + font->descent) / 2.0 -
(font->descent > 0 ? font->descent : 0);
x += exposable->particle->left_margin;
@ -110,13 +112,17 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) {
/* Glyph surface is a pre-rendered image (typically a color emoji...) */
pixman_image_composite32(PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0, x + glyph->x,
baseline - glyph->y, glyph->width, glyph->height);
pixman_image_composite32(
PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0,
x + glyph->x, baseline - glyph->y,
glyph->width, glyph->height);
} else {
/* Glyph surface is an alpha mask */
pixman_image_t *src = pixman_image_create_solid_fill(&exposable->particle->foreground);
pixman_image_composite32(PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0, x + glyph->x,
baseline - glyph->y, glyph->width, glyph->height);
pixman_image_composite32(
PIXMAN_OP_OVER, src, glyph->pix, pix, 0, 0, 0, 0,
x + glyph->x, baseline - glyph->y,
glyph->width, glyph->height);
pixman_image_unref(src);
}
@ -174,16 +180,29 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
/* Truncate, if necessary */
if (p->max_len > 0 && chars > p->max_len) {
chars = p->max_len;
if (p->max_len > 3)
wtext[p->max_len - 1] = U'';
wtext[p->max_len] = U'\0';
size_t end = p->max_len;
if (end >= 1) {
/* "allocate" room for three dots at the end */
end -= 1;
}
if (p->max_len > 1) {
wtext[end] = U'';
wtext[end + 1] = U'\0';
chars = end + 1;
} else {
wtext[end] = U'\0';
chars = 0;
}
}
e->kern_x = calloc(chars, sizeof(e->kern_x[0]));
if (particle->font_shaping == FONT_SHAPE_FULL && fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING) {
struct fcft_text_run *run = fcft_rasterize_text_run_utf32(font, chars, wtext, FCFT_SUBPIXEL_NONE);
if (particle->font_shaping == FONT_SHAPE_FULL &&
fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING)
{
struct fcft_text_run *run = fcft_rasterize_text_run_utf32(
font, chars, wtext, FCFT_SUBPIXEL_NONE);
if (run != NULL) {
int w = 0;
@ -201,7 +220,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
if (cache_idx < 0) {
size_t new_size = p->cache_size + 1;
struct text_run_cache *new_cache = realloc(p->cache, new_size * sizeof(new_cache[0]));
struct text_run_cache *new_cache = realloc(
p->cache, new_size * sizeof(new_cache[0]));
p->cache_size = new_size;
p->cache = new_cache;
@ -225,7 +245,8 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
/* Convert text to glyph masks/images. */
for (size_t i = 0; i < chars; i++) {
const struct fcft_glyph *glyph = fcft_rasterize_char_utf32(font, wtext[i], FCFT_SUBPIXEL_NONE);
const struct fcft_glyph *glyph = fcft_rasterize_char_utf32(
font, wtext[i], FCFT_SUBPIXEL_NONE);
if (glyph == NULL)
continue;
@ -286,7 +307,10 @@ from_conf(const struct yml_node *node, struct particle *common)
const struct yml_node *text = yml_get_value(node, "text");
const struct yml_node *max = yml_get_value(node, "max");
return string_new(common, yml_value_as_string(text), max != NULL ? yml_value_as_int(max) : 0);
return string_new(
common,
yml_value_as_string(text),
max != NULL ? yml_value_as_int(max) : 0);
}
static bool

147
plugin.c
View file

@ -1,100 +1,99 @@
#include "plugin.h"
#include <dlfcn.h>
#include <string.h>
#include <dlfcn.h>
#include <tllist.h>
#define LOG_MODULE "plugin"
#define LOG_ENABLE_DBG 0
#include "config.h"
#include "log.h"
#include "config.h"
#if !defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
#define EXTERN_MODULE(plug_name) \
extern const struct module_iface module_##plug_name##_iface; \
extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \
extern struct module *plug_name##_from_conf(const struct yml_node *node, struct conf_inherit inherited);
#define EXTERN_MODULE(plug_name) \
extern const struct module_iface module_##plug_name##_iface; \
extern bool plug_name##_verify_conf( \
keychain_t *chain, const struct yml_node *node); \
extern struct module *plug_name##_from_conf( \
const struct yml_node *node, struct conf_inherit inherited);
#define EXTERN_PARTICLE(plug_name) \
extern const struct particle_iface particle_##plug_name##_iface; \
extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \
extern struct particle *plug_name##_from_conf(const struct yml_node *node, struct particle *common);
#define EXTERN_PARTICLE(plug_name) \
extern const struct particle_iface particle_##plug_name##_iface; \
extern bool plug_name##_verify_conf( \
keychain_t *chain, const struct yml_node *node); \
extern struct particle *plug_name##_from_conf( \
const struct yml_node *node, struct particle *common);
#define EXTERN_DECORATION(plug_name) \
extern const struct deco_iface deco_##plug_name##_iface; \
extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \
#define EXTERN_DECORATION(plug_name) \
extern const struct deco_iface deco_##plug_name##_iface; \
extern bool plug_name##_verify_conf( \
keychain_t *chain, const struct yml_node *node); \
extern struct deco *plug_name##_from_conf(const struct yml_node *node);
#if defined(HAVE_PLUGIN_alsa)
EXTERN_MODULE(alsa);
EXTERN_MODULE(alsa);
#endif
#if defined(HAVE_PLUGIN_backlight)
EXTERN_MODULE(backlight);
EXTERN_MODULE(backlight);
#endif
#if defined(HAVE_PLUGIN_battery)
EXTERN_MODULE(battery);
EXTERN_MODULE(battery);
#endif
#if defined(HAVE_PLUGIN_clock)
EXTERN_MODULE(clock);
EXTERN_MODULE(clock);
#endif
#if defined(HAVE_PLUGIN_cpu)
EXTERN_MODULE(cpu);
EXTERN_MODULE(cpu);
#endif
#if defined(HAVE_PLUGIN_disk_io)
EXTERN_MODULE(disk_io);
EXTERN_MODULE(disk_io);
#endif
#if defined(HAVE_PLUGIN_dwl)
EXTERN_MODULE(dwl);
EXTERN_MODULE(dwl);
#endif
#if defined(HAVE_PLUGIN_foreign_toplevel)
EXTERN_MODULE(foreign_toplevel);
EXTERN_MODULE(foreign_toplevel);
#endif
#if defined(HAVE_PLUGIN_mem)
EXTERN_MODULE(mem);
EXTERN_MODULE(mem);
#endif
#if defined(HAVE_PLUGIN_mpd)
EXTERN_MODULE(mpd);
EXTERN_MODULE(mpd);
#endif
#if defined(HAVE_PLUGIN_i3)
EXTERN_MODULE(i3);
EXTERN_MODULE(i3);
#endif
#if defined(HAVE_PLUGIN_label)
EXTERN_MODULE(label);
EXTERN_MODULE(label);
#endif
#if defined(HAVE_PLUGIN_network)
EXTERN_MODULE(network);
EXTERN_MODULE(network);
#endif
#if defined(HAVE_PLUGIN_pipewire)
EXTERN_MODULE(pipewire);
EXTERN_MODULE(pipewire);
#endif
#if defined(HAVE_PLUGIN_pulse)
EXTERN_MODULE(pulse);
EXTERN_MODULE(pulse);
#endif
#if defined(HAVE_PLUGIN_removables)
EXTERN_MODULE(removables);
EXTERN_MODULE(removables);
#endif
#if defined(HAVE_PLUGIN_river)
EXTERN_MODULE(river);
EXTERN_MODULE(river);
#endif
#if defined(HAVE_PLUGIN_script)
EXTERN_MODULE(script);
EXTERN_MODULE(script);
#endif
#if defined(HAVE_PLUGIN_sway_xkb)
EXTERN_MODULE(sway_xkb);
#endif
#if defined(HAVE_PLUGIN_niri_language)
EXTERN_MODULE(niri_language);
#endif
#if defined(HAVE_PLUGIN_niri_workspaces)
EXTERN_MODULE(niri_workspaces);
EXTERN_MODULE(sway_xkb);
#endif
#if defined(HAVE_PLUGIN_xkb)
EXTERN_MODULE(xkb);
EXTERN_MODULE(xkb);
#endif
#if defined(HAVE_PLUGIN_xwindow)
EXTERN_MODULE(xwindow);
EXTERN_MODULE(xwindow);
#endif
EXTERN_PARTICLE(empty);
@ -122,45 +121,41 @@ static const char *
type2str(enum plugin_type type)
{
switch (type) {
case PLUGIN_MODULE:
return "module";
case PLUGIN_PARTICLE:
return "particle";
case PLUGIN_DECORATION:
return "decoration";
case PLUGIN_MODULE: return "module";
case PLUGIN_PARTICLE: return "particle";
case PLUGIN_DECORATION: return "decoration";
}
assert(false && "invalid type");
return "";
return NULL;
}
static void __attribute__((constructor)) init(void)
static void __attribute__((constructor))
init(void)
{
#if !defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
#define REGISTER_CORE_PLUGIN(plug_name, func_prefix, plug_type) \
do { \
tll_push_back(plugins, ((struct plugin){ \
.name = strdup(#plug_name), \
.type = (plug_type), \
.lib = RTLD_DEFAULT, \
})); \
#define REGISTER_CORE_PLUGIN(plug_name, func_prefix, plug_type) \
do { \
tll_push_back( \
plugins, \
((struct plugin){ \
.name = strdup(#plug_name), \
.type = (plug_type), \
.lib = RTLD_DEFAULT, \
})); \
} while (0)
#define REGISTER_CORE_MODULE(plug_name, func_prefix) \
do { \
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_MODULE); \
tll_back(plugins).module = &module_##func_prefix##_iface; \
#define REGISTER_CORE_MODULE(plug_name, func_prefix) do { \
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_MODULE); \
tll_back(plugins).module = &module_##func_prefix##_iface; \
} while (0)
#define REGISTER_CORE_PARTICLE(plug_name, func_prefix) \
do { \
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_PARTICLE); \
tll_back(plugins).particle = &particle_##func_prefix##_iface; \
#define REGISTER_CORE_PARTICLE(plug_name, func_prefix) do { \
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_PARTICLE); \
tll_back(plugins).particle = &particle_##func_prefix##_iface; \
} while (0)
#define REGISTER_CORE_DECORATION(plug_name, func_prefix) \
do { \
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_DECORATION); \
tll_back(plugins).decoration = &deco_##func_prefix##_iface; \
#define REGISTER_CORE_DECORATION(plug_name, func_prefix) do { \
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_DECORATION); \
tll_back(plugins).decoration = &deco_##func_prefix##_iface; \
} while (0)
#if defined(HAVE_PLUGIN_alsa)
@ -220,12 +215,6 @@ static void __attribute__((constructor)) init(void)
#if defined(HAVE_PLUGIN_sway_xkb)
REGISTER_CORE_MODULE(sway-xkb, sway_xkb);
#endif
#if defined(HAVE_PLUGIN_niri_language)
REGISTER_CORE_MODULE(niri-language, niri_language);
#endif
#if defined(HAVE_PLUGIN_niri_workspaces)
REGISTER_CORE_MODULE(niri-workspaces, niri_workspaces);
#endif
#if defined(HAVE_PLUGIN_xkb)
REGISTER_CORE_MODULE(xkb, xkb);
#endif
@ -268,13 +257,16 @@ free_plugin(struct plugin plug)
free(plug.name);
}
static void __attribute__((destructor)) fini(void) { tll_free_and_free(plugins, free_plugin); }
static void __attribute__((destructor))
fini(void)
{
tll_free_and_free(plugins, free_plugin);
}
const struct plugin *
plugin_load(const char *name, enum plugin_type type)
{
tll_foreach(plugins, plug)
{
tll_foreach(plugins, plug) {
if (plug->item.type == type && strcmp(plug->item.name, name) == 0) {
LOG_DBG("%s: %s already loaded: %p", type2str(type), name, plug->item.lib);
assert(plug->item.dummy != NULL);
@ -282,6 +274,7 @@ plugin_load(const char *name, enum plugin_type type)
}
}
char path[128];
snprintf(path, sizeof(path), "%s_%s.so", type2str(type), name);

View file

@ -1,7 +1,7 @@
#pragma once
#include "config-verify.h"
#include "config.h"
#include "config-verify.h"
#include "module.h"
#include "particle.h"
@ -9,12 +9,14 @@ typedef bool (*verify_func_t)(keychain_t *chain, const struct yml_node *node);
struct module_iface {
verify_func_t verify_conf;
struct module *(*from_conf)(const struct yml_node *node, struct conf_inherit inherited);
struct module *(*from_conf)(
const struct yml_node *node, struct conf_inherit inherited);
};
struct particle_iface {
verify_func_t verify_conf;
struct particle *(*from_conf)(const struct yml_node *node, struct particle *common);
struct particle *(*from_conf)(
const struct yml_node *node, struct particle *common);
};
struct deco_iface {

181
tag.c
View file

@ -1,20 +1,19 @@
#include "tag.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include<errno.h>
#define LOG_MODULE "tag"
#define LOG_ENABLE_DBG 1
#include "log.h"
#include "module.h"
struct private
{
struct private {
char *name;
union {
struct {
@ -157,8 +156,8 @@ int_refresh_in(const struct tag *tag, long units)
if (tag->owner == NULL || tag->owner->refresh_in == NULL)
return false;
assert(priv->value_as_int.realtime_unit == TAG_REALTIME_SECS
|| priv->value_as_int.realtime_unit == TAG_REALTIME_MSECS);
assert(priv->value_as_int.realtime_unit == TAG_REALTIME_SECS ||
priv->value_as_int.realtime_unit == TAG_REALTIME_MSECS);
long milli_seconds = units;
if (priv->value_as_int.realtime_unit == TAG_REALTIME_SECS)
@ -270,14 +269,15 @@ tag_new_int(struct module *owner, const char *name, long value)
}
struct tag *
tag_new_int_range(struct module *owner, const char *name, long value, long min, long max)
tag_new_int_range(struct module *owner, const char *name, long value,
long min, long max)
{
return tag_new_int_realtime(owner, name, value, min, max, TAG_REALTIME_NONE);
}
struct tag *
tag_new_int_realtime(struct module *owner, const char *name, long value, long min, long max,
enum tag_realtime_unit unit)
tag_new_int_realtime(struct module *owner, const char *name, long value,
long min, long max, enum tag_realtime_unit unit)
{
struct private *priv = malloc(sizeof(*priv));
priv->name = strdup(name);
@ -414,7 +414,7 @@ sbuf_append_at_most(struct sbuf *s1, const char *s2, size_t n)
s1->size = 2 * required_size;
s1->s = realloc(s1->s, s1->size);
// s1->s[s1->len] = '\0';
//s1->s[s1->len] = '\0';
}
memcpy(&s1->s[s1->len], s2, n);
@ -430,12 +430,12 @@ sbuf_append(struct sbuf *s1, const char *s2)
// stores the number in "*value" on success
static bool
is_number(const char *str, long *value)
is_number(const char *str, int *value)
{
errno = 0;
char *end;
long v = strtol(str, &end, 10);
int v = strtol(str, &end, 10);
if (errno != 0 || *end != '\0')
return false;
@ -510,21 +510,23 @@ tags_expand_template(const char *template, const struct tag_set *tags)
FMT_HEX,
FMT_OCT,
FMT_PERCENT,
FMT_DIVIDE,
} format
= FMT_DEFAULT;
FMT_KBYTE,
FMT_MBYTE,
FMT_GBYTE,
FMT_KIBYTE,
FMT_MIBYTE,
FMT_GIBYTE,
} format = FMT_DEFAULT;
enum {
VALUE_VALUE,
VALUE_MIN,
VALUE_MAX,
VALUE_UNIT,
} kind
= VALUE_VALUE;
} kind = VALUE_VALUE;
long digits = 0;
long decimals = 2;
long divider = 1;
int digits = 0;
int decimals = 2;
bool zero_pad = false;
char *point = NULL;
@ -537,38 +539,18 @@ tags_expand_template(const char *template, const struct tag_set *tags)
format = FMT_OCT;
else if (strcmp(tag_args[i], "%") == 0)
format = FMT_PERCENT;
else if (*tag_args[i] == '/') {
format = FMT_DIVIDE;
const char *divider_str = tag_args[i] + 1;
if (!is_number(divider_str, &divider) || divider == 0) {
divider = 1;
LOG_WARN("tag `%s`: invalid divider %s, reset to 1", tag_name, divider_str);
}
}
else if (strcmp(tag_args[i], "kb") == 0) {
format = FMT_DIVIDE;
divider = 1000;
}
else if (strcmp(tag_args[i], "mb") == 0) {
format = FMT_DIVIDE;
divider = 1000 * 1000;
}
else if (strcmp(tag_args[i], "gb") == 0) {
format = FMT_DIVIDE;
divider = 1000 * 1000 * 1000;
}
else if (strcmp(tag_args[i], "kib") == 0) {
format = FMT_DIVIDE;
divider = 1024;
}
else if (strcmp(tag_args[i], "mib") == 0) {
format = FMT_DIVIDE;
divider = 1024 * 1024;
}
else if (strcmp(tag_args[i], "gib") == 0) {
format = FMT_DIVIDE;
divider = 1024 * 1024 * 1024;
}
else if (strcmp(tag_args[i], "kb") == 0)
format = FMT_KBYTE;
else if (strcmp(tag_args[i], "mb") == 0)
format = FMT_MBYTE;
else if (strcmp(tag_args[i], "gb") == 0)
format = FMT_GBYTE;
else if (strcmp(tag_args[i], "kib") == 0)
format = FMT_KIBYTE;
else if (strcmp(tag_args[i], "mib") == 0)
format = FMT_MIBYTE;
else if (strcmp(tag_args[i], "gib") == 0)
format = FMT_GIBYTE;
else if (strcmp(tag_args[i], "min") == 0)
kind = VALUE_MIN;
else if (strcmp(tag_args[i], "max") == 0)
@ -585,17 +567,22 @@ tags_expand_template(const char *template, const struct tag_set *tags)
if (digits_str[0] != '\0') { // guards against i.e. "{tag:.3}"
if (!is_number(digits_str, &digits)) {
LOG_WARN("tag `%s`: invalid field width formatter. Ignoring...", tag_name);
LOG_WARN(
"tag `%s`: invalid field width formatter. Ignoring...",
tag_name);
}
}
if (decimals_str[0] != '\0') { // guards against i.e. "{tag:3.}"
if (!is_number(decimals_str, &decimals)) {
LOG_WARN("tag `%s`: invalid decimals formatter. Ignoring...", tag_name);
LOG_WARN(
"tag `%s`: invalid decimals formatter. Ignoring...",
tag_name);
}
}
zero_pad = digits_str[0] == '0';
} else
}
else
LOG_WARN("invalid tag formatter: %s", tag_args[i]);
}
@ -606,7 +593,7 @@ tags_expand_template(const char *template, const struct tag_set *tags)
case FMT_DEFAULT: {
switch (tag->type(tag)) {
case TAG_TYPE_FLOAT: {
const char *fmt = zero_pad ? "%0*.*f" : "%*.*f";
const char* fmt = zero_pad ? "%0*.*f" : "%*.*f";
char str[24];
snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag));
sbuf_append(&formatted, str);
@ -614,7 +601,7 @@ tags_expand_template(const char *template, const struct tag_set *tags)
}
case TAG_TYPE_INT: {
const char *fmt = zero_pad ? "%0*ld" : "%*ld";
const char* fmt = zero_pad ? "%0*ld" : "%*ld";
char str[24];
snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag));
sbuf_append(&formatted, str);
@ -631,7 +618,9 @@ tags_expand_template(const char *template, const struct tag_set *tags)
case FMT_HEX:
case FMT_OCT: {
const char *fmt = format == FMT_HEX ? zero_pad ? "%0*lx" : "%*lx" : zero_pad ? "%0*lo" : "%*lo";
const char* fmt = format == FMT_HEX ?
zero_pad ? "%0*lx" : "%*lx" :
zero_pad ? "%0*lo" : "%*lo";
char str[24];
snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag));
sbuf_append(&formatted, str);
@ -643,20 +632,34 @@ tags_expand_template(const char *template, const struct tag_set *tags)
const long max = tag->max(tag);
const long cur = tag->as_int(tag);
const char *fmt = zero_pad ? "%0*lu" : "%*lu";
const char* fmt = zero_pad ? "%0*lu" : "%*lu";
char str[4];
snprintf(str, sizeof(str), fmt, digits, (cur - min) * 100 / (max - min));
sbuf_append(&formatted, str);
break;
}
case FMT_DIVIDE: {
case FMT_KBYTE:
case FMT_MBYTE:
case FMT_GBYTE:
case FMT_KIBYTE:
case FMT_MIBYTE:
case FMT_GIBYTE: {
const long divider =
format == FMT_KBYTE ? 1000 :
format == FMT_MBYTE ? 1000 * 1000 :
format == FMT_GBYTE ? 1000 * 1000 * 1000 :
format == FMT_KIBYTE ? 1024 :
format == FMT_MIBYTE ? 1024 * 1024 :
format == FMT_GIBYTE ? 1024 * 1024 * 1024 :
1;
char str[24];
if (tag->type(tag) == TAG_TYPE_FLOAT) {
const char *fmt = zero_pad ? "%0*.*f" : "%*.*f";
const char* fmt = zero_pad ? "%0*.*f" : "%*.*f";
snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag) / (double)divider);
} else {
const char *fmt = zero_pad ? "%0*lu" : "%*lu";
const char* fmt = zero_pad ? "%0*lu" : "%*lu";
snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag) / divider);
}
sbuf_append(&formatted, str);
@ -671,31 +674,36 @@ tags_expand_template(const char *template, const struct tag_set *tags)
const long max = tag->max(tag);
long value = kind == VALUE_MIN ? min : max;
const char *fmt = NULL;
const char *fmt;
switch (format) {
case FMT_DEFAULT:
fmt = zero_pad ? "%0*ld" : "%*ld";
break;
case FMT_HEX:
fmt = zero_pad ? "%0*lx" : "%*lx";
break;
case FMT_OCT:
fmt = zero_pad ? "%0*lo" : "%*lo";
break;
case FMT_DEFAULT: fmt = zero_pad ? "%0*ld" : "%*ld"; break;
case FMT_HEX: fmt = zero_pad ? "%0*lx" : "%*lx"; break;
case FMT_OCT: fmt = zero_pad ? "%0*lo" : "%*lo"; break;
case FMT_PERCENT:
value = (value - min) * 100 / (max - min);
fmt = zero_pad ? "%0*lu" : "%*lu";
break;
case FMT_DIVIDE: {
case FMT_KBYTE:
case FMT_MBYTE:
case FMT_GBYTE:
case FMT_KIBYTE:
case FMT_MIBYTE:
case FMT_GIBYTE: {
const long divider =
format == FMT_KBYTE ? 1024 :
format == FMT_MBYTE ? 1024 * 1024 :
format == FMT_GBYTE ? 1024 * 1024 * 1024 :
format == FMT_KIBYTE ? 1000 :
format == FMT_MIBYTE ? 1000 * 1000 :
format == FMT_GIBYTE ? 1000 * 1000 * 1000 :
1;
value /= divider;
fmt = zero_pad ? "%0*lu" : "%*lu";
break;
}
}
assert(fmt != NULL);
char str[24];
snprintf(str, sizeof(str), fmt, digits, value);
sbuf_append(&formatted, str);
@ -706,15 +714,9 @@ tags_expand_template(const char *template, const struct tag_set *tags)
const char *value = NULL;
switch (tag->realtime(tag)) {
case TAG_REALTIME_NONE:
value = "";
break;
case TAG_REALTIME_SECS:
value = "s";
break;
case TAG_REALTIME_MSECS:
value = "ms";
break;
case TAG_REALTIME_NONE: value = ""; break;
case TAG_REALTIME_SECS: value = "s"; break;
case TAG_REALTIME_MSECS: value = "ms"; break;
}
sbuf_append(&formatted, value);
@ -730,7 +732,8 @@ tags_expand_template(const char *template, const struct tag_set *tags)
}
void
tags_expand_templates(char *expanded[], const char *template[], size_t nmemb, const struct tag_set *tags)
tags_expand_templates(char *expanded[], const char *template[], size_t nmemb,
const struct tag_set *tags)
{
for (size_t i = 0; i < nmemb; i++)
expanded[i] = tags_expand_template(template[i], tags);

17
tag.h
View file

@ -1,7 +1,7 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdbool.h>
enum tag_type {
TAG_TYPE_BOOL,
@ -43,16 +43,21 @@ struct tag_set {
};
struct tag *tag_new_int(struct module *owner, const char *name, long value);
struct tag *tag_new_int_range(struct module *owner, const char *name, long value, long min, long max);
struct tag *tag_new_int_realtime(struct module *owner, const char *name, long value, long min, long max,
enum tag_realtime_unit unit);
struct tag *tag_new_int_range(
struct module *owner, const char *name, long value, long min, long max);
struct tag *tag_new_int_realtime(
struct module *owner, const char *name, long value, long min,
long max, enum tag_realtime_unit unit);
struct tag *tag_new_bool(struct module *owner, const char *name, bool value);
struct tag *tag_new_float(struct module *owner, const char *name, double value);
struct tag *tag_new_string(struct module *owner, const char *name, const char *value);
struct tag *tag_new_string(
struct module *owner, const char *name, const char *value);
const struct tag *tag_for_name(const struct tag_set *set, const char *name);
void tag_set_destroy(struct tag_set *set);
/* Utility functions */
char *tags_expand_template(const char *template, const struct tag_set *tags);
void tags_expand_templates(char *expanded[], const char *template[], size_t nmemb, const struct tag_set *tags);
void tags_expand_templates(
char *expanded[], const char *template[], size_t nmemb,
const struct tag_set *tags);

View file

@ -39,13 +39,8 @@ bar:
host: 127.0.0.1
content: {string: {text: "{state}"}}
- network:
content:
map:
default:
string: {text: "{name}: {state} ({ipv4})"}
conditions:
ipv4 == "":
string: {text: "{name}: {state}"}
name: ldsjfdf
content: {string: {text: "{name}"}}
- removables:
content: {string: {text: "{label}"}}
# - xkb:

Some files were not shown because too many files have changed in this diff Show more