diff options
-rw-r--r-- | CMakeLists.txt | 51 | ||||
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | gdm-switch-user.c | 2 | ||||
-rw-r--r-- | iexec.c | 113 | ||||
-rw-r--r-- | input-switch.c | 88 | ||||
m--------- | liberty | 0 | ||||
-rwxr-xr-x | wmstatus-weather.pl | 3 | ||||
-rw-r--r-- | wmstatus.c | 56 |
8 files changed, 207 insertions, 108 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e18b66..f1d4292 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ configure_file (${PROJECT_SOURCE_DIR}/config.h.in include_directories (${PROJECT_BINARY_DIR}) # Build -set (targets wmstatus paswitch siprandom big-brother) +set (targets wmstatus paswitch siprandom) if ("${CMAKE_SYSTEM_NAME}" STREQUAL Linux) # These use Linux i2c APIs, but can be made to work on macOS list (APPEND targets brightness input-switch) @@ -47,7 +47,7 @@ elseif (APPLE) add_definitions (-D_DARWIN_C_SOURCE) endif () -foreach (name ${targets}) +foreach (name big-brother ${targets}) add_executable (${name} ${name}.c) endforeach () @@ -71,27 +71,42 @@ include (GNUInstallDirs) set (SYSTEMD_UNITDIR /lib/systemd/system CACHE PATH "Base directory for systemd unit files") -configure_file (${PROJECT_SOURCE_DIR}/fancontrol-ng.service.in - ${PROJECT_BINARY_DIR}/fancontrol-ng.service @ONLY) -install (FILES fancontrol-ng.conf.example - DESTINATION ${CMAKE_INSTALL_DATADIR}/fancontrol-ng) - -configure_file (${PROJECT_SOURCE_DIR}/priod.service.in - ${PROJECT_BINARY_DIR}/priod.service @ONLY) -install (FILES priod.conf.example - DESTINATION ${CMAKE_INSTALL_DATADIR}/priod) - -# System-wide unit files should be installed under /lib and not /usr/lib -install (FILES - ${PROJECT_BINARY_DIR}/fancontrol-ng.service - ${PROJECT_BINARY_DIR}/priod.service - DESTINATION "${SYSTEMD_UNITDIR}") +if ("${CMAKE_SYSTEM_NAME}" STREQUAL Linux) + configure_file (${PROJECT_SOURCE_DIR}/fancontrol-ng.service.in + ${PROJECT_BINARY_DIR}/fancontrol-ng.service @ONLY) + install (FILES fancontrol-ng.conf.example + DESTINATION ${CMAKE_INSTALL_DATADIR}/fancontrol-ng) + + configure_file (${PROJECT_SOURCE_DIR}/priod.service.in + ${PROJECT_BINARY_DIR}/priod.service @ONLY) + install (FILES priod.conf.example + DESTINATION ${CMAKE_INSTALL_DATADIR}/priod) + + # System-wide unit files should be installed under /lib and not /usr/lib + install (FILES + ${PROJECT_BINARY_DIR}/fancontrol-ng.service + ${PROJECT_BINARY_DIR}/priod.service + DESTINATION "${SYSTEMD_UNITDIR}") +endif () if (WITH_GDM) install (TARGETS gdm-switch-user DESTINATION ${CMAKE_INSTALL_BINDIR}) endif () -list (REMOVE_ITEM targets big-brother) +# These should be accessible by users, but need to touch system devices. +# Use the setuid bit, for simplicity. +foreach (target brightness input-switch) + if (${target} IN_LIST targets) + list (REMOVE_ITEM targets ${target}) + install (TARGETS ${target} DESTINATION ${CMAKE_INSTALL_BINDIR} + PERMISSIONS + OWNER_WRITE OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + SETUID) + endif () +endforeach () + install (TARGETS ${targets} DESTINATION ${CMAKE_INSTALL_BINDIR}) install (PROGRAMS shellify DESTINATION ${CMAKE_INSTALL_BINDIR}) install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) @@ -1,4 +1,4 @@ -Copyright (c) 2015 - 2021, Přemysl Eric Janouch <p@janouch.name> +Copyright (c) 2015 - 2024, Přemysl Eric Janouch <p@janouch.name> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. diff --git a/gdm-switch-user.c b/gdm-switch-user.c index 5718c31..55d8ba3 100644 --- a/gdm-switch-user.c +++ b/gdm-switch-user.c @@ -1,5 +1,5 @@ // Public domain -#include <gdm-user-switching.h> +#include <gdm/gdm-user-switching.h> int main (int argc, char *argv[]) @@ -1,7 +1,7 @@ /* * iexec.c: run a program and restart on file change * - * Copyright (c) 2017, Přemysl Eric Janouch <p@janouch.name> + * Copyright (c) 2017 - 2023, Přemysl Eric Janouch <p@janouch.name> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. @@ -24,34 +24,54 @@ // This can also work on BSD if someone puts in the effort to support kqueue #include <sys/inotify.h> -static pid_t g_child; -static bool g_restarting = false; -static int g_inotify_fd, g_inotify_wd; +static struct +{ + pid_t child; ///< Watched child or 0 + bool exits; ///< Don't restart child when it exits + bool respawn; ///< Respawn child ASAP + bool killing; ///< Waiting for child to die + int inotify_fd, inotify_wd; +} +g; +// Note that this program doesn't queue up file-based restarts static void -handle_file_change (const char *base) +handle_inotify_event (const struct inotify_event *e, const char *base) { - char buf[4096]; ssize_t len; const struct inotify_event *e; - while ((len = read (g_inotify_fd, buf, sizeof buf)) > 0) - for (char *ptr = buf; ptr < buf + len; ptr += sizeof *e + e->len) - { - e = (const struct inotify_event *) buf; - if (e->wd != g_inotify_wd || strcmp (e->name, base)) - continue; + if (e->wd != g.inotify_wd || strcmp (e->name, base)) + return; + if (g.child) + { print_debug ("file changed, killing child"); - g_restarting = true; - if (kill (g_child, SIGINT)) + if (kill (g.child, SIGINT)) print_error ("kill: %s", strerror (errno)); + g.killing = true; + } + else + { + print_debug ("file changed, respawning"); + g.respawn = true; } } static void +handle_file_change (const char *base) +{ + char buf[4096]; + ssize_t len = 0; + struct inotify_event *e = NULL; + while ((len = read (g.inotify_fd, buf, sizeof buf)) > 0) + for (char *ptr = buf; ptr < buf + len; ptr += sizeof *e + e->len) + handle_inotify_event ((e = (struct inotify_event *) buf), base); +} + +static void spawn (char *argv[]) { - if ((g_child = fork ()) == -1) + if ((g.child = fork ()) == -1) exit_fatal ("fork: %s", strerror (errno)); - else if (g_child) + else if (g.child) return; // A linker can create spurious CLOSE_WRITEs, wait until it's executable @@ -64,23 +84,22 @@ spawn (char *argv[]) } static bool -check_child_death (char *argv[]) +check_child_death (void) { - if (waitpid (g_child, NULL, WNOHANG) != g_child) + int status = 0; + if (waitpid (g.child, &status, WNOHANG) != g.child) return true; - if (!g_restarting) + g.child = 0; + if (!g.killing) { print_debug ("child died on its own, not respawning"); - return false; - } - else - { - print_debug ("child died on request, respawning"); - spawn (argv); - g_restarting = false; - return true; + return g.exits; } + + g.killing = false; + print_debug ("child died on request, respawning"); + return g.respawn = true; } static void @@ -93,8 +112,11 @@ sigchld_handler (int signum) int main (int argc, char *argv[]) { + const char *target = NULL; static const struct opt opts[] = { + { 'f', "file", "PATH", 0, "watch this path rather than the program" }, + { 'e', "exits", NULL, 0, "allow the program to exit on its own" }, { 'd', "debug", NULL, 0, "run in debug mode" }, { 'h', "help", NULL, 0, "display this help and exit" }, { 'V', "version", NULL, 0, "output version information and exit" }, @@ -111,6 +133,12 @@ main (int argc, char *argv[]) while ((c = opt_handler_get (&oh)) != -1) switch (c) { + case 'f': + target = optarg; + break; + case 'e': + g.exits = true; + break; case 'd': g_debug_mode = true; break; @@ -136,6 +164,9 @@ main (int argc, char *argv[]) argc -= optind; argv += optind; + if (!target) + target = argv[0]; + (void) signal (SIGPIPE, SIG_IGN); struct sigaction sa = { .sa_handler = sigchld_handler }; sigemptyset (&sa.sa_mask); @@ -148,27 +179,33 @@ main (int argc, char *argv[]) if (sigprocmask (SIG_BLOCK, &chld, &orig)) exit_fatal ("sigprocmask: %s", strerror (errno)); - char *path = xstrdup (argv[0]); + char *path = NULL; + char *dir = dirname ((path = xstrdup (target))); - if ((g_inotify_fd = inotify_init1 (IN_NONBLOCK)) < 0) + if ((g.inotify_fd = inotify_init1 (IN_NONBLOCK)) < 0) exit_fatal ("inotify_init1: %s", strerror (errno)); - if ((g_inotify_wd = inotify_add_watch (g_inotify_fd, - dirname (path), IN_MOVED_TO | IN_CLOSE_WRITE)) < 0) + if ((g.inotify_wd = inotify_add_watch (g.inotify_fd, + dir, IN_MOVED_TO | IN_CLOSE_WRITE)) < 0) exit_fatal ("inotify_add_watch: %s", strerror (errno)); free (path); - char *base = basename ((path = xstrdup (argv[0]))); - spawn (argv); - + char *base = basename ((path = xstrdup (target))); + g.respawn = true; do { - fd_set r; FD_SET (g_inotify_fd, &r); - (void) pselect (g_inotify_fd + 1, &r, NULL, NULL, NULL, &orig); + if (g.respawn) + { + spawn (argv); + g.respawn = false; + } + + fd_set r; FD_SET (g.inotify_fd, &r); + (void) pselect (g.inotify_fd + 1, &r, NULL, NULL, NULL, &orig); handle_file_change (base); } - while (check_child_death (argv)); + while (check_child_death ()); free (path); - close (g_inotify_fd); + xclose (g.inotify_fd); return EXIT_SUCCESS; } diff --git a/input-switch.c b/input-switch.c index da93670..5788f4a 100644 --- a/input-switch.c +++ b/input-switch.c @@ -1,7 +1,7 @@ /* * input-switch.c: switches display input via DDC/CI * - * Copyright (c) 2017, Přemysl Eric Janouch <p@janouch.name> + * Copyright (c) 2017 - 2022, Přemysl Eric Janouch <p@janouch.name> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. @@ -28,11 +28,60 @@ #include "ddc-ci.c" #include <dirent.h> +// This list is from the MCCS 2.2a specification +struct +{ + int code; ///< Input code + const char *name; ///< Input name + int index; ///< Input index +} +g_inputs[] = +{ + { 0x01, "VGA", 1, }, // Analog video (R/G/B) 1 + { 0x02, "VGA", 2, }, // Analog video (R/G/B) 2 + { 0x03, "DVI", 1, }, // Digital video (TMDS) 1 DVI 1 + { 0x04, "DVI", 2, }, // Digital video (TMDS) 2 DVI 2 + { 0x05, "composite", 1, }, // Composite video 1 + { 0x06, "composite", 2, }, // Composite video 2 + { 0x07, "S-Video", 1, }, // S-video 1 + { 0x08, "S-Video", 2, }, // S-video 2 + { 0x09, "tuner", 1, }, // Tuner 1 + { 0x0A, "tuner", 2, }, // Tuner 2 + { 0x0B, "tuner", 3, }, // Tuner 3 + { 0x0C, "component", 1, }, // Component video (YPbPr/YCbCr) 1 + { 0x0D, "component", 2, }, // Component video (YPbPr/YCbCr) 2 + { 0x0E, "component", 3, }, // Component video (YPbPr/YCbCr) 3 + { 0x0F, "DP", 1, }, // DisplayPort 1 + { 0x10, "DP", 2, }, // DisplayPort 2 + { 0x11, "HDMI", 1, }, // Digital Video (TMDS) 3 HDMI 1 + { 0x12, "HDMI", 2, }, // Digital Video (TMDS) 4 HDMI 2 + { 0x15, "bnq-tb", 1, }, // Thunderbolt on BenQ PD3220U (no spec) +}; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - typedef bool (*ActionFunc) (int fd, int param, struct error **); static bool +get_input_source (int fd, int input, struct error **e) +{ + struct vcp_feature_readout readout = {}; + if (!vcp_get_feature (fd, VCP_INPUT_SOURCE, &readout, e)) + return false; + + (void) input; + for (size_t i = 0; i < N_ELEMENTS (g_inputs); i++) + if (g_inputs[i].code == readout.cur) + { + printf ("input is %s %d\n", g_inputs[i].name, g_inputs[i].index); + return true; + } + + printf ("input is %d\n", readout.cur); + return true; +} + +static bool set_input_source (int fd, int input, struct error **e) { struct vcp_feature_readout readout = {}; @@ -114,36 +163,6 @@ i2c (ActionFunc action, int param) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// This list is from the MCCS 2.2a specification -struct -{ - int code; ///< Input code - const char *name; ///< Input name - int index; ///< Input index -} -g_inputs[] = -{ - { 0x01, "vga", 1, }, // Analog video (R/G/B) 1 - { 0x02, "vga", 2, }, // Analog video (R/G/B) 2 - { 0x03, "dvi", 1, }, // Digital video (TMDS) 1 DVI 1 - { 0x04, "dvi", 2, }, // Digital video (TMDS) 2 DVI 2 - { 0x05, "composite", 1, }, // Composite video 1 - { 0x06, "composite", 2, }, // Composite video 2 - { 0x07, "s-video", 1, }, // S-video 1 - { 0x08, "s-video", 2, }, // S-video 2 - { 0x09, "tuner", 1, }, // Tuner 1 - { 0x0A, "tuner", 2, }, // Tuner 2 - { 0x0B, "tuner", 3, }, // Tuner 3 - { 0x0C, "component", 1, }, // Component video (YPbPr/YCbCr) 1 - { 0x0D, "component", 2, }, // Component video (YPbPr/YCbCr) 2 - { 0x0E, "component", 3, }, // Component video (YPbPr/YCbCr) 3 - { 0x0F, "dp", 1, }, // DisplayPort 1 - { 0x10, "dp", 2, }, // DisplayPort 2 - { 0x11, "hdmi", 1, }, // Digital Video (TMDS) 3 HDMI 1 - { 0x12, "hdmi", 2, }, // Digital Video (TMDS) 4 HDMI 2 - { 0x15, "bnq-tb", 1, }, // Thunderbolt on BenQ PD3220U (no spec) -}; - int main (int argc, char *argv[]) { @@ -151,9 +170,14 @@ main (int argc, char *argv[]) if (argc <= 1) { - printf ("Usage: %s <input> [<index>]\n", argv[0]); + printf ("Usage: %s {? | INPUT [INDEX]}\n", argv[0]); exit (EXIT_FAILURE); } + if (!strcmp (argv[1], "?")) + { + i2c (get_input_source, -1); + exit (EXIT_SUCCESS); + } unsigned long input_source = 0; if (xstrtoul (&input_source, argv[1], 10)) diff --git a/liberty b/liberty -Subproject 782a9a5977bd5f2101e8808b94d659fe52e2490 +Subproject ad5b2fb8cd4915de9c6d97c362839de02d4970a diff --git a/wmstatus-weather.pl b/wmstatus-weather.pl index d5252f2..2d60bc4 100755 --- a/wmstatus-weather.pl +++ b/wmstatus-weather.pl @@ -20,7 +20,8 @@ my %legends; sub retrieve_legends { # HTTP/Tiny supports TLS, but with non-core IO::Socket::SSL, so use cURL open(my $sock, '-|', 'curl', '-sSA', $agent, - "$base/weathericon/2.0/legends.txt") or return $!; + 'https://raw.githubusercontent.com/' . + 'metno/weathericons/main/weather/legend.csv') or return $!; while (local $_ = <$sock>) { $legends{$1} = $2 if /^(.+?),(.+?),/ } close($sock); } @@ -1,7 +1,7 @@ /* * wmstatus.c: simple PulseAudio-enabled status setter for dwm and i3/sway * - * Copyright (c) 2015 - 2021, Přemysl Eric Janouch <p@janouch.name> + * Copyright (c) 2015 - 2024, Přemysl Eric Janouch <p@janouch.name> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. @@ -20,7 +20,10 @@ #define LIBERTY_WANT_ASYNC #define LIBERTY_WANT_PROTO_MPD -#define _GNU_SOURCE // openat +// openat, dirfd +#define _XOPEN_SOURCE 700 +#define _ATFILE_SOURCE +#define _GNU_SOURCE #include "config.h" #undef PROGRAM_NAME @@ -849,7 +852,7 @@ struct app_context struct mpd_client mpd_client; ///< MPD client char *mpd_song; ///< MPD current song - char *mpd_status; ///< MPD status (overrides song) + bool mpd_stopped; ///< MPD stopped (overrides song) // NUT: @@ -989,7 +992,6 @@ app_context_free (struct app_context *self) mpd_client_free (&self->mpd_client); cstr_set (&self->mpd_song, NULL); - cstr_set (&self->mpd_status, NULL); nut_client_free (&self->nut_client); str_map_free (&self->nut_ups_info); @@ -1237,7 +1239,7 @@ refresh_status (struct app_context *ctx) { if (ctx->prefix) ctx->backend->add (ctx->backend, ctx->prefix); - if (ctx->mpd_status) ctx->backend->add (ctx->backend, ctx->mpd_status); + if (ctx->mpd_stopped) ctx->backend->add (ctx->backend, "MPD stopped"); else if (ctx->mpd_song) ctx->backend->add (ctx->backend, ctx->mpd_song); if (ctx->noise_end_time) @@ -1504,9 +1506,8 @@ mpd_on_info_response (const struct mpd_response *response, struct str_map map; mpd_vector_to_map (data, &map); - cstr_set (&ctx->mpd_status, NULL); - struct str s = str_make (); + ctx->mpd_stopped = false; const char *value; if ((value = str_map_find (&map, "state"))) @@ -1514,7 +1515,7 @@ mpd_on_info_response (const struct mpd_response *response, // Unicode approximates since in proportional fonts ASCII looks ugly // and I don't want to depend on a particular font with player chars if (!strcmp (value, "stop")) - ctx->mpd_status = xstrdup ("MPD stopped"); + ctx->mpd_stopped = true; else if (!strcmp (value, "pause")) str_append (&s, "▯▯ " /* "|| " */); else @@ -1611,6 +1612,10 @@ mpd_on_failure (void *user_data) struct app_context *ctx = user_data; print_error ("connection to MPD failed"); mpd_queue_reconnect (ctx); + + cstr_set (&ctx->mpd_song, NULL); + ctx->mpd_stopped = false; + refresh_status (ctx); } static void @@ -2064,8 +2069,19 @@ on_noise_adjust (struct app_context *ctx, int arg) if (!ctx->noise_end_time && (arg < 0 || !noise_start (ctx))) return; - // The granularity of noise playback is whole minutes - ctx->noise_end_time += arg * 60; + time_t now = time (NULL); + int diff = difftime (ctx->noise_end_time, now); + + // The granularity of noise playback setting is whole hours. + enum { SECOND = 1, MINUTE = 60, HOUR = 3600 }; + if (arg > 0) + // Add a minute to enable stepping up from 0:59 to 2:00. + diff = (diff + arg * HOUR + MINUTE) / HOUR * HOUR; + else if (arg++ < 0) + // Remove a second to enable stepping down from 2:00 to 1:00. + diff = (diff + arg * HOUR - SECOND) / HOUR * HOUR; + + ctx->noise_end_time = now + diff; on_noise_timer (ctx); } @@ -2220,9 +2236,9 @@ spawn (char *argv[]) mpd_client_idle (c, 0); \ } -// XXX: pause without argument is deprecated, we can watch play state -// if we want to have the toggle pause/play functionality -MPD_SIMPLE (play, "pause", NULL) + +MPD_SIMPLE (play, "play", NULL) +MPD_SIMPLE (toggle, "pause", NULL) MPD_SIMPLE (stop, "stop", NULL) MPD_SIMPLE (prev, "previous", NULL) MPD_SIMPLE (next, "next", NULL) @@ -2230,6 +2246,12 @@ MPD_SIMPLE (forward, "seekcur", "+10", NULL) MPD_SIMPLE (backward, "seekcur", "-10", NULL) static void +on_mpd_play_toggle (struct app_context *ctx, int arg) +{ + (ctx->mpd_stopped ? on_mpd_play : on_mpd_toggle) (ctx, arg); +} + +static void on_volume_finish (pa_context *context, int success, void *userdata) { (void) context; @@ -2426,13 +2448,13 @@ g_keys[] = // can be used to figure out which modifier is AltGr // MPD - { Mod4Mask, XK_Up, on_mpd_play, 0 }, + { Mod4Mask, XK_Up, on_mpd_play_toggle, 0 }, { Mod4Mask, XK_Down, on_mpd_stop, 0 }, { Mod4Mask, XK_Left, on_mpd_prev, 0 }, { Mod4Mask, XK_Right, on_mpd_next, 0 }, { Mod4Mask | ShiftMask, XK_Left, on_mpd_backward, 0 }, { Mod4Mask | ShiftMask, XK_Right, on_mpd_forward, 0 }, - { 0, XF86XK_AudioPlay, on_mpd_play, 0 }, + { 0, XF86XK_AudioPlay, on_mpd_play_toggle, 0 }, { 0, XF86XK_AudioPrev, on_mpd_prev, 0 }, { 0, XF86XK_AudioNext, on_mpd_next, 0 }, @@ -2481,8 +2503,8 @@ g_keys[] = { 0, XF86XK_AudioMicMute, on_volume_mic_mute, 0 }, // Noise playback - { ControlMask, XF86XK_AudioRaiseVolume, on_noise_adjust, 60 }, - { ControlMask, XF86XK_AudioLowerVolume, on_noise_adjust, -60 }, + { ControlMask, XF86XK_AudioRaiseVolume, on_noise_adjust, 1 }, + { ControlMask, XF86XK_AudioLowerVolume, on_noise_adjust, -1 }, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |