Compare commits

...
Sign in to create a new pull request.

98 commits

Author SHA1 Message Date
80404504ed fix(wayland): this may fix it 2025-02-22 16:29:29 +01:00
43c8316380 fix(wayland): this may fix it 2025-02-22 16:27:22 +01:00
Daniel Eklöf
fc24ea225d
changelog: fix ref (again) for #405 - the issue number is #404 2025-01-01 13:57:32 +01:00
Daniel Eklöf
e1f7c0292f
changelog: fix ref for #405 2025-01-01 13:52:52 +01:00
vova
d746d12f6a
add niri-workspaces and niri-language modules 2025-01-01 13:51:25 +01:00
Ben Boeckel
61d082c802
typos: fix some typos 2025-01-01 13:49:32 +01:00
Ben Boeckel
57711f0dbe mpd: support the single flag
This flag indicates that `mpd` will automatically stop after the
current song is played.
2024-12-28 21:04:54 +01:00
Alexey Yerin
b15714b38a pipewire: Improve handling of node switching
When switching to a node that has a missing property, yambar didn't
reset its internal state to the default value, causing outdated
information to be displayed.
2024-11-27 00:03:12 +03:00
Daniel Eklöf
3e0083c9f2
module/removables: no need to open+fdopen, just do fopen() 2024-10-23 09:40:06 +02:00
Daniel Eklöf
a367895dc6
Open sockets, files etc with FD_CLOEXEC 2024-10-23 09:36:59 +02:00
Mathias Stærk
650d1f13f9
docs: fix typo in example 2024-10-08 15:42:03 +02:00
Daniel Eklöf
e1b6a78f22
doc: particles: remove trailing spaces 2024-10-02 08:11:02 +02:00
Daniel Eklöf
20d48a753b
particle/map: code style 2024-10-02 08:10:53 +02:00
Daniel Eklöf
37ecc251a4
changelog: line-wrap 2024-10-02 08:10:30 +02:00
bagnaram
4826a52306
string like operation 2024-09-16 10:39:12 -05:00
Daniel Eklöf
0f47cbb889
changelog: i3/sway: output tag 2024-09-07 08:35:58 +02:00
Daniel Eklöf
c3f7fe013d
doc: i3/sway: add 'output' to tag list 2024-09-07 08:35:39 +02:00
Daniel Eklöf
b81e41c3c4
module/i3: add 'output' tag
This allows bars to render workspaces differently, depending on which
output the workspace is on:

    - map:
      default: ...
      conditions:
        output == DP-1:
          ...
2024-09-05 11:56:10 +02:00
Daniel Eklöf
060586dbbe
tag: remove the :b formatter
Superseded by /N. Removing since a) it's no longer needed, and b) its
name is not consistent with the other kb/mb/gb formatters.
2024-09-05 08:23:47 +02:00
Daniel Eklöf
c80bae7604
changelog: /N tag formatter 2024-09-05 08:20:59 +02:00
Zhong Jianxin
311c481bfe
tag: add '/N' formatter 2024-09-05 08:19:28 +02:00
Zhong Jianxin
9498d7e445
tag: combine FMT_*BYTE into one FMT_DIVIDE 2024-09-05 08:19:28 +02:00
Daniel Eklöf
2d651d1c0e
changelog: bar position in multi-monitor setups, with location=bottom 2024-09-05 08:16:25 +02:00
fraktal
1b2dee55ef fix bar Y position in case of multi-monitor setups with mixed resolutions 2024-09-04 15:33:25 +02:00
Daniel Eklöf
700bf5b28c
tag: add 'b' formatter
Divides the tag's decimal value by 8.

Closes #392
2024-08-20 14:34:45 +02:00
Daniel Eklöf
f8ba887dcd
readme: repology: use four columns 2024-08-20 09:11:17 +02:00
Daniel Eklöf
887e770202
doc: network: update example
Only display Ethernet and WLAN devices (not loopback, bridges etc).
2024-08-20 07:40:09 +02:00
Daniel Eklöf
54902f46ab
module: network: hardcode type to "wlan" when we see NL80211_CMD_NEW_INTERFACE
Wlan interfaces apparently report themselves as ARPHRD_ETHER in their
ifinfomsg struct (despite there being a ARPHRD_IEEE80211 type...).

"Fix" by hardcoding the type to "wlan" when we receive a
NL80211_CMD_NEW_INTERFACE message.
2024-08-20 07:40:08 +02:00
Daniel Eklöf
699c563051
module: network: add 'kind' tag
The tag maps to the IFLA_INFO_KIND (part of the IFLA_LINKINFO)
netlink attribute.

This attribute is only available on virtual interfaces. Examples of
valid values are:

* bond
* bridge
* gre
* tun
* veth
2024-08-20 07:40:08 +02:00
Daniel Eklöf
a5ae61b5df
module: network: add 'type` tag
This tag maps to the ifinfomsg->ifi_type member, which is set to one
of the ARPHRD_xyz values, defined in linux/if_arp.h.

There's a *ton* of them, and we can't possibly add a string mapping
for _all_ of them, so for now, set to one of:

* loopback
* ether
* wlan
* ARPHRD_NNN, where N is a number
2024-08-20 07:39:59 +02:00
Daniel Eklöf
568eb1140f
modules/mpd: fix reconnect when we're not using inotify
When we're not able to use inotify, we rely on polling. However, we
never detected poll() timeouts, which meant we never re-attempted to
reconnect to MPD.

Maybe #394
2024-08-20 07:34:46 +02:00
Daniel Eklöf
3e0a65f185
meson: fix misdetection of memfd_create() 2024-08-07 17:27:26 +02:00
Daniel Eklöf
1a323c6d21
log: respect the NO_COLOR environment variable
http://no-color.org/
2024-07-18 08:31:46 +02:00
Daniel Eklöf
739dc30323
changelog: env var substitution: fix issue reference
Reference the issue, not the PR.
2024-06-09 10:12:32 +02:00
Daniel Eklöf
8422e7e0b1
doc: yambar(5): remove trailing whitespace 2024-06-09 10:12:23 +02:00
Daniel Eklöf
9cc5e0f7a7
module/network: plug memory leak
Free the 'ifaces' list, not just its contents.
2024-06-09 10:08:38 +02:00
Daniel Eklöf
3431d5fc75
yml: replace_env_variables(): const:ify function variables 2024-06-09 10:05:21 +02:00
Tomas Slusny
20659d3350 Add support for environment variable references
The format is
key: ${env_variable}

Closes #96

Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
2024-06-09 01:11:34 +02:00
Daniel Eklöf
0bea49b75e
module/river: return empty particle list when river is not running
Closes #384
2024-05-20 09:33:45 +02:00
Daniel Eklöf
70efd7d15c
doc: yambar-particles: document the hard-coded spacing of short-form lists
Closes #385
2024-05-20 09:21:29 +02:00
Daniel Eklöf
b8a93a2673
changelog: i3/sway crash fix for output being turned on/off 2024-05-20 07:45:49 +02:00
QuincePie
a467f56677
i3: Handle FALLBACK output for workspaces.
sway moves the workspace to fallback_output when there is no output. For example: when all the screens are off. This commit adds an ignore for the fallback output.
2024-05-20 07:44:50 +02:00
Delgan
b3313cefc6 Fix remaining typos in the codebase (and update CI checks) 2024-05-02 16:28:51 +00:00
betazoid
00234696fe
Add examples/river-minimal.yml 2024-04-30 08:57:36 +02:00
Birger Schacht
3a7455913f
fix: typo
Probaly -> Probably
2024-04-30 08:56:18 +02:00
Sertonix
547cef5afb network: fix missing break in switch statement
This can cause the first character of the string to be read as an iface state.

Fixes https://codeberg.org/dnkl/yambar/issues/377
2024-04-22 16:23:16 +02:00
Daniel Eklöf
6f3952819f
changelog: add new 'unreleased' section 2024-04-17 10:42:56 +02:00
Daniel Eklöf
f148c68736
Merge branch 'releases/1.11' 2024-04-17 10:42:35 +02:00
Daniel Eklöf
a2d30b96fb
meson/pkgbuild: bump version to 1.11.0 2024-04-17 10:30:54 +02:00
Daniel Eklöf
cae07a36ff
changelog: prepare for 1.11.0 2024-04-17 10:30:29 +02:00
Daniel Eklöf
3136310ade
ci: install openssl explicitly, to fix missing SSL module in Python 2024-04-17 09:53:00 +02:00
Daniel Eklöf
be01eeb1de
ci: set 'event' filters on all 'when'-statements 2024-04-17 09:52:46 +02:00
Daniel Eklöf
13f46a314a
examples: conf: laptop: repair network modules
Closes #374
2024-04-11 15:47:50 +02:00
Daniel Eklöf
3c572c70c9
wayland: silence compiler warning
... by ensuring 'layer' is always initialized, to _something_.
2024-04-09 16:34:53 +02:00
Delgan
b85ba99980 Apply "clang-format" preferences globally 2024-04-07 10:05:10 +02:00
Daniel Eklöf
d841aeeecd
config: layer: add 'overlay' and 'background'
The layer option (Wayland only) now accepts 'overlay' and
'background'.

Closes #372
2024-04-06 15:39:19 +02:00
Daniel Eklöf
28a18ad91e
log: fix syslog not respecting the configured log level 2024-04-05 16:11:37 +02:00
Delgan
da19c09122 Add missing "dynlist" dependency to network module 2024-04-01 08:53:50 +00:00
Delgan
58c397d154 Fix CI failing due to outdated test config file 2024-04-01 08:46:50 +00:00
Delgan
53dec73ed2
Fix miscalculation of list width in presence of empty particles 2024-04-01 09:10:58 +02:00
Sertonix
c44c66c83f
network: use dynlist instead of fixed name
Closes #271
Closes #265
Closes #71
2024-04-01 08:34:18 +02:00
Daniel Eklöf
4e07b63cef
plugin: workaround gcc bug that triggers a compilation error
GCC thinks str2type() returns NULL when it doesn't.

Closes #350
2024-03-18 16:47:37 +01:00
Daniel Eklöf
c19a31d925
ci: install and run codespell in/from a venv 2024-03-18 16:45:41 +01:00
Daniel Eklöf
4066326614
ci: sync with woodpecker 2.x changes 2024-03-18 16:40:25 +01:00
Daniel Eklöf
424f22ab84
ci: rename .woodpecker.yml -> .woodpecker.yaml 2024-03-18 16:39:43 +01:00
Haden Collins
7a5cf26fb5
Add changelog entry 2024-03-16 10:00:24 -05:00
Haden Collins
89ae7bd743
Handle reload workspace events from sway correctly
Closes #361
2024-03-14 16:14:53 -05:00
Daniel Eklöf
f2d25c8341
script: fix buffer resize bug
If the amount of data coming in is more than we can hold in our
buffer, we resized the buffer by doubling its size. However, there
were two(!) issues here:

* If this was the first resize, the buffer size was set to 1024. This
  may not be enough (i.e. there may be more than 1024 bytes to process).
* In all other cases, the buffer size was doubled. However, there is
  still no guarantee the buffer is large enough.

Fix by looping until the buffer *is* large enough.
2024-02-05 12:52:40 +01:00
Delgan
aeeef4f236
Fix "mem" values updated while it should not
Closes #352
2024-02-05 12:49:26 +01:00
Delgan
195ac5d1cd
Fix incorrect empty/title state of i3 workspaces 2024-02-05 12:45:02 +01:00
Yiyu Zhou
9d90848291 style: remove trailing spaces 2024-01-13 00:24:58 -05:00
Daniel Eklöf
bbbf2b601e
main: S_ISFIFO() matches both pipes and FIFOs 2024-01-04 16:35:05 +01:00
Daniel Eklöf
cb2561a72c
changelog: move 'reading config from pipe' from changed to added 2024-01-04 16:33:59 +01:00
steovd
8b1fa13686 main: allow reading alternative config from pipe 2024-01-04 15:13:49 +01:00
Daniel Eklöf
bdc4fbe8e7
doc: pipewire: describe the 'content' config option 2024-01-04 13:57:17 +01:00
Delgan
e1f78a16ab
Add new "quality" tag to "network" module 2024-01-04 13:44:54 +01:00
rdbo
26bf62a899 fixed meson setup directory on readme
Signed-off-by: rdbo <rdbo@noreply.codeberg.org>
2024-01-04 08:21:05 +00:00
Daniel Eklöf
cdee55afed
bar: wayland: update bar size + refresh in output_done()
This ensures the bar's size (width) is updated when the screen
resolution (and/or scale) is changed.

Note that we already handled scale changes. This logic has been moved
from output_scale() to output_done().

Closes #330
2024-01-03 15:39:04 +01:00
Daniel Eklöf
9365580539
module: battery: style 2024-01-03 15:30:03 +01:00
Daniel Eklöf
3a3a711b69
changelog: battery: smoothing + scaling 2024-01-03 15:29:06 +01:00
Daniel Eklöf
4d46f25854
doc: battery: document defaults for battery-scale and smoothing-secs 2024-01-03 15:28:32 +01:00
Jordan Isaacs
a943def94e
battery scale and discharge smoothing 2024-01-03 15:22:12 +01:00
Sertonix
e54e8635e0
main: change default log level to warning 2024-01-03 15:20:31 +01:00
kotyk
176ed4a6f3
particles/string: rewrite truncation code, show three dots only for max>3 2024-01-03 15:17:51 +01:00
Daniel Eklöf
d5823bcc4c
changelog: fixed: crash when hidden by an opaque window 2024-01-03 15:15:20 +01:00
Väinö Mäkelä
1283160e17
bar/wayland: Reset last_mapped_monitor on enter
If the surface enters an output, there's no need for
last_mapped_monitor, and it must be reset to fulfill the asserts in
other parts of the code.

This makes yambar no longer crash when it is hidden by an opaque window
multiple times on a compositor using wlroots' scene tree.
2024-01-03 15:14:05 +01:00
Leonardo Hernández Hernández
60671da2ca
lowercase DWL (dwl is the preferred form) 2024-01-03 15:11:09 +01:00
oob
14550440dd
Minor documentation update 2024-01-03 14:34:24 +01:00
Daniel Eklöf
89e74139f5
bar: wayland: shm: try with MFD_NOEXEC_SEAL first, then without
MFD_NOEXEC_SEAL is only supported on kernels 6.3 and later.

If we were compiled on linux >= 6.3, but run on linux < 6.3, we'd exit
with an error, due to memfd_create() failing with EINVAL.

This patch fixes the problem by first trying to call
memfd_create() *with* MFD_NOEXEC_SEAL, and if that fails with EINVAL,
we try again without it.
2023-10-13 16:34:02 +02:00
Daniel Eklöf
cbd3bebb04
bar/wayland: create memfd with MFD_NOEXEC_SEAL 2023-10-08 11:12:15 +02:00
Daniel Eklöf
7fbc1f2c44
bar/wayland: seal memfd 2023-10-08 11:12:08 +02:00
Daniel Eklöf
9a111a52f5
ci: 'pipeline' -> 'steps' 2023-08-18 16:49:18 +02:00
Daniel Eklöf
78f7b60e13
particle/map: non-greedy matching of quotes
Flex regexps are greedy.

This means '"foo" || "bar"' will return 'foo" || "bar', which is
obviously wrong.

Use "start conditions" to implement non-greedy matching.

Closes #302
2023-07-24 17:13:19 +02:00
Daniel Eklöf
9f5f35a8ac
Merge branch 'tag-fmt-is-maybe-uninitialized-warning'
Closes #311
2023-07-14 13:05:17 +02:00
Daniel Eklöf
42cef9373e
changelog: "‘fmt’ may be used uninitialized" compiler warning 2023-07-14 12:54:23 +02:00
Daniel Eklöf
e1fc3a0e29
tag: explicitly initialize ‘fmt’
Fixes the following compiler warning/error:

  In file included from /usr/include/stdio.h:906,
                   from ../tag.c:6:
  In function ‘snprintf’,
      inlined from ‘tags_expand_template’ at ../tag.c:708:13:
  /usr/include/bits/stdio2.h:54:10: error: ‘fmt’ may be used uninitialized [-Werror=maybe-uninitialized]
     54 |   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
        |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     55 |                                    __glibc_objsize (__s), __fmt,
        |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     56 |                                    __va_arg_pack ());
        |                                    ~~~~~~~~~~~~~~~~~
  ../tag.c: In function ‘tags_expand_template’:
  ../tag.c:677:25: note: ‘fmt’ was declared here
    677 |             const char *fmt;
        |                         ^~~
  cc1: all warnings being treated as errors

Closes #311
2023-07-14 12:52:19 +02:00
Daniel Eklöf
5db61745a4
changelog: add new ‘unreleased’ section 2023-07-14 09:04:32 +02:00
Daniel Eklöf
4ba193ad0f
Merge branch 'releases/1.10' 2023-07-14 09:04:18 +02:00
103 changed files with 4100 additions and 3263 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -2,7 +2,7 @@
# Yambar
[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg)](https://repology.org/project/yambar/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg?columns=4)](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

View file

@ -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);

View file

@ -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;
}

View file

@ -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 {

View file

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

View file

@ -1,25 +1,25 @@
#include "wayland.h"
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/input-event-codes.h>
#include <sys/mman.h>
#include <pixman.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <tllist.h>
#include <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
View file

@ -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 *

View file

@ -1,15 +1,15 @@
#include "char32.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <wchar.h>
#if defined __has_include
#if __has_include (<stdc-predef.h>)
#include <stdc-predef.h>
#endif
#if __has_include(<stdc-predef.h>)
#include <stdc-predef.h>
#endif
#endif
#define LOG_MODULE "char32"
@ -24,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

View file

@ -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);

View file

@ -8,6 +8,6 @@ _arguments \
'(-c --config)'{-c,--config}'[alternative configuration file]:filename:_files' \
'(-C --validate)'{-C,--validate}'[verify configuration then quit]' \
'(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running]:pidfile:_files' \
'(-d --log-level)'{-d,--log-level}'[log level (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]'

View file

@ -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

View file

@ -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
View file

@ -1,10 +1,10 @@
#include "config.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
@ -21,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);

View file

@ -1,9 +1,9 @@
#pragma once
#include <fcft/fcft.h>
#include "yml.h"
#include "bar/bar.h"
#include "font-shaping.h"
#include "yml.h"
#include <fcft/fcft.h>
struct bar;
struct particle;
@ -25,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);

View file

@ -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 \
}

View file

@ -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 *

View file

@ -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

View file

@ -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 *

View file

@ -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;
}

View file

@ -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 *

View file

@ -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

View file

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

View file

@ -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

View file

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

View file

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

View file

@ -26,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)

View file

@ -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

View file

@ -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

View 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)

View 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)

View file

@ -19,10 +19,10 @@ pipewire - Monitors pipewire for volume, mute/unmute, device change
: Current device description
| form_factor
: string
: Current device form factor (headset, speaker, mic, etc)
: Current device form factor (headset, speaker, mic, etc.)
| bus
: string
: Current device bus (bluetooth, alsa, etc)
: Current device bus (bluetooth, alsa, etc.)
| icon
: string
: Current device icon name
@ -39,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

View file

@ -16,7 +16,7 @@ configurable amount of time.
In continuous mode, the script is executed once. It will typically run
in a loop, sending an updated tag set whenever it needs, or wants
to. The last tag set is used (displayed) by yambar until a new tag set
is received. This mode is intended to be used by scripts that 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

View file

@ -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)

View file

@ -155,7 +155,7 @@ content:
This particle is a list (or sequence, if you like) of other
particles. It can be used to render e.g. _string_ particles with
different font and/or color formatting. Or 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: ├}}

View file

@ -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

View file

@ -25,11 +25,11 @@ yambar - modular status panel for X11 and Wayland
*-p*,*--print-pid*=_FILE_|_FD_
Print PID to this file, or FD, when successfully started. The file
(or FD) is closed immediately after writing the PID. When a _FILE_
as been specified, the file is unlinked 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.

View file

@ -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

View file

@ -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

View file

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

View file

@ -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}"}

View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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};

View file

@ -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,
},

View file

@ -19,7 +19,7 @@ option('plugin-cpu', type: 'feature', value: 'auto',
option('plugin-disk-io', type: 'feature', value: 'auto',
description: 'Disk I/O support')
option('plugin-dwl', type: 'feature', value: 'auto',
description: 'DWL (dwm for wayland) support')
description: 'dwl (dwm for wayland) support')
option('plugin-foreign-toplevel', type: 'feature', value: 'auto',
description: 'Foreign toplevel (window tracking for Wayland) support')
option('plugin-mem', type: 'feature', value: 'auto',
@ -44,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',

View file

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

View file

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

View file

@ -1,8 +1,8 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <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

View file

@ -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

View file

@ -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,
};

View file

@ -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

View file

@ -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;
}

View file

