forked from external/yambar
Compare commits
98 commits
releases/1
...
master
Author | SHA1 | Date | |
---|---|---|---|
80404504ed | |||
43c8316380 | |||
|
fc24ea225d | ||
|
e1f7c0292f | ||
|
d746d12f6a | ||
|
61d082c802 | ||
|
57711f0dbe | ||
|
b15714b38a | ||
|
3e0083c9f2 | ||
|
a367895dc6 | ||
|
650d1f13f9 | ||
|
e1b6a78f22 | ||
|
20d48a753b | ||
|
37ecc251a4 | ||
|
4826a52306 | ||
|
0f47cbb889 | ||
|
c3f7fe013d | ||
|
b81e41c3c4 | ||
|
060586dbbe | ||
|
c80bae7604 | ||
|
311c481bfe | ||
|
9498d7e445 | ||
|
2d651d1c0e | ||
|
1b2dee55ef | ||
|
700bf5b28c | ||
|
f8ba887dcd | ||
|
887e770202 | ||
|
54902f46ab | ||
|
699c563051 | ||
|
a5ae61b5df | ||
|
568eb1140f | ||
|
3e0a65f185 | ||
|
1a323c6d21 | ||
|
739dc30323 | ||
|
8422e7e0b1 | ||
|
9cc5e0f7a7 | ||
|
3431d5fc75 | ||
|
20659d3350 | ||
|
0bea49b75e | ||
|
70efd7d15c | ||
|
b8a93a2673 | ||
|
a467f56677 | ||
|
b3313cefc6 | ||
|
00234696fe | ||
|
3a7455913f | ||
|
547cef5afb | ||
|
6f3952819f | ||
|
f148c68736 | ||
|
a2d30b96fb | ||
|
cae07a36ff | ||
|
3136310ade | ||
|
be01eeb1de | ||
|
13f46a314a | ||
|
3c572c70c9 | ||
|
b85ba99980 | ||
|
d841aeeecd | ||
|
28a18ad91e | ||
|
da19c09122 | ||
|
58c397d154 | ||
|
53dec73ed2 | ||
|
c44c66c83f | ||
|
4e07b63cef | ||
|
c19a31d925 | ||
|
4066326614 | ||
|
424f22ab84 | ||
|
7a5cf26fb5 | ||
|
89ae7bd743 | ||
|
f2d25c8341 | ||
|
aeeef4f236 | ||
|
195ac5d1cd | ||
|
9d90848291 | ||
|
bbbf2b601e | ||
|
cb2561a72c | ||
|
8b1fa13686 | ||
|
bdc4fbe8e7 | ||
|
e1f78a16ab | ||
|
26bf62a899 | ||
|
cdee55afed | ||
|
9365580539 | ||
|
3a3a711b69 | ||
|
4d46f25854 | ||
|
a943def94e | ||
|
e54e8635e0 | ||
|
176ed4a6f3 | ||
|
d5823bcc4c | ||
|
1283160e17 | ||
|
60671da2ca | ||
![]() |
14550440dd | ||
|
89e74139f5 | ||
|
cbd3bebb04 | ||
|
7fbc1f2c44 | ||
|
9a111a52f5 | ||
|
78f7b60e13 | ||
|
9f5f35a8ac | ||
|
42cef9373e | ||
|
e1fc3a0e29 | ||
|
5db61745a4 | ||
|
4ba193ad0f |
103 changed files with 4100 additions and 3263 deletions
|
@ -3,6 +3,7 @@ BasedOnStyle: GNU
|
|||
IndentWidth: 4
|
||||
---
|
||||
Language: Cpp
|
||||
Standard: Auto
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 120
|
||||
BreakBeforeBraces: Custom
|
||||
|
@ -15,3 +16,9 @@ BraceWrapping:
|
|||
|
||||
SpaceBeforeParens: ControlStatements
|
||||
Cpp11BracedListStyle: true
|
||||
|
||||
WhitespaceSensitiveMacros:
|
||||
- REGISTER_CORE_PARTICLE
|
||||
- REGISTER_CORE_DECORATION
|
||||
- REGISTER_CORE_PLUGIN
|
||||
- REGISTER_CORE_MODULE
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
pipeline:
|
||||
codespell:
|
||||
steps:
|
||||
- name: codespell
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
- releases/*
|
||||
- event: [manual, pull_request]
|
||||
- event: [push, tag]
|
||||
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
|
||||
- codespell README.md CHANGELOG.md *.c *.h doc/*.scd bar decorations modules particles examples
|
||||
- deactivate
|
||||
|
||||
subprojects:
|
||||
- name: subprojects
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
- releases/*
|
||||
- event: [manual, pull_request]
|
||||
- event: [push, tag]
|
||||
branch: [master, releases/*]
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add git
|
||||
|
@ -24,12 +28,12 @@ pipeline:
|
|||
- git clone https://codeberg.org/dnkl/fcft.git
|
||||
- cd ..
|
||||
|
||||
x64:
|
||||
- name: x64
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
- releases/*
|
||||
group: build
|
||||
- event: [manual, pull_request]
|
||||
- event: [push, tag]
|
||||
branch: [master, releases/*]
|
||||
depends_on: [subprojects]
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk update
|
||||
|
@ -83,12 +87,12 @@ pipeline:
|
|||
- ./yambar --version
|
||||
- cd ../..
|
||||
|
||||
x86:
|
||||
- name: x86
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
- releases/*
|
||||
group: build
|
||||
- event: [manual, pull_request]
|
||||
- event: [push, tag]
|
||||
branch: [master, releases/*]
|
||||
depends_on: [subprojects]
|
||||
image: i386/alpine:latest
|
||||
commands:
|
||||
- apk add musl-dev eudev-libs eudev-dev linux-headers meson ninja gcc scdoc
|
122
CHANGELOG.md
122
CHANGELOG.md
|
@ -1,5 +1,7 @@
|
|||
# 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)
|
||||
|
@ -10,6 +12,126 @@
|
|||
* [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
|
||||
|
|
2
PKGBUILD
2
PKGBUILD
|
@ -1,5 +1,5 @@
|
|||
pkgname=yambar
|
||||
pkgver=1.10.0
|
||||
pkgver=1.11.0
|
||||
pkgrel=1
|
||||
pkgdesc="Simplistic and highly configurable status panel for X and Wayland"
|
||||
changelog=CHANGELOG.md
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pkgname=yambar-wayland
|
||||
pkgver=1.10.0
|
||||
pkgver=1.11.0
|
||||
pkgrel=1
|
||||
pkgdesc="Simplistic and highly configurable status panel for Wayland"
|
||||
arch=('x86_64' 'aarch64')
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Yambar
|
||||
|
||||
[](https://repology.org/project/yambar/versions)
|
||||
[](https://repology.org/project/yambar/versions)
|
||||
|
||||
|
||||
## Index
|
||||
|
@ -87,6 +87,7 @@ Available modules:
|
|||
* mem
|
||||
* mpd
|
||||
* network
|
||||
* pipewire
|
||||
* pulse
|
||||
* removables
|
||||
* river
|
||||
|
@ -106,7 +107,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 --buildtype=release ../..
|
||||
meson setup --buildtype=release ../..
|
||||
```
|
||||
|
||||
Optionally, explicitly disable a backend (or enable, if you want a
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
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);
|
||||
|
|
79
bar/bar.c
79
bar/bar.c
|
@ -1,15 +1,15 @@
|
|||
#include "bar.h"
|
||||
#include "private.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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <threads.h>
|
||||
#include <unistd.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/rigth groups.
|
||||
* Calculate total width of left/center/right groups.
|
||||
* Note: begin_expose() must have been called
|
||||
*/
|
||||
static void
|
||||
|
@ -75,9 +75,8 @@ 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,
|
||||
|
@ -86,20 +85,15 @@ 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++) {
|
||||
|
@ -136,12 +130,8 @@ 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);
|
||||
|
@ -161,11 +151,7 @@ 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];
|
||||
|
@ -177,7 +163,6 @@ expose(const struct bar *_bar)
|
|||
bar->backend.iface->commit(_bar);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
refresh(const struct bar *bar)
|
||||
{
|
||||
|
@ -200,15 +185,12 @@ 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;
|
||||
}
|
||||
|
@ -250,10 +232,7 @@ on_mouse(struct bar *_bar, enum mouse_event event, enum mouse_button btn,
|
|||
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];
|
||||
|
@ -294,8 +273,7 @@ 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);
|
||||
|
@ -347,8 +325,7 @@ 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;
|
||||
}
|
||||
|
@ -356,8 +333,7 @@ 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;
|
||||
}
|
||||
|
@ -365,8 +341,7 @@ 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;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ struct bar {
|
|||
};
|
||||
|
||||
enum bar_location { BAR_TOP, BAR_BOTTOM };
|
||||
enum bar_layer { BAR_LAYER_TOP, BAR_LAYER_BOTTOM };
|
||||
enum bar_layer { BAR_LAYER_OVERLAY, BAR_LAYER_TOP, BAR_LAYER_BOTTOM, BAR_LAYER_BACKGROUND };
|
||||
enum bar_backend { BAR_BACKEND_AUTO, BAR_BACKEND_XCB, BAR_BACKEND_WAYLAND };
|
||||
|
||||
struct bar_config {
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
#include "../bar/bar.h"
|
||||
#include "backend.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
/* From bar_config */
|
||||
char *monitor;
|
||||
enum bar_layer layer;
|
||||
|
|
435
bar/wayland.c
435
bar/wayland.c
|
@ -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 <xdg-output-unstable-v1.h>
|
||||
#include <wlr-layer-shell-unstable-v1.h>
|
||||
#include <xdg-output-unstable-v1.h>
|
||||
|
||||
#define LOG_MODULE "bar:wayland"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
|
@ -28,6 +28,10 @@
|
|||
|
||||
#include "private.h"
|
||||
|
||||
#if !defined(MFD_NOEXEC_SEAL)
|
||||
#define MFD_NOEXEC_SEAL 0
|
||||
#endif
|
||||
|
||||
struct buffer {
|
||||
bool busy;
|
||||
size_t width;
|
||||
|
@ -112,16 +116,15 @@ 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
|
||||
|
@ -153,7 +156,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 = {
|
||||
|
@ -163,10 +166,7 @@ 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,17 +175,12 @@ 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);
|
||||
|
@ -215,11 +210,9 @@ 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);
|
||||
|
@ -231,8 +224,7 @@ 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;
|
||||
|
@ -248,8 +240,7 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -261,8 +252,7 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -271,14 +261,12 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
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;
|
||||
|
@ -289,23 +277,31 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|||
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;
|
||||
|
@ -321,24 +317,18 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -352,14 +342,12 @@ 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;
|
||||
|
@ -370,8 +358,7 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -380,16 +367,12 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,16 +389,14 @@ 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);
|
||||
|
@ -455,10 +436,8 @@ 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;
|
||||
|
@ -466,19 +445,29 @@ output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y,
|
|||
}
|
||||
|
||||
static void
|
||||
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)
|
||||
output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -487,14 +476,6 @@ 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)
|
||||
|
@ -509,8 +490,7 @@ 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
|
||||
|
@ -529,9 +509,7 @@ 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;
|
||||
|
@ -539,8 +517,7 @@ xdg_output_handle_logical_position(void *data,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -555,9 +532,8 @@ 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;
|
||||
|
@ -569,15 +545,11 @@ 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);
|
||||
|
@ -599,8 +571,7 @@ 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);
|
||||
|
@ -608,8 +579,7 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -627,14 +597,12 @@ 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;
|
||||
|
@ -644,8 +612,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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) {
|
||||
|
@ -653,8 +620,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -663,13 +629,9 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
|
@ -682,8 +644,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -694,8 +655,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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) {
|
||||
|
@ -703,12 +663,10 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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));
|
||||
}
|
||||
|
@ -718,8 +676,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -728,7 +685,8 @@ 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;
|
||||
|
@ -738,8 +696,10 @@ 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);
|
||||
|
||||
|
@ -752,6 +712,7 @@ 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);
|
||||
|
@ -763,8 +724,7 @@ 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;
|
||||
|
@ -807,33 +767,43 @@ create_surface(struct wayland_backend *backend)
|
|||
|
||||
wl_surface_add_listener(backend->surface, &surface_listener, backend);
|
||||
|
||||
enum zwlr_layer_shell_v1_layer layer = bar->layer == BAR_LAYER_BOTTOM
|
||||
? ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM
|
||||
: ZWLR_LAYER_SHELL_V1_LAYER_TOP;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -866,7 +836,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;
|
||||
|
@ -879,7 +849,8 @@ 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;
|
||||
|
@ -907,7 +878,16 @@ get_buffer(struct wayland_backend *backend)
|
|||
|
||||
/* Backing memory for SHM */
|
||||
#if defined(MEMFD_CREATE)
|
||||
pool_fd = memfd_create("yambar-wayland-shm-buffer-pool", MFD_CLOEXEC);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
#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);
|
||||
|
@ -922,8 +902,7 @@ 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) {
|
||||
|
@ -937,43 +916,50 @@ 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);
|
||||
|
@ -1003,7 +989,8 @@ 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) {
|
||||
|
@ -1031,9 +1018,6 @@ 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;
|
||||
|
@ -1042,29 +1026,21 @@ 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;
|
||||
}
|
||||
|
@ -1134,8 +1110,7 @@ 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");
|
||||
|
@ -1157,7 +1132,8 @@ 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);
|
||||
|
||||
|
@ -1172,13 +1148,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)
|
||||
|
@ -1203,14 +1179,11 @@ 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;
|
||||
|
@ -1297,22 +1270,23 @@ 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;
|
||||
|
||||
tll_foreach(backend->monitors, it) {
|
||||
free(backend->last_mapped_monitor);
|
||||
backend->last_mapped_monitor = NULL;
|
||||
|
||||
tll_foreach(backend->monitors, it)
|
||||
{
|
||||
struct monitor *mon = &it->item;
|
||||
|
||||
if (mon->output != wl_output)
|
||||
|
@ -1332,8 +1306,7 @@ surface_enter(void *data, struct wl_surface *wl_surface,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -1352,8 +1325,7 @@ 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,
|
||||
|
@ -1362,7 +1334,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;
|
||||
|
||||
|
@ -1389,7 +1361,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
|
||||
|
@ -1398,7 +1370,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;
|
||||
|
@ -1407,7 +1379,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;
|
||||
|
@ -1416,7 +1388,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);
|
||||
|
||||
|
@ -1444,9 +1416,7 @@ 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");
|
||||
}
|
||||
}
|
||||
|
@ -1466,8 +1436,7 @@ 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
210
bar/xcb.c
|
@ -1,16 +1,16 @@
|
|||
#include "xcb.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <string.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,7 +39,6 @@ struct xcb_backend {
|
|||
void *client_pixmap;
|
||||
size_t client_pixmap_size;
|
||||
pixman_image_t *pix;
|
||||
|
||||
};
|
||||
|
||||
void *
|
||||
|
@ -55,11 +54,8 @@ 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");
|
||||
}
|
||||
|
||||
|
@ -76,10 +72,8 @@ 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));
|
||||
|
@ -90,17 +84,13 @@ 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) {
|
||||
|
@ -111,14 +101,11 @@ setup(struct bar *_bar)
|
|||
backend->x = mon->x;
|
||||
backend->y = mon->y;
|
||||
bar->width = mon->width;
|
||||
backend->y += bar->location == BAR_TOP ? 0
|
||||
: screen->height_in_pixels - bar->height_with_border;
|
||||
backend->y += bar->location == BAR_TOP ? 0 : mon->height - 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;
|
||||
|
@ -155,61 +142,34 @@ 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];
|
||||
|
@ -232,42 +192,38 @@ 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);
|
||||
|
@ -310,10 +266,8 @@ 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;
|
||||
|
@ -323,10 +277,7 @@ loop(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);
|
||||
|
||||
|
@ -335,18 +286,14 @@ loop(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));
|
||||
|
@ -369,9 +316,12 @@ loop(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;
|
||||
|
@ -405,10 +355,9 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -420,23 +369,19 @@ refresh(const struct bar *_bar)
|
|||
|
||||
/* Send an event to handle refresh from main thread */
|
||||
|
||||
/* Note: docs say that all X11 events are 32 bytes, reglardless of
|
||||
/* Note: docs say that all X11 events are 32 bytes, regardless 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);
|
||||
|
@ -458,8 +403,7 @@ 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 *
|
||||
|
|
15
char32.c
15
char32.c
|
@ -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,14 +24,13 @@
|
|||
* - 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
|
||||
|
|
2
char32.h
2
char32.h
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <uchar.h>
|
||||
#include <stddef.h>
|
||||
#include <uchar.h>
|
||||
|
||||
size_t c32len(const char32_t *s);
|
||||
char32_t *ambstoc32(const char *src);
|
||||
|
|
|
@ -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 (info)]:loglevel:(info warning error none)' \
|
||||
'(-d --log-level)'{-d,--log-level}'[log level (warning)]: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]'
|
||||
|
|
113
config-verify.c
113
config-verify.c
|
@ -1,7 +1,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <tllist.h>
|
||||
|
||||
|
@ -16,11 +16,9 @@ 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';
|
||||
|
@ -45,8 +43,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -56,8 +53,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -67,8 +63,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -81,10 +76,7 @@ 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;
|
||||
}
|
||||
|
@ -93,8 +85,7 @@ 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) {
|
||||
|
@ -115,8 +106,7 @@ conf_verify_enum(keychain_t *chain, const struct yml_node *node,
|
|||
}
|
||||
|
||||
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));
|
||||
|
@ -131,10 +121,7 @@ conf_verify_dict(keychain_t *chain, const struct yml_node *node,
|
|||
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));
|
||||
|
@ -190,8 +177,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -208,14 +194,10 @@ 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);
|
||||
|
@ -234,21 +216,18 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -258,8 +237,7 @@ 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
|
||||
|
@ -269,7 +247,8 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -285,8 +264,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -303,10 +281,7 @@ 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;
|
||||
}
|
||||
|
@ -321,7 +296,8 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -331,15 +307,13 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -361,19 +335,18 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -389,8 +362,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -412,10 +384,7 @@ 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;
|
||||
}
|
||||
|
@ -427,18 +396,12 @@ 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);
|
||||
|
@ -453,7 +416,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 *[]){"top", "bottom"}, 2);
|
||||
return conf_verify_enum(chain, node, (const char *[]){"overlay", "top", "bottom", "background"}, 4);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -26,17 +26,14 @@ 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
119
config.c
|
@ -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,9 +21,7 @@
|
|||
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';
|
||||
|
@ -57,9 +55,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,
|
||||
};
|
||||
}
|
||||
|
@ -74,10 +72,7 @@ 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++;
|
||||
|
@ -112,9 +107,7 @@ 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");
|
||||
}
|
||||
|
@ -124,9 +117,7 @@ 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");
|
||||
}
|
||||
|
@ -154,25 +145,20 @@ 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);
|
||||
|
@ -181,9 +167,8 @@ particle_simple_list_from_config(const struct yml_node *node,
|
|||
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);
|
||||
}
|
||||
|
@ -206,10 +191,8 @@ 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) {
|
||||
|
@ -234,10 +217,7 @@ 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);
|
||||
|
||||
|
@ -286,16 +266,14 @@ 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);
|
||||
|
||||
|
@ -323,8 +301,7 @@ 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);
|
||||
|
@ -340,15 +317,18 @@ 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, "top") == 0)
|
||||
if (strcmp(tmp, "overlay") == 0)
|
||||
conf.layer = BAR_LAYER_OVERLAY;
|
||||
else 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);
|
||||
|
@ -373,11 +353,8 @@ 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) {
|
||||
|
@ -394,10 +371,8 @@ 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);
|
||||
|
@ -412,10 +387,8 @@ 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);
|
||||
|
@ -470,10 +443,7 @@ 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);
|
||||
|
||||
|
@ -485,16 +455,13 @@ 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);
|
||||
|
|
7
config.h
7
config.h
|
@ -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,6 +25,5 @@ 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);
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
|
||||
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 \
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../decoration.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
//struct rgba color;
|
||||
struct private
|
||||
{
|
||||
// struct rgba color;
|
||||
pixman_color_t color;
|
||||
};
|
||||
|
||||
|
@ -22,9 +23,7 @@ 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 *
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../decoration.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
|
@ -12,7 +12,8 @@
|
|||
#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;
|
||||
};
|
||||
|
@ -29,21 +30,20 @@ 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,9 +66,7 @@ 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
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../decoration.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
int size;
|
||||
pixman_color_t color;
|
||||
};
|
||||
|
@ -22,9 +23,7 @@ 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 *
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#define LOG_MODULE "stack"
|
||||
#include "../log.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../decoration.h"
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct deco **decos;
|
||||
size_t count;
|
||||
};
|
||||
|
@ -57,10 +58,7 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -75,10 +73,7 @@ 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;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../decoration.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
int size;
|
||||
pixman_color_t color;
|
||||
};
|
||||
|
@ -22,9 +23,8 @@ 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 *
|
||||
|
|
|
@ -36,6 +36,7 @@ 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']
|
||||
|
@ -43,6 +44,12 @@ 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
|
||||
|
|
|
@ -137,7 +137,7 @@ content:
|
|||
|
||||
# STACK
|
||||
|
||||
This particles combines multiple decorations.
|
||||
This particle combines multiple decorations.
|
||||
|
||||
## CONFIGURATION
|
||||
|
||||
|
|
|
@ -61,6 +61,16 @@ 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -26,6 +26,9 @@ 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)
|
||||
|
|
|
@ -20,6 +20,9 @@ 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
|
||||
|
|
|
@ -6,11 +6,12 @@ network - This module monitors network connection state
|
|||
# DESCRIPTION
|
||||
|
||||
This module monitors network connection state; disconnected/connected
|
||||
state and MAC/IP addresses.
|
||||
state and MAC/IP addresses. It instantiates the provided _content_
|
||||
particle for each network interface.
|
||||
|
||||
Note: while the module internally tracks all assigned IPv4/IPv6
|
||||
addresses, it currently exposes only a single IPv4 and a single IPv6
|
||||
address.
|
||||
address per network interface.
|
||||
|
||||
# TAGS
|
||||
|
||||
|
@ -20,6 +21,16 @@ address.
|
|||
| 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
|
||||
|
@ -45,6 +56,9 @@ address.
|
|||
| 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
|
||||
|
@ -65,27 +79,45 @@ address.
|
|||
:[ *Type*
|
||||
:[ *Req*
|
||||
:< *Description*
|
||||
| name
|
||||
: string
|
||||
: yes
|
||||
: Name of network interface to monitor
|
||||
| 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_
|
||||
| poll-interval
|
||||
: int
|
||||
: no
|
||||
: Periodically (in milliseconds) update the signal, rx+tx bitrate, and
|
||||
ul+dl speed tags. Setting it to 0 disables updates. Cannot be less
|
||||
: 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
|
||||
than 250ms.
|
||||
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
Display all Ethernet (including WLAN) devices. This excludes loopback,
|
||||
bridges etc.
|
||||
|
||||
```
|
||||
bar:
|
||||
left:
|
||||
- network:
|
||||
name: wlp3s0
|
||||
content:
|
||||
string: {text: "{name}: {state} ({ipv4})"}
|
||||
map:
|
||||
conditions:
|
||||
type == ether || type == wlan:
|
||||
map:
|
||||
default:
|
||||
string: {text: "{name}: {state} ({ipv4})"}
|
||||
conditions:
|
||||
ipv4 == "":
|
||||
string: {text: "{name}: {state}"}
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
|
34
doc/yambar-modules-niri-language.5.scd
Normal file
34
doc/yambar-modules-niri-language.5.scd
Normal file
|
@ -0,0 +1,34 @@
|
|||
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)
|
||||
|
60
doc/yambar-modules-niri-workspaces.5.scd
Normal file
60
doc/yambar-modules-niri-workspaces.5.scd
Normal file
|
@ -0,0 +1,60 @@
|
|||
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)
|
||||
|
|
@ -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,8 +39,16 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change
|
|||
|
||||
# CONFIGURATION
|
||||
|
||||
No additional attributes supported, only the generic ones (see
|
||||
*GENERIC CONFIGURATION* in *yambar-modules*(5))
|
||||
[[ *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'.
|
||||
|
||||
|
||||
# EXAMPLES
|
||||
|
|
|
@ -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 depends
|
||||
is received. This mode is intended to be used by scripts that depend
|
||||
on non-polling methods to update their state.
|
||||
|
||||
Tag sets, or _transactions_, are separated by an empty line
|
||||
|
|
|
@ -142,14 +142,26 @@ 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)
|
||||
|
@ -162,6 +174,10 @@ 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)
|
||||
|
|
|
@ -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 ay other particle
|
||||
different font and/or color formatting. Or any other particle
|
||||
combinations.
|
||||
|
||||
But note that this means you *cannot* set any attributes on the _list_
|
||||
|
@ -214,6 +214,11 @@ 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
|
||||
|
@ -260,6 +265,26 @@ 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:
|
||||
|
||||
[- &&
|
||||
|
@ -451,7 +476,7 @@ itself when needed.
|
|||
|
||||
```
|
||||
content:
|
||||
progres-bar:
|
||||
progress-bar:
|
||||
tag: tag_name
|
||||
length: 20
|
||||
start: {string: {text: ├}}
|
||||
|
|
|
@ -86,11 +86,15 @@ 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
|
||||
|
|
|
@ -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 exit.
|
||||
as been specified, the file is unlinked upon exiting.
|
||||
|
||||
*-d*,*--log-level*={*info*,*warning*,*error*,*none*}
|
||||
Log level, used both for log output on stderr as well as
|
||||
syslog. Default: _info_.
|
||||
syslog. Default: _warning_.
|
||||
|
||||
*-l*,*--log-colorize*=[{*never*,*always*,*auto*}]
|
||||
Enables or disables colorization of log output on stderr.
|
||||
|
|
|
@ -23,6 +23,11 @@ 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*
|
||||
|
@ -49,7 +54,8 @@ types that are frequently used:
|
|||
| layer
|
||||
: string
|
||||
: no
|
||||
: Layer to put bar on. One of _top_ or _bottom_. Wayland only
|
||||
: Layer to put bar on. One of _overlay_, _top_, _bottom_ or
|
||||
_background_. Wayland only. Default: _bottom_.
|
||||
| left-spacing
|
||||
: int
|
||||
: no
|
||||
|
|
|
@ -169,34 +169,40 @@ bar:
|
|||
- string: {text: , font: *awesome}
|
||||
- string: {text: "{layout}"}
|
||||
- network:
|
||||
name: enp1s0
|
||||
content:
|
||||
map:
|
||||
default: {empty: {}}
|
||||
conditions:
|
||||
~carrier: {empty: {}}
|
||||
carrier:
|
||||
name == enp1s0:
|
||||
map:
|
||||
default: {string: {text: , font: *awesome, foreground: ffffff66}}
|
||||
conditions:
|
||||
state == up && ipv4 != "": {string: {text: , font: *awesome}}
|
||||
~carrier: {empty: {}}
|
||||
carrier:
|
||||
map:
|
||||
default: {string: {text: , font: *awesome, foreground: ffffff66}}
|
||||
conditions:
|
||||
state == up && ipv4 != "": {string: {text: , font: *awesome}}
|
||||
- network:
|
||||
name: wlp2s0
|
||||
poll-interval: 1000
|
||||
content:
|
||||
map:
|
||||
default: {string: {text: , font: *awesome, foreground: ffffff66}}
|
||||
default: {empty: {}}
|
||||
conditions:
|
||||
state == down: {string: {text: , font: *awesome, foreground: ff0000ff}}
|
||||
state == up:
|
||||
name == wlp2s0:
|
||||
map:
|
||||
default:
|
||||
- string: {text: , font: *awesome}
|
||||
- string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"}
|
||||
|
||||
default: {string: {text: , font: *awesome, foreground: ffffff66}}
|
||||
conditions:
|
||||
ipv4 == "":
|
||||
- string: {text: , font: *awesome, foreground: ffffff66}
|
||||
- string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66}
|
||||
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"}
|
||||
|
||||
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
|
||||
|
|
|
@ -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)))"
|
||||
|
|
69
examples/river-minimal.yml
Normal file
69
examples/river-minimal.yml
Normal file
|
@ -0,0 +1,69 @@
|
|||
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}"}
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# Now the fun part
|
||||
#
|
||||
# Exemple configuration:
|
||||
# Example configuration:
|
||||
#
|
||||
# - script:
|
||||
# path: /absolute/path/to/dwl-tags.sh
|
||||
|
@ -136,4 +136,3 @@ done
|
|||
|
||||
unset -v output title layout activetags selectedtags
|
||||
unset -v tags name
|
||||
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
# {aur} int number of aur packages
|
||||
# {pkg} int sum of both
|
||||
#
|
||||
# Exemples configuration:
|
||||
# Examples 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,4 +76,3 @@ done
|
|||
|
||||
unset -v interval aur_helper pacman_num aur_num pkg_num
|
||||
unset -f _err
|
||||
|
||||
|
|
51
log.c
51
log.c
|
@ -1,5 +1,6 @@
|
|||
#include "log.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -9,13 +10,12 @@
|
|||
#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 = true;
|
||||
static bool do_syslog = false;
|
||||
static enum log_class log_level = LOG_CLASS_NONE;
|
||||
|
||||
static const struct {
|
||||
|
@ -32,23 +32,28 @@ 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 : isatty(STDERR_FILENO);
|
||||
? false
|
||||
: _colorize == LOG_COLORIZE_ALWAYS
|
||||
? true
|
||||
: !no_color && 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));
|
||||
}
|
||||
}
|
||||
|
@ -61,8 +66,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));
|
||||
|
@ -92,9 +97,8 @@ _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));
|
||||
|
@ -102,6 +106,9 @@ _sys_log(enum log_class log_class, const char *module,
|
|||
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;
|
||||
|
||||
|
@ -116,8 +123,7 @@ _sys_log(enum log_class log_class, const char *module,
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -127,8 +133,7 @@ log_msg_va(enum log_class log_class, const char *module,
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -137,17 +142,13 @@ log_msg(enum log_class log_class, const char *module,
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -156,8 +157,7 @@ log_errno(enum log_class log_class, const char *module,
|
|||
}
|
||||
|
||||
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,8 +168,7 @@ log_errno_provided_va(enum log_class log_class, const char *module,
|
|||
}
|
||||
|
||||
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
71
log.h
|
@ -1,68 +1,43 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.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_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_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)));
|
||||
|
||||
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
61
main.c
|
@ -1,4 +1,6 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <locale.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
|
@ -9,14 +11,12 @@
|
|||
#include <string.h>
|
||||
#include <threads.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.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, "r");
|
||||
FILE *conf_file = fopen(config_path, "re");
|
||||
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 (info)\n"
|
||||
" -d,--log-level={info|warning|error|none} log level (warning)\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,9 +147,8 @@ 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
|
||||
|
@ -178,16 +177,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;
|
||||
|
@ -197,7 +196,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_INFO;
|
||||
enum log_class log_level = LOG_CLASS_WARNING;
|
||||
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
||||
bool log_syslog = true;
|
||||
|
||||
|
@ -223,9 +222,8 @@ 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)) {
|
||||
fprintf(stderr, "%s: invalid configuration file: not a regular file\n",
|
||||
optarg);
|
||||
} 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);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -244,11 +242,7 @@ 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;
|
||||
|
@ -292,12 +286,9 @@ 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};
|
||||
|
|
10
meson.build
10
meson.build
|
@ -1,5 +1,5 @@
|
|||
project('yambar', 'c',
|
||||
version: '1.10.0',
|
||||
version: '1.11.0',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.59.0',
|
||||
default_options: ['c_std=c18',
|
||||
|
@ -12,7 +12,9 @@ plugs_as_libs = get_option('core-plugins-as-shared-libraries')
|
|||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
if cc.has_function('memfd_create')
|
||||
if cc.has_function('memfd_create',
|
||||
args: ['-D_GNU_SOURCE=200809L'],
|
||||
prefix: '#include <sys/mman.h>')
|
||||
add_project_arguments('-DMEMFD_CREATE', language: 'c')
|
||||
endif
|
||||
|
||||
|
@ -174,7 +176,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,
|
||||
|
@ -187,6 +189,8 @@ 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,
|
||||
},
|
||||
|
|
|
@ -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,6 +44,10 @@ 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',
|
||||
|
|
2
module.c
2
module.c
|
@ -1,6 +1,6 @@
|
|||
#include "module.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct module *
|
||||
|
|
12
module.h
12
module.h
|
@ -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 \
|
||||
}
|
||||
|
|
223
modules/alsa.c
223
modules/alsa.c
|
@ -1,8 +1,8 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/time.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,7 +29,8 @@ struct channel {
|
|||
bool muted;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *card;
|
||||
char *mixer;
|
||||
char *volume_name;
|
||||
|
@ -70,7 +71,8 @@ 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);
|
||||
}
|
||||
|
@ -129,9 +131,7 @@ 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,9 +141,7 @@ 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 = {
|
||||
|
@ -173,107 +171,94 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -309,10 +294,8 @@ 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;
|
||||
|
@ -323,7 +306,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;
|
||||
|
@ -332,30 +315,24 @@ 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;
|
||||
|
@ -363,30 +340,24 @@ 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;
|
||||
|
@ -400,7 +371,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);
|
||||
}
|
||||
|
@ -413,13 +384,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));
|
||||
}
|
||||
|
||||
|
@ -429,7 +400,8 @@ 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;
|
||||
|
@ -462,26 +434,14 @@ 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);
|
||||
|
||||
|
@ -595,8 +555,7 @@ 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) {
|
||||
|
@ -638,7 +597,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) {
|
||||
|
@ -656,23 +615,20 @@ 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;
|
||||
|
@ -692,12 +648,9 @@ 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
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
#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 <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#define LOG_MODULE "backlight"
|
||||
#include "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *label;
|
||||
|
||||
char *device;
|
||||
|
@ -111,13 +112,13 @@ readint_from_fd(int fd)
|
|||
static int
|
||||
initialize(struct private *m)
|
||||
{
|
||||
int backlight_fd = open("/sys/class/backlight", O_RDONLY);
|
||||
int backlight_fd = open("/sys/class/backlight", O_RDONLY | O_CLOEXEC);
|
||||
if (backlight_fd == -1) {
|
||||
LOG_ERRNO("/sys/class/backlight");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int base_dir_fd = openat(backlight_fd, m->device, O_RDONLY);
|
||||
int base_dir_fd = openat(backlight_fd, m->device, O_RDONLY | O_CLOEXEC);
|
||||
close(backlight_fd);
|
||||
|
||||
if (base_dir_fd == -1) {
|
||||
|
@ -125,7 +126,7 @@ initialize(struct private *m)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int max_fd = openat(base_dir_fd, "max_brightness", O_RDONLY);
|
||||
int max_fd = openat(base_dir_fd, "max_brightness", O_RDONLY | O_CLOEXEC);
|
||||
if (max_fd == -1) {
|
||||
LOG_ERRNO("/sys/class/backlight/%s/max_brightness", m->device);
|
||||
close(base_dir_fd);
|
||||
|
@ -135,7 +136,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);
|
||||
int current_fd = openat(base_dir_fd, "brightness", O_RDONLY | O_CLOEXEC);
|
||||
close(base_dir_fd);
|
||||
|
||||
if (current_fd == -1) {
|
||||
|
@ -145,8 +146,7 @@ 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,8 +244,7 @@ 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
|
||||
|
|
|
@ -1,37 +1,49 @@
|
|||
#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 <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libudev.h>
|
||||
#include <tllist.h>
|
||||
|
||||
#define LOG_MODULE "battery"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "../log.h"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.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 private {
|
||||
struct current_state {
|
||||
long ema;
|
||||
long current;
|
||||
struct timespec time;
|
||||
};
|
||||
|
||||
struct private
|
||||
{
|
||||
struct particle *label;
|
||||
|
||||
long poll_interval;
|
||||
int battery_scale;
|
||||
long smoothing_scale;
|
||||
char *battery;
|
||||
char *manufacturer;
|
||||
char *model;
|
||||
|
@ -45,16 +57,53 @@ struct private {
|
|||
long energy;
|
||||
long power;
|
||||
long charge;
|
||||
long current;
|
||||
struct current_state ema_current;
|
||||
long time_to_empty;
|
||||
long time_to_full;
|
||||
};
|
||||
|
||||
static void
|
||||
timespec_sub(const struct timespec *a, const struct timespec *b,
|
||||
struct timespec *res)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
@ -96,11 +145,8 @@ 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;
|
||||
|
@ -113,9 +159,8 @@ 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)
|
||||
|
@ -127,15 +172,14 @@ 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->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->ema_current.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->current > 0)
|
||||
hours_as_float = (double)charge / m->current;
|
||||
else if (m->ema_current.current > 0)
|
||||
hours_as_float = (double)charge / m->ema_current.current;
|
||||
else
|
||||
hours_as_float = 99.0;
|
||||
|
||||
|
@ -215,13 +259,13 @@ initialize(struct private *m)
|
|||
{
|
||||
char line_buf[512];
|
||||
|
||||
int pw_fd = open("/sys/class/power_supply", O_RDONLY);
|
||||
int pw_fd = open("/sys/class/power_supply", O_RDONLY | O_CLOEXEC);
|
||||
if (pw_fd < 0) {
|
||||
LOG_ERRNO("/sys/class/power_supply");
|
||||
return false;
|
||||
}
|
||||
|
||||
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY);
|
||||
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY | O_CLOEXEC);
|
||||
close(pw_fd);
|
||||
|
||||
if (base_dir_fd < 0) {
|
||||
|
@ -230,10 +274,9 @@ initialize(struct private *m)
|
|||
}
|
||||
|
||||
{
|
||||
int fd = openat(base_dir_fd, "manufacturer", O_RDONLY);
|
||||
int fd = openat(base_dir_fd, "manufacturer", O_RDONLY | O_CLOEXEC);
|
||||
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));
|
||||
|
@ -242,10 +285,9 @@ initialize(struct private *m)
|
|||
}
|
||||
|
||||
{
|
||||
int fd = openat(base_dir_fd, "model_name", O_RDONLY);
|
||||
int fd = openat(base_dir_fd, "model_name", O_RDONLY | O_CLOEXEC);
|
||||
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));
|
||||
|
@ -253,11 +295,10 @@ 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);
|
||||
int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
LOG_ERRNO("/sys/class/power_supply/%s/energy_full_design", m->battery);
|
||||
goto err;
|
||||
|
@ -268,7 +309,7 @@ initialize(struct private *m)
|
|||
}
|
||||
|
||||
{
|
||||
int fd = openat(base_dir_fd, "energy_full", O_RDONLY);
|
||||
int fd = openat(base_dir_fd, "energy_full", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
LOG_ERRNO("/sys/class/power_supply/%s/energy_full", m->battery);
|
||||
goto err;
|
||||
|
@ -281,28 +322,27 @@ 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);
|
||||
int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY | O_CLOEXEC);
|
||||
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->charge_full_design = readint_from_fd(fd) / m->battery_scale;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
{
|
||||
int fd = openat(base_dir_fd, "charge_full", O_RDONLY);
|
||||
int fd = openat(base_dir_fd, "charge_full", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
LOG_ERRNO("/sys/class/power_supply/%s/charge_full", m->battery);
|
||||
goto err;
|
||||
}
|
||||
|
||||
m->charge_full = readint_from_fd(fd);
|
||||
m->charge_full = readint_from_fd(fd) / m->battery_scale;
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
|
@ -322,13 +362,13 @@ update_status(struct module *mod)
|
|||
{
|
||||
struct private *m = mod->private;
|
||||
|
||||
int pw_fd = open("/sys/class/power_supply", O_RDONLY);
|
||||
int pw_fd = open("/sys/class/power_supply", O_RDONLY | O_CLOEXEC);
|
||||
if (pw_fd < 0) {
|
||||
LOG_ERRNO("/sys/class/power_supply");
|
||||
return false;
|
||||
}
|
||||
|
||||
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY);
|
||||
int base_dir_fd = openat(pw_fd, m->battery, O_RDONLY | O_CLOEXEC);
|
||||
close(pw_fd);
|
||||
|
||||
if (base_dir_fd < 0) {
|
||||
|
@ -336,14 +376,14 @@ update_status(struct module *mod)
|
|||
return false;
|
||||
}
|
||||
|
||||
int status_fd = openat(base_dir_fd, "status", O_RDONLY);
|
||||
int status_fd = openat(base_dir_fd, "status", O_RDONLY | O_CLOEXEC);
|
||||
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);
|
||||
int capacity_fd = openat(base_dir_fd, "capacity", O_RDONLY | O_CLOEXEC);
|
||||
if (capacity_fd < 0) {
|
||||
LOG_ERRNO("/sys/class/power_supply/%s/capacity", m->battery);
|
||||
close(status_fd);
|
||||
|
@ -351,12 +391,12 @@ update_status(struct module *mod)
|
|||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
long capacity = readint_from_fd(capacity_fd);
|
||||
long energy = energy_fd >= 0 ? readint_from_fd(energy_fd) : -1;
|
||||
|
@ -366,6 +406,10 @@ 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);
|
||||
|
||||
|
@ -409,16 +453,23 @@ 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;
|
||||
m->current = current;
|
||||
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->time_to_empty = time_to_empty;
|
||||
m->time_to_full = time_to_full;
|
||||
mtx_unlock(&mod->lock);
|
||||
|
@ -434,13 +485,10 @@ 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;
|
||||
|
||||
|
@ -495,12 +543,11 @@ 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");
|
||||
|
||||
|
@ -526,11 +573,9 @@ 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;
|
||||
|
@ -548,13 +593,17 @@ out:
|
|||
}
|
||||
|
||||
static struct module *
|
||||
battery_new(const char *battery, struct particle *label, long poll_interval_msecs)
|
||||
battery_new(const char *battery, struct particle *label, long poll_interval_msecs, int battery_scale,
|
||||
long smoothing_secs)
|
||||
{
|
||||
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;
|
||||
|
@ -571,13 +620,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));
|
||||
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));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -589,8 +638,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -603,6 +651,8 @@ 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,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
#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 "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *label;
|
||||
enum {
|
||||
UPDATE_GRANULARITY_SECONDS,
|
||||
|
@ -57,8 +58,7 @@ 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,15 +90,12 @@ 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;
|
||||
}
|
||||
|
@ -118,8 +115,7 @@ 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) {
|
||||
|
@ -142,8 +138,7 @@ 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;
|
||||
|
@ -152,20 +147,12 @@ clock_new(struct particle *label, const char *date_format,
|
|||
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;
|
||||
|
@ -173,8 +160,7 @@ clock_new(struct particle *label, const char *date_format,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -193,11 +179,9 @@ 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
|
||||
|
|
|
@ -31,7 +31,8 @@ struct cpu_stats {
|
|||
uint32_t *cur_cores_nidle;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *template;
|
||||
uint16_t interval;
|
||||
size_t core_count;
|
||||
|
@ -69,28 +70,22 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -98,18 +93,12 @@ parse_proc_stat_line(const char *line, uint32_t *user, uint32_t *nice,
|
|||
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);
|
||||
|
@ -135,7 +124,7 @@ refresh_cpu_stats(struct cpu_stats *cpu_stats, size_t core_count)
|
|||
size_t len = 0;
|
||||
ssize_t read;
|
||||
|
||||
fp = fopen("/proc/stat", "r");
|
||||
fp = fopen("/proc/stat", "re");
|
||||
if (NULL == fp) {
|
||||
LOG_ERRNO("unable to open /proc/stat");
|
||||
return;
|
||||
|
@ -143,10 +132,8 @@ 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;
|
||||
}
|
||||
|
@ -251,15 +238,11 @@ 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;
|
||||
|
@ -276,9 +259,7 @@ 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
|
||||
|
@ -288,8 +269,7 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,7 +34,8 @@ struct device_stats {
|
|||
bool exists;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *label;
|
||||
uint16_t interval;
|
||||
tll(struct device_stats *) devices;
|
||||
|
@ -63,7 +64,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));
|
||||
|
@ -84,9 +85,7 @@ 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);
|
||||
|
@ -106,7 +105,7 @@ refresh_device_stats(struct private *m)
|
|||
size_t len = 0;
|
||||
ssize_t read;
|
||||
|
||||
fp = fopen("/proc/diskstats", "r");
|
||||
fp = fopen("/proc/diskstats", "re");
|
||||
if (NULL == fp) {
|
||||
LOG_ERRNO("unable to open /proc/diskstats");
|
||||
return;
|
||||
|
@ -126,13 +125,11 @@ 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 bellow, see
|
||||
* For an explanation of the fields below, see
|
||||
* https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
|
||||
*/
|
||||
uint8_t major_number = 0;
|
||||
|
@ -156,25 +153,23 @@ 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, §ors_read, &reading_time, &completed_writes,
|
||||
&merged_writes, §ors_written, &writting_time, &ios_in_progress,
|
||||
&io_time, &io_weighted_time, &completed_discards, &merged_discards,
|
||||
§ors_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, §ors_read,
|
||||
&reading_time, &completed_writes, &merged_writes, §ors_written, &writting_time,
|
||||
&ios_in_progress, &io_time, &io_weighted_time, &completed_discards, &merged_discards,
|
||||
§ors_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;
|
||||
|
@ -200,8 +195,9 @@ 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);
|
||||
}
|
||||
|
@ -221,12 +217,13 @@ 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;
|
||||
|
@ -314,9 +311,8 @@ 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
|
||||
|
@ -326,9 +322,7 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ process_line(char *line, struct module *module)
|
|||
/* No need to check error IMHO */
|
||||
*target = strtoul(string, NULL, 10);
|
||||
|
||||
/* Populate informations */
|
||||
/* Populate information */
|
||||
if (index == 6) {
|
||||
for (size_t id = 1; id <= private->number_of_tags; ++id) {
|
||||
uint32_t mask = 1 << (id - 1);
|
||||
|
@ -249,13 +249,16 @@ 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);
|
||||
|
@ -327,7 +330,7 @@ run_init(int *inotify_fd, int *inotify_wd, FILE **file, char *dwl_info_filename)
|
|||
return 1;
|
||||
}
|
||||
|
||||
*file = fopen(dwl_info_filename, "r");
|
||||
*file = fopen(dwl_info_filename, "re");
|
||||
if (*file == NULL) {
|
||||
inotify_rm_watch(*inotify_fd, *inotify_wd);
|
||||
close(*inotify_fd);
|
||||
|
@ -438,8 +441,7 @@ 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;
|
||||
|
@ -480,8 +482,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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
|
@ -11,8 +11,8 @@
|
|||
#define LOG_MODULE "foreign-toplevel"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
#include "../particles/dynlist.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
#include "wlr-foreign-toplevel-management-unstable-v1.h"
|
||||
#include "xdg-output-unstable-v1.h"
|
||||
|
@ -46,7 +46,8 @@ 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;
|
||||
|
@ -110,7 +111,8 @@ 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;
|
||||
|
@ -118,11 +120,10 @@ 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;
|
||||
}
|
||||
|
@ -158,22 +159,18 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -183,8 +180,7 @@ 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;
|
||||
|
@ -198,8 +194,7 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -238,8 +233,7 @@ 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;
|
||||
|
@ -248,7 +242,8 @@ output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
|
|||
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;
|
||||
|
@ -260,7 +255,8 @@ output_enter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
|
|||
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;
|
||||
|
@ -275,8 +271,7 @@ 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;
|
||||
|
@ -285,7 +280,8 @@ output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
|
|||
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;
|
||||
|
@ -298,10 +294,10 @@ output_leave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -318,8 +314,7 @@ 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;
|
||||
|
||||
|
@ -329,12 +324,21 @@ state(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle,
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,7 +368,8 @@ 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);
|
||||
|
@ -378,9 +383,7 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -396,9 +399,7 @@ 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;
|
||||
|
@ -412,15 +413,13 @@ toplevel(void *data,
|
|||
{
|
||||
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;
|
||||
|
@ -445,15 +444,12 @@ 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;
|
||||
|
@ -473,8 +469,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
|
@ -488,12 +483,10 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -506,16 +499,19 @@ 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;
|
||||
|
@ -551,9 +547,8 @@ run(struct module *mod)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if ((registry = wl_display_get_registry(display)) == NULL ||
|
||||
wl_registry_add_listener(registry, ®istry_listener, mod) != 0)
|
||||
{
|
||||
if ((registry = wl_display_get_registry(display)) == NULL
|
||||
|| wl_registry_add_listener(registry, ®istry_listener, mod) != 0) {
|
||||
LOG_ERR("failed to get Wayland registry");
|
||||
goto out;
|
||||
}
|
||||
|
@ -561,18 +556,14 @@ 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);
|
||||
|
@ -606,12 +597,14 @@ 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);
|
||||
}
|
||||
|
@ -649,9 +642,7 @@ 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
|
||||
|
|
|
@ -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,14 +41,11 @@ 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) {
|
||||
|
@ -102,11 +99,7 @@ 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;
|
||||
|
@ -120,8 +113,7 @@ 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
|
||||
|
@ -133,10 +125,7 @@ i3_receive_loop(int abort_fd, int sock,
|
|||
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) {
|
||||
|
@ -159,13 +148,11 @@ i3_receive_loop(int abort_fd, int sock,
|
|||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -188,10 +175,8 @@ i3_receive_loop(int abort_fd, int sock,
|
|||
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;
|
||||
|
@ -210,10 +195,10 @@ i3_receive_loop(int abort_fd, int sock,
|
|||
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");
|
||||
|
@ -262,13 +247,13 @@ i3_receive_loop(int abort_fd, int sock,
|
|||
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;
|
||||
|
@ -295,7 +280,7 @@ i3_receive_loop(int abort_fd, int sock,
|
|||
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;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <json-c/json_util.h>
|
||||
|
@ -43,6 +43,4 @@ 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);
|
||||
|
|
283
modules/i3.c
283
modules/i3.c
|
@ -1,27 +1,27 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <threads.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <tllist.h>
|
||||
|
||||
#define LOG_MODULE "i3"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../particles/dynlist.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
#include "i3-ipc.h"
|
||||
#include "i3-common.h"
|
||||
#include "i3-ipc.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,7 +48,8 @@ struct workspace {
|
|||
} window;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
int left_spacing;
|
||||
int right_spacing;
|
||||
|
||||
|
@ -105,10 +106,8 @@ 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;
|
||||
|
@ -126,14 +125,12 @@ 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,
|
||||
|
@ -152,9 +149,12 @@ 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,13 +162,15 @@ 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);
|
||||
|
@ -176,7 +178,6 @@ workspaces_free(struct private *m, bool free_persistent)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
workspace_add(struct private *m, struct workspace ws)
|
||||
{
|
||||
|
@ -187,7 +188,8 @@ 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) {
|
||||
|
@ -202,7 +204,8 @@ 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) {
|
||||
|
@ -211,10 +214,9 @@ 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;
|
||||
}
|
||||
|
@ -225,14 +227,16 @@ 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) {
|
||||
|
@ -249,7 +253,8 @@ 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)
|
||||
|
@ -264,7 +269,8 @@ 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;
|
||||
|
@ -275,7 +281,8 @@ 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;
|
||||
|
@ -339,13 +346,9 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -418,11 +421,12 @@ 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", ¤t) ||
|
||||
!json_object_object_get_ex(current, "id", &_current_id))
|
||||
{
|
||||
if ((!json_object_object_get_ex(json, "current", ¤t)
|
||||
|| !json_object_object_get_ex(current, "id", &_current_id))
|
||||
&& !is_reload) {
|
||||
LOG_ERR("workspace event without 'current' and/or 'id' properties");
|
||||
return false;
|
||||
}
|
||||
|
@ -450,10 +454,8 @@ 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;
|
||||
|
@ -465,7 +467,8 @@ 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;
|
||||
|
@ -499,7 +502,8 @@ 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;
|
||||
|
@ -510,7 +514,6 @@ 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)) {
|
||||
|
@ -518,16 +521,22 @@ 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);
|
||||
|
||||
free(w->output);
|
||||
w->output = strdup(json_object_get_string(_current_output));
|
||||
/* Ignore fallback_output ("For when there's no connected outputs") */
|
||||
if (strcmp(current_output_string, "FALLBACK") != 0) {
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,6 +552,12 @@ 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);
|
||||
}
|
||||
|
@ -569,19 +584,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_new && !is_focus && !is_close && !is_title)
|
||||
if (!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++;
|
||||
|
@ -591,6 +606,20 @@ 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);
|
||||
|
@ -599,33 +628,9 @@ 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);
|
||||
|
@ -646,27 +651,24 @@ 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);
|
||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
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;
|
||||
|
@ -838,7 +840,8 @@ 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;
|
||||
|
||||
|
@ -854,21 +857,12 @@ 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;
|
||||
|
@ -882,6 +876,7 @@ 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),
|
||||
|
@ -893,7 +888,7 @@ content(struct module *mod)
|
|||
|
||||
tag_new_string(mod, "mode", m->mode),
|
||||
},
|
||||
.count = 9,
|
||||
.count = 10,
|
||||
};
|
||||
|
||||
if (ws->focused) {
|
||||
|
@ -903,12 +898,9 @@ 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);
|
||||
|
@ -918,8 +910,7 @@ 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. */
|
||||
|
@ -929,10 +920,8 @@ 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));
|
||||
|
@ -953,8 +942,7 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count,
|
|||
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]);
|
||||
|
@ -977,31 +965,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 *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);
|
||||
}
|
||||
}
|
||||
|
@ -1009,38 +992,27 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -1056,8 +1028,7 @@ 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
|
||||
|
@ -1090,5 +1061,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
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../module.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct particle *label;
|
||||
};
|
||||
struct private { struct particle *label; };
|
||||
|
||||
static void
|
||||
destroy(struct module *mod)
|
||||
|
|
|
@ -24,6 +24,8 @@ struct private
|
|||
{
|
||||
struct particle *label;
|
||||
uint16_t interval;
|
||||
uint64_t mem_free;
|
||||
uint64_t mem_total;
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -52,7 +54,7 @@ get_mem_stats(uint64_t *mem_free, uint64_t *mem_total)
|
|||
size_t len = 0;
|
||||
ssize_t read = 0;
|
||||
|
||||
fp = fopen("/proc/meminfo", "r");
|
||||
fp = fopen("/proc/meminfo", "re");
|
||||
if (NULL == fp) {
|
||||
LOG_ERRNO("unable to open /proc/meminfo");
|
||||
return false;
|
||||
|
@ -79,15 +81,12 @@ 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;
|
||||
|
||||
if (!get_mem_stats(&mem_free, &mem_total)) {
|
||||
LOG_ERR("unable to retrieve the memory stats");
|
||||
}
|
||||
mtx_lock(&mod->lock);
|
||||
|
||||
mem_used = mem_total - mem_free;
|
||||
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;
|
||||
|
||||
double percent_used = ((double)mem_used * 100) / (mem_total + 1);
|
||||
double percent_free = ((double)mem_free * 100) / (mem_total + 1);
|
||||
|
@ -102,6 +101,7 @@ content(struct module *mod)
|
|||
|
||||
struct exposable *exposable = p->label->instantiate(p->label, &tags);
|
||||
tag_set_destroy(&tags);
|
||||
mtx_unlock(&mod->lock);
|
||||
return exposable;
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,13 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -155,9 +162,7 @@ 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
|
||||
|
@ -167,8 +172,7 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,12 @@ 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()
|
||||
|
||||
|
@ -98,7 +104,7 @@ if plugin_label_enabled
|
|||
endif
|
||||
|
||||
if plugin_network_enabled
|
||||
mod_data += {'network': [[], []]}
|
||||
mod_data += {'network': [[], [dynlist]]}
|
||||
endif
|
||||
|
||||
if plugin_pipewire_enabled
|
||||
|
@ -121,6 +127,14 @@ 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
|
||||
|
|
141
modules/mpd.c
141
modules/mpd.c
|
@ -1,33 +1,34 @@
|
|||
#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 <poll.h>
|
||||
#include <libgen.h>
|
||||
#include <poll.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 "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *host;
|
||||
uint16_t port;
|
||||
struct particle *label;
|
||||
|
@ -38,7 +39,8 @@ struct private {
|
|||
bool repeat;
|
||||
bool random;
|
||||
bool consume;
|
||||
int volume;
|
||||
bool single;
|
||||
int volume;
|
||||
char *album;
|
||||
char *artist;
|
||||
char *title;
|
||||
|
@ -60,11 +62,9 @@ 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,12 +132,11 @@ 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;
|
||||
|
@ -154,16 +153,23 @@ 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 *[]){
|
||||
|
@ -171,6 +177,7 @@ 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),
|
||||
|
@ -182,7 +189,7 @@ content(struct module *mod)
|
|||
tag_new_int_realtime(
|
||||
mod, "elapsed", elapsed, 0, m->duration, realtime),
|
||||
},
|
||||
.count = 13,
|
||||
.count = 14,
|
||||
};
|
||||
|
||||
mtx_unlock(&mod->lock);
|
||||
|
@ -237,8 +244,7 @@ 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);
|
||||
|
@ -249,10 +255,7 @@ 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)
|
||||
|
@ -272,7 +275,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);
|
||||
|
||||
|
@ -282,7 +285,7 @@ wait_for_socket_create(const struct module *mod)
|
|||
break;
|
||||
}
|
||||
|
||||
ptr += sizeof(*e) + e->len;
|
||||
ptr += sizeof(*e) + e->len;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,8 +308,7 @@ 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;
|
||||
}
|
||||
|
@ -324,8 +326,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -337,6 +338,7 @@ 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);
|
||||
|
@ -347,17 +349,20 @@ 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);
|
||||
|
@ -401,10 +406,14 @@ 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;
|
||||
|
@ -431,7 +440,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]), 10 * 1000);
|
||||
int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 2 * 1000);
|
||||
|
||||
if (res < 0) {
|
||||
if (errno == EINTR)
|
||||
|
@ -442,10 +451,16 @@ run(struct module *mod)
|
|||
break;
|
||||
}
|
||||
|
||||
if (res == 1) {
|
||||
if (res == 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (res == 1) {
|
||||
assert(fds[0].revents & POLLIN);
|
||||
aborted = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,8 +482,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -492,8 +506,7 @@ 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);
|
||||
|
||||
|
@ -565,9 +578,7 @@ 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;
|
||||
}
|
||||
|
@ -607,7 +618,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;
|
||||
}
|
||||
|
||||
|
@ -638,10 +649,8 @@ 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
|
||||
|
|
1069
modules/network.c
1069
modules/network.c
File diff suppressed because it is too large
Load diff
377
modules/niri-common.c
Normal file
377
modules/niri-common.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
#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;
|
||||
}
|
45
modules/niri-common.h
Normal file
45
modules/niri-common.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#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);
|
160
modules/niri-language.c
Normal file
160
modules/niri-language.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
#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
|
163
modules/niri-workspaces.c
Normal file
163
modules/niri-workspaces.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
#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
|
|
@ -33,7 +33,7 @@ struct output_informations {
|
|||
uint32_t device_id;
|
||||
uint32_t card_profile_device_id;
|
||||
|
||||
/* informations */
|
||||
/* information */
|
||||
bool muted;
|
||||
uint16_t linear_volume; /* classic volume */
|
||||
uint16_t cubic_volume; /* volume a la pulseaudio */
|
||||
|
@ -45,6 +45,16 @@ 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
|
||||
{
|
||||
|
@ -213,18 +223,23 @@ 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)
|
||||
|
@ -235,6 +250,9 @@ 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
|
||||
|
@ -333,7 +351,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 informations if possible */
|
||||
/* set missing information if possible */
|
||||
struct private *private = device->data->module->private;
|
||||
struct node *binded_node = NULL;
|
||||
struct output_informations *output_informations = NULL;
|
||||
|
@ -350,7 +368,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 the same as route's device */
|
||||
/* Node's device is the same as route's device */
|
||||
if (output_informations->device_id != route->device->id)
|
||||
return;
|
||||
|
||||
|
@ -358,7 +376,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 informations */
|
||||
/* Update missing information */
|
||||
X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor));
|
||||
X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name));
|
||||
|
||||
|
@ -384,7 +402,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 parem will then be handled
|
||||
/* Found it, will emit a param event, the param will then be handled
|
||||
* in node_events_param */
|
||||
pw_node_enum_params(target_node, 0, info->params[i].id, 0, -1, NULL);
|
||||
break;
|
||||
|
@ -398,18 +416,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");
|
||||
if (item != NULL)
|
||||
X_FREE_SET(output_informations->name, X_STRDUP(item->value));
|
||||
X_FREE_SET(output_informations->name, item != NULL ? X_STRDUP(item->value) : NULL);
|
||||
|
||||
item = spa_dict_lookup_item(info->props, "node.description");
|
||||
if (item != NULL)
|
||||
X_FREE_SET(output_informations->description, X_STRDUP(item->value));
|
||||
X_FREE_SET(output_informations->description, item != NULL ? X_STRDUP(item->value) : NULL);
|
||||
|
||||
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");
|
||||
|
@ -417,30 +435,29 @@ 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 informations has an more important priority than node's informations */
|
||||
/* Device's information has an more important priority than node's information */
|
||||
/* icon_name */
|
||||
struct route *route = node_find_route(data, node_data->is_sink);
|
||||
if (route != NULL && route->icon_name != NULL)
|
||||
output_informations->icon = X_STRDUP(route->icon_name);
|
||||
X_FREE_SET(output_informations->icon, X_STRDUP(route->icon_name));
|
||||
else {
|
||||
item = spa_dict_lookup_item(info->props, "device.icon-name");
|
||||
if (item != NULL)
|
||||
X_FREE_SET(output_informations->icon, X_STRDUP(item->value));
|
||||
X_FREE_SET(output_informations->icon, item != NULL ? X_STRDUP(item->value) : NULL);
|
||||
}
|
||||
/* form_factor */
|
||||
if (route != NULL && route->form_factor != NULL)
|
||||
output_informations->form_factor = X_STRDUP(route->form_factor);
|
||||
X_FREE_SET(output_informations->form_factor, X_STRDUP(route->form_factor));
|
||||
else {
|
||||
item = spa_dict_lookup_item(info->props, "device.form-factor");
|
||||
if (item != NULL)
|
||||
X_FREE_SET(output_informations->form_factor, X_STRDUP(item->value));
|
||||
X_FREE_SET(output_informations->form_factor, item != NULL ? X_STRDUP(item->value) : NULL);
|
||||
}
|
||||
|
||||
item = spa_dict_lookup_item(info->props, "device.bus");
|
||||
if (item != NULL)
|
||||
X_FREE_SET(output_informations->bus, X_STRDUP(item->value));
|
||||
X_FREE_SET(output_informations->bus, item != NULL ? X_STRDUP(item->value) : NULL);
|
||||
|
||||
data->module->bar->refresh(data->module->bar);
|
||||
}
|
||||
|
@ -659,7 +676,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 deactived */
|
||||
/* profile deactivated */
|
||||
if (target_name == NULL)
|
||||
return;
|
||||
|
||||
|
@ -827,18 +844,8 @@ destroy(struct module *module)
|
|||
pipewire_deinit(private->data);
|
||||
private->label->destroy(private->label);
|
||||
|
||||
/* 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);
|
||||
output_informations_destroy(&private->sink_informations);
|
||||
output_informations_destroy(&private->source_informations);
|
||||
|
||||
free(private);
|
||||
module_default_destroy(module);
|
||||
|
@ -867,9 +874,7 @@ 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 *[]){
|
||||
|
@ -888,9 +893,7 @@ 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 *[]){
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
|
@ -17,7 +17,8 @@
|
|||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *sink_name;
|
||||
char *source_name;
|
||||
struct particle *label;
|
||||
|
@ -69,9 +70,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 = {
|
||||
|
@ -106,11 +107,7 @@ 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;
|
||||
|
@ -119,11 +116,7 @@ abort_event_cb(pa_mainloop_api *api,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -155,8 +148,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);
|
||||
|
||||
|
@ -200,12 +193,10 @@ 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);
|
||||
|
||||
|
@ -234,12 +225,10 @@ 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);
|
||||
|
||||
|
@ -293,32 +282,28 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -332,15 +317,12 @@ 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)
|
||||
|
@ -380,16 +362,13 @@ 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:
|
||||
|
@ -435,8 +414,7 @@ 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);
|
||||
|
@ -460,7 +438,7 @@ run(struct module *mod)
|
|||
}
|
||||
|
||||
// Create refresh timer.
|
||||
priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||
priv->refresh_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
if (priv->refresh_timer_fd < 0) {
|
||||
LOG_ERRNO("failed to create timerfd");
|
||||
pa_mainloop_free(priv->mainloop);
|
||||
|
@ -477,10 +455,8 @@ 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) {
|
||||
|
@ -497,9 +473,7 @@ 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;
|
||||
|
@ -522,10 +496,9 @@ 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
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
#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 <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.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 "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../particles/dynlist.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
|
@ -54,7 +54,8 @@ struct block_device {
|
|||
tll(struct partition) partitions;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *label;
|
||||
int left_spacing;
|
||||
int right_spacing;
|
||||
|
@ -75,8 +76,7 @@ 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,8 +91,7 @@ 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);
|
||||
|
||||
|
@ -113,24 +112,23 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -157,20 +155,16 @@ 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)
|
||||
{
|
||||
int fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC);
|
||||
FILE *f = fd >= 0 ? fdopen(fd, "r") : NULL;
|
||||
FILE *f = fopen("/proc/self/mountinfo", "re");
|
||||
|
||||
if (fd < 0 || f == NULL) {
|
||||
if (f == NULL) {
|
||||
LOG_ERRNO("failed to open /proc/self/mountinfo");
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -178,9 +172,7 @@ 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);
|
||||
|
@ -207,9 +199,11 @@ 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 */
|
||||
|
@ -228,7 +222,8 @@ 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);
|
||||
|
||||
|
@ -242,14 +237,13 @@ 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;
|
||||
|
@ -260,7 +254,8 @@ add_partition(struct module *mod, struct block_device *block,
|
|||
|
||||
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;
|
||||
|
@ -272,21 +267,17 @@ add_partition(struct module *mod, struct block_device *block,
|
|||
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);
|
||||
|
@ -296,14 +287,13 @@ add_partition(struct module *mod, struct block_device *block,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -314,7 +304,8 @@ add_audio_cd(struct module *mod, struct block_device *block,
|
|||
|
||||
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;
|
||||
|
@ -322,28 +313,24 @@ add_audio_cd(struct module *mod, struct block_device *block,
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -353,17 +340,15 @@ add_audio_cd(struct module *mod, struct block_device *block,
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -392,7 +377,8 @@ 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;
|
||||
|
@ -403,11 +389,12 @@ 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
|
||||
|
@ -424,27 +411,22 @@ 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);
|
||||
|
||||
|
@ -466,7 +448,8 @@ 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);
|
||||
|
||||
|
@ -490,7 +473,8 @@ 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;
|
||||
|
@ -511,10 +495,8 @@ 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;
|
||||
|
||||
|
@ -522,8 +504,7 @@ 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)
|
||||
|
@ -569,7 +550,8 @@ 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;
|
||||
|
||||
|
@ -578,8 +560,7 @@ 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;
|
||||
|
@ -606,15 +587,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) {
|
||||
|
@ -631,9 +612,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);
|
||||
}
|
||||
|
@ -673,8 +654,10 @@ 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;
|
||||
}
|
||||
|
@ -703,8 +686,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;
|
||||
|
@ -732,26 +715,22 @@ 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
|
||||
|
|
182
modules/river.c
182
modules/river.c
|
@ -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 <wayland-client.h>
|
||||
#include <tllist.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#define LOG_MODULE "river"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
#include "../particles/dynlist.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
#include "river-status-unstable-v1.h"
|
||||
#include "xdg-output-unstable-v1.h"
|
||||
|
@ -49,8 +49,10 @@ 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;
|
||||
|
@ -87,18 +89,22 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -106,7 +112,8 @@ 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;
|
||||
|
@ -127,10 +134,7 @@ 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",
|
||||
|
@ -155,12 +159,10 @@ 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 *[]){
|
||||
|
@ -187,15 +189,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;
|
||||
|
@ -223,8 +225,7 @@ 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;
|
||||
|
||||
|
@ -241,8 +242,7 @@ 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,9 +254,7 @@ view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
|
|||
/* 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);
|
||||
}
|
||||
|
@ -265,8 +263,7 @@ view_tags(void *data, struct zriver_output_status_v1 *zriver_output_status_v1,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -281,9 +278,7 @@ 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;
|
||||
|
@ -300,8 +295,7 @@ layout_name(void *data,
|
|||
|
||||
#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;
|
||||
|
@ -329,15 +323,12 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -347,8 +338,7 @@ 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;
|
||||
|
@ -363,8 +353,7 @@ xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -391,36 +380,32 @@ 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;
|
||||
|
@ -441,8 +426,7 @@ 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;
|
||||
|
@ -451,7 +435,8 @@ 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;
|
||||
|
@ -469,8 +454,7 @@ 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;
|
||||
|
@ -485,11 +469,9 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
|
|||
|
||||
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);
|
||||
|
@ -502,8 +484,7 @@ focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1,
|
|||
|
||||
#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;
|
||||
|
@ -531,8 +512,7 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -569,19 +549,16 @@ 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;
|
||||
|
||||
|
@ -590,8 +567,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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;
|
||||
|
@ -605,8 +581,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -615,12 +590,10 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -629,8 +602,7 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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;
|
||||
|
@ -649,14 +621,11 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -667,7 +636,8 @@ 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);
|
||||
|
@ -676,7 +646,8 @@ 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);
|
||||
|
@ -707,9 +678,8 @@ run(struct module *mod)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if ((registry = wl_display_get_registry(display)) == NULL ||
|
||||
wl_registry_add_listener(registry, ®istry_listener, m) != 0)
|
||||
{
|
||||
if ((registry = wl_display_get_registry(display)) == NULL
|
||||
|| wl_registry_add_listener(registry, ®istry_listener, m) != 0) {
|
||||
LOG_ERR("failed to get Wayland registry");
|
||||
goto out;
|
||||
}
|
||||
|
@ -721,6 +691,8 @@ run(struct module *mod)
|
|||
goto out;
|
||||
}
|
||||
|
||||
m->is_running = true;
|
||||
|
||||
wl_display_roundtrip(display);
|
||||
|
||||
while (true) {
|
||||
|
@ -754,11 +726,9 @@ 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)
|
||||
|
@ -797,10 +767,8 @@ 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
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
@ -16,15 +16,16 @@
|
|||
|
||||
#define LOG_MODULE "script"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.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;
|
||||
|
@ -110,9 +111,8 @@ 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,16 +165,12 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -186,9 +182,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -199,9 +193,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -223,8 +215,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -298,7 +289,7 @@ data_received(struct module *mod, const char *data, size_t len)
|
|||
{
|
||||
struct private *m = mod->private;
|
||||
|
||||
if (len > m->recv_buf.sz - m->recv_buf.idx) {
|
||||
while (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);
|
||||
|
||||
|
@ -326,9 +317,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -432,11 +421,8 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -452,9 +438,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -533,9 +517,7 @@ 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);
|
||||
|
||||
|
@ -547,7 +529,7 @@ execute_script(struct module *mod)
|
|||
|
||||
/* Don't spinning */
|
||||
thrd_yield();
|
||||
usleep(100000); /* 100ms */
|
||||
usleep(100000); /* 100ms */
|
||||
}
|
||||
|
||||
if (waited_pid == pid) {
|
||||
|
@ -580,7 +562,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;
|
||||
}
|
||||
|
@ -631,8 +613,7 @@ 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;
|
||||
|
@ -665,10 +646,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
@ -691,10 +669,8 @@ 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
|
||||
|
@ -709,8 +685,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -730,8 +705,7 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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-ipc.h"
|
||||
#include "i3-common.h"
|
||||
#include "i3-ipc.h"
|
||||
|
||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
|
@ -21,7 +21,8 @@ struct input {
|
|||
char *layout;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *template;
|
||||
int left_spacing;
|
||||
int right_spacing;
|
||||
|
@ -89,8 +90,7 @@ 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,8 +121,7 @@ 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);
|
||||
|
@ -142,8 +141,7 @@ 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);
|
||||
|
@ -240,8 +238,7 @@ 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);
|
||||
|
@ -309,8 +306,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;
|
||||
|
@ -343,40 +340,32 @@ 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;
|
||||
}
|
||||
|
@ -404,5 +393,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
|
||||
|
|
145
modules/xkb.c
145
modules/xkb.c
|
@ -1,7 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
|
@ -10,10 +10,10 @@
|
|||
|
||||
#define LOG_MODULE "xkb"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
#include "../xcb.h"
|
||||
|
||||
|
@ -32,7 +32,8 @@ struct indicators {
|
|||
char **names;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *label;
|
||||
struct indicators indicators;
|
||||
struct layouts layouts;
|
||||
|
@ -117,10 +118,8 @@ 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));
|
||||
|
@ -142,8 +141,7 @@ 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");
|
||||
|
@ -159,19 +157,14 @@ 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));
|
||||
|
@ -181,22 +174,18 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
|
||||
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++)
|
||||
|
@ -209,17 +198,14 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
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);
|
||||
|
||||
|
@ -232,9 +218,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
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);
|
||||
|
@ -249,9 +233,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
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);
|
||||
|
@ -259,8 +241,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
|
||||
/* 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, "()");
|
||||
|
@ -279,8 +260,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -290,8 +270,7 @@ get_layouts_and_indicators(xcb_connection_t *conn, struct layouts *layouts,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -312,10 +291,8 @@ 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));
|
||||
|
@ -332,10 +309,8 @@ 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));
|
||||
|
@ -353,23 +328,14 @@ 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) {
|
||||
|
@ -393,10 +359,7 @@ 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) {
|
||||
|
@ -425,9 +388,7 @@ 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);
|
||||
|
@ -435,7 +396,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;
|
||||
|
@ -463,7 +424,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);
|
||||
}
|
||||
|
@ -472,8 +433,7 @@ 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);
|
||||
|
@ -490,8 +450,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);
|
||||
|
@ -508,8 +468,7 @@ 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;
|
||||
|
@ -609,18 +568,12 @@ 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);
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <threads.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.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 "../log.h"
|
||||
#include "../bar/bar.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../plugin.h"
|
||||
#include "../xcb.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
/* Accessed from bar thread only */
|
||||
struct particle *label;
|
||||
|
||||
|
@ -48,23 +49,19 @@ 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);
|
||||
|
@ -86,9 +83,8 @@ 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});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,8 +101,7 @@ 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);
|
||||
|
@ -135,7 +130,7 @@ update_application(struct module *mod)
|
|||
char path[1024];
|
||||
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||
|
||||
int fd = open(path, O_RDONLY);
|
||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
|
@ -164,12 +159,11 @@ 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);
|
||||
|
@ -207,7 +201,7 @@ update_title(struct module *mod)
|
|||
free(r1);
|
||||
free(r2);
|
||||
free(r3);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
run(struct module *mod)
|
||||
|
@ -227,19 +221,16 @@ 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);
|
||||
|
||||
|
@ -252,8 +243,7 @@ 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;
|
||||
|
@ -267,10 +257,7 @@ 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));
|
||||
|
@ -278,18 +265,13 @@ 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);
|
||||
|
|
63
particle.c
63
particle.c
|
@ -1,21 +1,21 @@
|
|||
#include "particle.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define LOG_MODULE "particle"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "bar/bar.h"
|
||||
#include "log.h"
|
||||
|
||||
void
|
||||
particle_default_destroy(struct particle *particle)
|
||||
|
@ -29,10 +29,8 @@ 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;
|
||||
|
@ -63,13 +61,11 @@ 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
|
||||
|
@ -114,9 +110,7 @@ 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;
|
||||
|
@ -152,8 +146,7 @@ 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
|
||||
|
@ -168,17 +161,13 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
[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 */
|
||||
|
@ -246,7 +235,7 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -254,11 +243,8 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -271,10 +257,8 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
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;
|
||||
}
|
||||
|
@ -316,10 +300,7 @@ 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;
|
||||
|
|
47
particle.h
47
particle.h
|
@ -42,11 +42,9 @@ 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;
|
||||
|
@ -56,38 +54,31 @@ 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 \
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include "dynlist.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LOG_MODULE "dynlist"
|
||||
#include "../log.h"
|
||||
#include "../particle.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
int left_spacing;
|
||||
int right_spacing;
|
||||
|
||||
|
@ -71,13 +72,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);
|
||||
x += left_spacing + e->widths[i] + right_spacing;
|
||||
if (e->widths[i] > 0)
|
||||
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;
|
||||
|
||||
|
@ -86,17 +87,16 @@ on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
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;
|
||||
}
|
||||
|
||||
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
|
||||
if (e->exposables[i]->width > 0)
|
||||
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
|
||||
}
|
||||
|
||||
LOG_DBG("on_mouse missed all sub-particles");
|
||||
|
@ -104,8 +104,7 @@ on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
#define LOG_MODULE "list"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../particle.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle **particles;
|
||||
size_t count;
|
||||
int left_spacing, right_spacing;
|
||||
|
@ -21,7 +22,6 @@ struct eprivate {
|
|||
int left_spacing, right_spacing;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
exposable_destroy(struct exposable *exposable)
|
||||
{
|
||||
|
@ -80,21 +80,18 @@ 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);
|
||||
x += left_spacing + e->widths[i] + right_spacing;
|
||||
if (e->widths[i] > 0)
|
||||
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;
|
||||
|
@ -104,13 +101,12 @@ on_mouse(struct exposable *exposable, struct bar *bar,
|
|||
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;
|
||||
}
|
||||
|
||||
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
|
||||
if (e->exposables[i]->width > 0)
|
||||
px += e->left_spacing + e->exposables[i]->width + e->right_spacing;
|
||||
}
|
||||
|
||||
/* We're between sub-particles (or in the left/right margin) */
|
||||
|
@ -156,9 +152,8 @@ 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]));
|
||||
|
@ -183,21 +178,20 @@ 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);
|
||||
|
|
238
particles/map.c
238
particles/map.c
|
@ -1,30 +1,93 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LOG_MODULE "map"
|
||||
#include "../log.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,34 +95,52 @@ 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_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_LIKE:
|
||||
return string_like(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) {
|
||||
|
@ -108,7 +189,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);
|
||||
}
|
||||
}
|
||||
|
@ -116,19 +197,17 @@ 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);
|
||||
|
@ -136,28 +215,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_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_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;
|
||||
}
|
||||
free(c);
|
||||
}
|
||||
|
@ -167,7 +246,8 @@ struct particle_map {
|
|||
struct particle *particle;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
struct particle *default_particle;
|
||||
struct particle_map *map;
|
||||
size_t count;
|
||||
|
@ -208,21 +288,16 @@ 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;
|
||||
|
@ -295,8 +370,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;
|
||||
|
@ -314,22 +389,16 @@ map_new(struct particle *common, const struct particle_map particle_map[],
|
|||
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));
|
||||
|
@ -363,17 +432,11 @@ 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);
|
||||
|
@ -384,8 +447,7 @@ 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);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ enum map_op {
|
|||
MAP_OP_GT,
|
||||
MAP_OP_SELF,
|
||||
MAP_OP_NOT,
|
||||
MAP_OP_LIKE,
|
||||
|
||||
MAP_OP_AND,
|
||||
MAP_OP_OR,
|
||||
|
@ -28,7 +29,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);
|
||||
|
|
|
@ -2,19 +2,74 @@
|
|||
#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;
|
||||
\".*\" yylval.str = strndup(yytext + 1, strlen(yytext) - 2); return STRING;
|
||||
|
||||
\" {
|
||||
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.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;
|
||||
|
|
|
@ -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 ")";
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LOG_MODULE "progress_bar"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "../log.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../particle.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *tag;
|
||||
int width;
|
||||
|
||||
|
@ -74,8 +75,7 @@ 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,8 +97,7 @@ 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;
|
||||
|
@ -161,18 +160,14 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -198,19 +193,17 @@ 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]));
|
||||
|
||||
|
@ -259,8 +252,7 @@ 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
|
||||
|
||||
|
@ -271,10 +263,8 @@ 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);
|
||||
|
@ -308,15 +298,10 @@ 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
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
#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 "../log.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../particle.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *tag;
|
||||
bool use_custom_min;
|
||||
long min;
|
||||
|
@ -57,21 +58,16 @@ 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;
|
||||
|
@ -118,22 +114,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;
|
||||
}
|
||||
|
||||
|
@ -168,10 +164,8 @@ 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));
|
||||
|
@ -204,19 +198,15 @@ 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
|
||||
|
|
|
@ -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 "../log.h"
|
||||
#include "../char32.h"
|
||||
#include "../config.h"
|
||||
#include "../config-verify.h"
|
||||
#include "../config.h"
|
||||
#include "../log.h"
|
||||
#include "../particle.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
|
@ -18,7 +18,8 @@ struct text_run_cache {
|
|||
bool in_use;
|
||||
};
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *text;
|
||||
size_t max_len;
|
||||
|
||||
|
@ -51,9 +52,7 @@ 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;
|
||||
|
@ -97,9 +96,8 @@ 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;
|
||||
|
||||
|
@ -112,17 +110,13 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -180,29 +174,16 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
|
|||
|
||||
/* Truncate, if necessary */
|
||||
if (p->max_len > 0 && chars > p->max_len) {
|
||||
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;
|
||||
}
|
||||
chars = p->max_len;
|
||||
if (p->max_len > 3)
|
||||
wtext[p->max_len - 1] = U'…';
|
||||
wtext[p->max_len] = U'\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;
|
||||
|
@ -220,8 +201,7 @@ 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;
|
||||
|
@ -245,8 +225,7 @@ 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;
|
||||
|
@ -307,10 +286,7 @@ 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
147
plugin.c
|
@ -1,99 +1,100 @@
|
|||
#include "plugin.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <tllist.h>
|
||||
|
||||
#define LOG_MODULE "plugin"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "log.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);
|
||||
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);
|
||||
#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);
|
||||
|
@ -121,41 +122,45 @@ 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";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
assert(false && "invalid type");
|
||||
return "";
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -215,6 +220,12 @@ 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
|
||||
|
@ -257,16 +268,13 @@ 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);
|
||||
|
@ -274,7 +282,6 @@ plugin_load(const char *name, enum plugin_type type)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
char path[128];
|
||||
snprintf(path, sizeof(path), "%s_%s.so", type2str(type), name);
|
||||
|
||||
|
|
8
plugin.h
8
plugin.h
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "config-verify.h"
|
||||
#include "config.h"
|
||||
#include "module.h"
|
||||
#include "particle.h"
|
||||
|
||||
|
@ -9,14 +9,12 @@ 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 {
|
||||
|
|
183
tag.c
183
tag.c
|
@ -1,19 +1,20 @@
|
|||
#include "tag.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>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_MODULE "tag"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "log.h"
|
||||
#include "module.h"
|
||||
|
||||
struct private {
|
||||
struct private
|
||||
{
|
||||
char *name;
|
||||
union {
|
||||
struct {
|
||||
|
@ -156,8 +157,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)
|
||||
|
@ -269,15 +270,14 @@ 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, int *value)
|
||||
is_number(const char *str, long *value)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
char *end;
|
||||
int v = strtol(str, &end, 10);
|
||||
long v = strtol(str, &end, 10);
|
||||
if (errno != 0 || *end != '\0')
|
||||
return false;
|
||||
|
||||
|
@ -510,23 +510,21 @@ tags_expand_template(const char *template, const struct tag_set *tags)
|
|||
FMT_HEX,
|
||||
FMT_OCT,
|
||||
FMT_PERCENT,
|
||||
FMT_KBYTE,
|
||||
FMT_MBYTE,
|
||||
FMT_GBYTE,
|
||||
FMT_KIBYTE,
|
||||
FMT_MIBYTE,
|
||||
FMT_GIBYTE,
|
||||
} format = FMT_DEFAULT;
|
||||
FMT_DIVIDE,
|
||||
} format
|
||||
= FMT_DEFAULT;
|
||||
|
||||
enum {
|
||||
VALUE_VALUE,
|
||||
VALUE_MIN,
|
||||
VALUE_MAX,
|
||||
VALUE_UNIT,
|
||||
} kind = VALUE_VALUE;
|
||||
} kind
|
||||
= VALUE_VALUE;
|
||||
|
||||
int digits = 0;
|
||||
int decimals = 2;
|
||||
long digits = 0;
|
||||
long decimals = 2;
|
||||
long divider = 1;
|
||||
bool zero_pad = false;
|
||||
char *point = NULL;
|
||||
|
||||
|
@ -539,18 +537,38 @@ 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 (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 (*tag_args[i] == '/') {
|
||||
format = FMT_DIVIDE;
|
||||
const char *divider_str = tag_args[i] + 1;
|
||||
if (!is_number(divider_str, ÷r) || 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], "min") == 0)
|
||||
kind = VALUE_MIN;
|
||||
else if (strcmp(tag_args[i], "max") == 0)
|
||||
|
@ -567,22 +585,17 @@ 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]);
|
||||
}
|
||||
|
||||
|
@ -593,7 +606,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);
|
||||
|
@ -601,7 +614,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);
|
||||
|
@ -618,9 +631,7 @@ 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);
|
||||
|
@ -632,34 +643,20 @@ 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_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;
|
||||
|
||||
case FMT_DIVIDE: {
|
||||
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);
|
||||
|
@ -674,36 +671,31 @@ 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;
|
||||
const char *fmt = NULL;
|
||||
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_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;
|
||||
case FMT_DIVIDE: {
|
||||
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);
|
||||
|
@ -714,9 +706,15 @@ 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);
|
||||
|
@ -732,8 +730,7 @@ 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
17
tag.h
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum tag_type {
|
||||
TAG_TYPE_BOOL,
|
||||
|
@ -43,21 +43,16 @@ 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);
|
||||
|
|
|
@ -39,8 +39,13 @@ bar:
|
|||
host: 127.0.0.1
|
||||
content: {string: {text: "{state}"}}
|
||||
- network:
|
||||
name: ldsjfdf
|
||||
content: {string: {text: "{name}"}}
|
||||
content:
|
||||
map:
|
||||
default:
|
||||
string: {text: "{name}: {state} ({ipv4})"}
|
||||
conditions:
|
||||
ipv4 == "":
|
||||
string: {text: "{name}: {state}"}
|
||||
- removables:
|
||||
content: {string: {text: "{label}"}}
|
||||
# - xkb:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue