pw-top: filter by status

This commit is contained in:
pallaswept 2026-04-07 20:02:55 +10:00 committed by Wim Taymans
parent 49073cf527
commit bf7f2a5d88
2 changed files with 69 additions and 2 deletions

View file

@ -188,6 +188,11 @@ Quit
Clear the ERR counters. This does *not* clear the counters globally, Clear the ERR counters. This does *not* clear the counters globally,
it will only reset the counters in this instance of *pw-top*. it will only reset the counters in this instance of *pw-top*.
\par [f|F]
Cycle through filter presets. If any nodes are filtered from view,
the current preset will be indicated in the header bar. Only nodes
with the indicated state or higher, will be printed.
# OPTIONS # OPTIONS
\par -h | \--help \par -h | \--help
@ -199,6 +204,9 @@ Run in non-interactive batch mode, similar to top\'s batch mode.
\par -n | \--iterations=NUMBER \par -n | \--iterations=NUMBER
Exit after NUMBER of batch iterations. Only used in batch mode. Exit after NUMBER of batch iterations. Only used in batch mode.
\par -f | \--filter=NUMBER
Start with filter preset NUMBER selected.
\par -r | \--remote=NAME \par -r | \--remote=NAME
The name the *remote* instance to monitor. If left unspecified, a The name the *remote* instance to monitor. If left unspecified, a
connection is made to the default PipeWire instance. connection is made to the default PipeWire instance.

View file

@ -66,6 +66,21 @@ struct node {
struct spa_hook object_listener; struct spa_hook object_listener;
}; };
struct filter_preset {
enum pw_node_state filter_state;
enum pw_node_state filter_followers;
};
struct filter_preset filter_presets[] = {
{PW_NODE_STATE_ERROR, PW_NODE_STATE_ERROR},
{PW_NODE_STATE_IDLE, PW_NODE_STATE_ERROR},
{PW_NODE_STATE_RUNNING, PW_NODE_STATE_ERROR},
{PW_NODE_STATE_RUNNING, PW_NODE_STATE_IDLE},
};
unsigned int filter_presets_length =
sizeof(filter_presets) / sizeof(struct filter_preset);
struct data { struct data {
struct pw_main_loop *loop; struct pw_main_loop *loop;
struct pw_context *context; struct pw_context *context;
@ -91,6 +106,8 @@ struct data {
unsigned int batch_mode:1; unsigned int batch_mode:1;
int iterations; int iterations;
unsigned int filter_preset;
}; };
struct point { struct point {
@ -564,9 +581,31 @@ static void do_refresh(struct data *d, bool force_refresh)
return; return;
if (!d->batch_mode) { if (!d->batch_mode) {
char statusbar[COLS] = {};
if (!((filter_presets[d->filter_preset].filter_state == PW_NODE_STATE_ERROR) &&
(filter_presets[d->filter_preset].filter_followers == PW_NODE_STATE_ERROR))) {
strcpy(statusbar, "FILTER: ");
if (filter_presets[d->filter_preset].filter_state == PW_NODE_STATE_ERROR)
strcat(statusbar, "ALL");
else for (enum pw_node_state showstate = PW_NODE_STATE_RUNNING; showstate >= PW_NODE_STATE_ERROR; showstate--) {
if (showstate >= filter_presets[d->filter_preset].filter_state)
strcat(statusbar, state_as_string(showstate, SPA_IO_POSITION_STATE_STOPPED));
}
strcat(statusbar, "+");
if (filter_presets[d->filter_preset].filter_followers == PW_NODE_STATE_ERROR)
strcat(statusbar, "ALL");
else for (enum pw_node_state showstate = PW_NODE_STATE_RUNNING; showstate >= PW_NODE_STATE_ERROR; showstate--) {
if (showstate >= filter_presets[d->filter_preset].filter_followers)
strcat(statusbar, state_as_string(showstate, SPA_IO_POSITION_STATE_STOPPED));
}
}
werase(d->win); werase(d->win);
wattron(d->win, A_REVERSE); wattron(d->win, A_REVERSE);
wprintw(d->win, "%-*.*s", COLS, COLS, HEADER); wprintw(d->win, "%-*.*s", COLS, COLS, HEADER);
if ((size_t)COLS >= strlen(HEADER) + strlen(statusbar))
mvwprintw(d->win, 0, COLS - strlen(statusbar), "%s", statusbar);
wattroff(d->win, A_REVERSE); wattroff(d->win, A_REVERSE);
wprintw(d->win, "\n"); wprintw(d->win, "\n");
} else } else
@ -575,6 +614,8 @@ static void do_refresh(struct data *d, bool force_refresh)
spa_list_for_each_safe(n, t, &d->node_list, link) { spa_list_for_each_safe(n, t, &d->node_list, link) {
if (n->driver != n) if (n->driver != n)
continue; continue;
if (n->state < filter_presets[d->filter_preset].filter_state)
continue;
print_node(d, n, n, y++); print_node(d, n, n, y++);
if(!d->batch_mode && y > LINES) if(!d->batch_mode && y > LINES)
@ -587,6 +628,9 @@ static void do_refresh(struct data *d, bool force_refresh)
if (f->driver != n || f == n) if (f->driver != n || f == n)
continue; continue;
if (f->state < filter_presets[d->filter_preset].filter_followers)
continue;
print_node(d, n, f, y++); print_node(d, n, f, y++);
if(!d->batch_mode && y > LINES) if(!d->batch_mode && y > LINES)
break; break;
@ -771,8 +815,9 @@ static void show_help(const char *name, bool error)
{ {
fprintf(error ? stderr : stdout, "Usage:\n%s [options]\n\n" fprintf(error ? stderr : stdout, "Usage:\n%s [options]\n\n"
"Options:\n" "Options:\n"
" -b, --batch-mode run in non-interactive batch mode\n" " -b, --batch-mode run in non-interactive batch mode\n"
" -n, --iterations = NUMBER exit after NUMBER batch iterations\n" " -n, --iterations = NUMBER exit after NUMBER batch iterations\n"
" -f, --filter = NUMBER start with filter preset NUMBER selected\n"
" -r, --remote Remote daemon name\n" " -r, --remote Remote daemon name\n"
"\n" "\n"
" -h, --help Show this help\n" " -h, --help Show this help\n"
@ -807,6 +852,14 @@ static void do_handle_io(void *data, int fd, uint32_t mask)
case 'c': case 'c':
reset_xruns(d); reset_xruns(d);
break; break;
case 'f':
d->filter_preset = ((d->filter_preset + 1) % filter_presets_length);
do_refresh(d, !d->batch_mode);
break;
case 'F':
d->filter_preset = ((d->filter_preset - 1 + filter_presets_length) % filter_presets_length);
do_refresh(d, !d->batch_mode);
break;
default: default:
do_refresh(d, !d->batch_mode); do_refresh(d, !d->batch_mode);
break; break;
@ -822,6 +875,7 @@ int main(int argc, char *argv[])
static const struct option long_options[] = { static const struct option long_options[] = {
{ "batch-mode", no_argument, NULL, 'b' }, { "batch-mode", no_argument, NULL, 'b' },
{ "iterations", required_argument, NULL, 'n' }, { "iterations", required_argument, NULL, 'n' },
{ "filter", required_argument, NULL, 'f' },
{ "remote", required_argument, NULL, 'r' }, { "remote", required_argument, NULL, 'r' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
@ -835,10 +889,11 @@ int main(int argc, char *argv[])
pw_init(&argc, &argv); pw_init(&argc, &argv);
data.iterations = -1; data.iterations = -1;
data.filter_preset = 0;
spa_list_init(&data.node_list); spa_list_init(&data.node_list);
while ((c = getopt_long(argc, argv, "hVr:o:bn:", long_options, NULL)) != -1) { while ((c = getopt_long(argc, argv, "hVr:o:bn:f:", long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'h': case 'h':
show_help(argv[0], false); show_help(argv[0], false);
@ -857,6 +912,10 @@ int main(int argc, char *argv[])
case 'b': case 'b':
data.batch_mode = 1; data.batch_mode = 1;
break; break;
case 'f':
spa_atoi32(optarg, &data.filter_preset, 10);
data.filter_preset = ((data.filter_preset) % filter_presets_length);
break;
case 'n': case 'n':
spa_atoi32(optarg, &data.iterations, 10); spa_atoi32(optarg, &data.iterations, 10);
break; break;