@ -1,9 +1,9 @@
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <poll.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h>
#include <tllist.h>
@ -34,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, &sectors_read, &reading_time, &completed_writes,
&merged_writes, &sectors_written, &writting_time, &ios_in_progress,
&io_time, &io_weighted_time, &completed_discards, &merged_discards,
&sectors_discarded, &discarding_time, &completed_flushes, &flushing_time))
{
" %" SCNu8 " %" SCNu8 " %ms %" SCNu32 " %" SCNu32 " %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu64 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32 " %" SCNu32
" %" SCNu32 " %" SCNu32 " %" SCNu32,
&major_number, &minor_number, &device_name, &completed_reads, &merged_reads, &sectors_read,
&reading_time, &completed_writes, &merged_writes, &sectors_written, &writting_time,
&ios_in_progress, &io_time, &io_weighted_time, &completed_discards, &merged_discards,
&sectors_discarded, &discarding_time, &completed_flushes, &flushing_time)) {
LOG_ERR("unable to parse /proc/diskstats line");
free(device_name);
goto exit;
}
bool found = false;
tll_foreach(m->devices, it) {
tll_foreach(m->devices, it)
{
struct device_stats *dev = it->item;
if (strcmp(dev->name, device_name) == 0){
if (strcmp(dev->name, device_name) == 0) {
dev->prev_sectors_read = dev->cur_sectors_read;
dev->prev_sectors_written = dev->cur_sectors_written;
dev->ios_in_progress = ios_in_progress;
@ -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;
}

View file

@ -231,7 +231,7 @@ process_line(char *line, struct module *module)
/* No need to check error IMHO */
*target = strtoul(string, NULL, 10);
/* Populate 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

View file

@ -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, &registry_listener, mod) != 0)
{
if ((registry = wl_display_get_registry(display)) == NULL
|| wl_registry_add_listener(registry, &registry_listener, mod) != 0) {
LOG_ERR("failed to get Wayland registry");
goto out;
}
@ -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

View file

@ -1,15 +1,15 @@
#include "i3-common.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <poll.h>
#if defined(ENABLE_X11)
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#endif
#include <json-c/json_tokener.h>
@ -19,7 +19,7 @@
#include "../log.h"
#if defined(ENABLE_X11)
#include "../xcb.h"
#include "../xcb.h"
#endif
#include "i3-ipc.h"
@ -41,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;

View file

@ -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);

View file

@ -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", &current) ||
!json_object_object_get_ex(current, "id", &_current_id))
{
if ((!json_object_object_get_ex(json, "current", &current)
|| !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

View file

@ -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)

View file

@ -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;
}

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

377
modules/niri-common.c Normal file
View 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
View 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
View 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
View 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

View file

@ -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 *[]){

View file

@ -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

View file

@ -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

View file

@ -1,17 +1,17 @@
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <poll.h>
#include <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, &registry_listener, m) != 0)
{
if ((registry = wl_display_get_registry(display)) == NULL
|| wl_registry_add_listener(registry, &registry_listener, m) != 0) {
LOG_ERR("failed to get Wayland registry");
goto out;
}
@ -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

View file

@ -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;
}

View file

@ -3,15 +3,15 @@
#define LOG_MODULE "sway-xkb"
#define LOG_ENABLE_DBG 0
#include "../log.h"
#include "../bar/bar.h"
#include "../config-verify.h"
#include "../config.h"
#include "../log.h"
#include "../particles/dynlist.h"
#include "../plugin.h"
#include "i3-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

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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 \
}

View file

@ -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;

View file

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

View file

@ -1,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;
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

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

View file

@ -1,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

View file

@ -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

View file

@ -1,13 +1,13 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define LOG_MODULE "string"
#define LOG_ENABLE_DBG 0
#include "../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
View file

@ -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);

View file

@ -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
View file

@ -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, &divider) || divider == 0) {
divider = 1;
LOG_WARN("tag `%s`: invalid divider %s, reset to 1", tag_name, divider_str);
}
}
else if (strcmp(tag_args[i], "kb") == 0) {
format = FMT_DIVIDE;
divider = 1000;
}
else if (strcmp(tag_args[i], "mb") == 0) {
format = FMT_DIVIDE;
divider = 1000 * 1000;
}
else if (strcmp(tag_args[i], "gb") == 0) {
format = FMT_DIVIDE;
divider = 1000 * 1000 * 1000;
}
else if (strcmp(tag_args[i], "kib") == 0) {
format = FMT_DIVIDE;
divider = 1024;
}
else if (strcmp(tag_args[i], "mib") == 0) {
format = FMT_DIVIDE;
divider = 1024 * 1024;
}
else if (strcmp(tag_args[i], "gib") == 0) {
format = FMT_DIVIDE;
divider = 1024 * 1024 * 1024;
}
else if (strcmp(tag_args[i], "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
View file

@ -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);

View file

@ -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