Compare commits

...

34 Commits

Author SHA1 Message Date
f26cfd3bb5 wmstatus: don't spam X session logs without MPD
All checks were successful
Alpine 3.21 Success
OpenBSD 7.6 Success
Allow and default to setting the MPD address to null.
2025-08-10 00:22:22 +02:00
f2ec611c26 Add genpass: a tool to generate passwords
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
2025-03-31 21:06:21 +02:00
5b64c639ac CMakeLists.txt: don't enforce setuid bit
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
2024-11-25 06:12:20 +01:00
8096a1b2c9 Move elksmart-comm to another repository 2024-11-25 03:31:07 +01:00
bb4fdcd936 wmstatus: fix noise adjustment logic
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
It was possible to trigger an untracked playback stream.
2024-10-12 15:36:34 +02:00
d06beedcaa CMakeLists.txt: install optional targets
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
2024-10-12 14:20:31 +02:00
dc3f0d6d05 elksmart-comm: add support for EKX5S-T
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
This device seems to be very picky about USB ports,
but at least learning is reliable,
and it uses the same protocol as EKX4S.
2024-10-12 14:02:30 +02:00
9e91058ed9 Add elksmart-comm for transceiving infrared codes
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
The receive functionality is quite unstable,
however useful enough for something that is officially unsupported.

The gadget is picky about cables,
but it has ridiculous reach when it works.
2024-08-30 02:55:35 +02:00
fbc7454647 wmstatus: cleanup 2024-08-10 08:51:43 +02:00
94bc8c251c wmstatus: improve Sway forwards of xkb-lock-group
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
2024-08-08 14:58:02 +02:00
e83cfa3c15 Fix calloc argument order, add some consts 2024-08-08 14:39:28 +02:00
29c89942ce Bump liberty
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
2024-08-08 08:58:36 +02:00
9042aeaa93 wmstatus: fix the binding parser
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
2024-08-07 18:30:46 +02:00
180b16faee wmstatus: add an option to import bindings to Sway
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
We still want to retain the ability to bind them on our own under X11.

With this, the Wayland situation has considerably improved,
but the activity watch and keyboard layout switching are still broken.
2024-08-07 17:01:35 +02:00
674ea6d9a6 wmstatus: add IPC capabilities
All checks were successful
Alpine 3.20 Success
OpenBSD 7.5 Success
And remove the odd prefix functionality.
2024-08-07 12:32:33 +02:00
9ccdc3430c wmstatus: make bindings configurable 2024-08-07 11:51:14 +02:00
4a22708f52 wmstatus: move to libertyconf 2024-08-07 11:51:14 +02:00
128ef14c39 wmstatus: round in noise playback setting
All checks were successful
Alpine 3.19 Success
OpenBSD 7.3 Success
2024-04-17 00:42:55 +02:00
9def673a2b Install some binaries with the setuid bit
All checks were successful
Alpine 3.19 Success
OpenBSD 7.3 Success
2024-03-27 08:26:49 +01:00
36df9cc6c9 Fix gdm-switch-user build 2024-02-25 01:56:09 +01:00
d97a6e3f16 Bump liberty 2024-02-24 00:39:50 +01:00
e073fc400e wmstatus: MPD play/toggle 2024-02-24 00:39:50 +01:00
fefeb242ae wmstatus-weather.pl: fix weather icons
The API seems to have been removed entirely.
2024-01-19 04:31:52 +01:00
37b6ce3560 wmstatus: try a bit harder to get openat() 2023-07-24 09:56:07 +02:00
5c32057c42 wmstatus: fix an OpenBSD build warning
Note that _GNU_SOURCE is there to imply _DEFAULT_SOURCE, for BYTE_ORDER.
2023-07-04 07:24:24 +02:00
87e5285622 Don't install orphan supplementary files 2023-07-04 02:46:33 +02:00
7e30dfb6f0 iexec: enable not exitting together with the child 2023-06-19 19:06:37 +02:00
4cc1baf429 iexec: enable watching a different path 2023-06-19 19:06:16 +02:00
957aed63a8 iexec: cleanup 2023-06-19 19:06:08 +02:00
59b78ebc5c Bump liberty 2023-06-19 17:10:31 +02:00
c291e4b6ac input-switch: enable requesting current values 2022-07-25 22:41:03 +02:00
81c3c9ec3f wmstatus: skip offline power supplies 2022-02-01 22:37:34 +01:00
fbc1f18393 Improve iexec's self-description 2021-12-30 03:21:01 +01:00
4cad7806ab CMakeLists.txt: improve portability
Also, stop lying in the README that this is present in AUR.
2021-11-07 17:21:27 +01:00
14 changed files with 1249 additions and 355 deletions

View File

@@ -16,30 +16,52 @@ set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/liberty/cmake)
include (AddThreads)
find_package (PkgConfig REQUIRED)
pkg_check_modules (dependencies REQUIRED libpulse x11 xext xextproto dbus-1)
pkg_check_modules (x REQUIRED x11 xext xextproto)
pkg_check_modules (pulse REQUIRED libpulse)
pkg_check_modules (dbus REQUIRED dbus-1)
pkg_check_modules (gdm gdm glib-2.0 gio-2.0)
include_directories (${dependencies_INCLUDE_DIRS})
include_directories (
${x_INCLUDE_DIRS} ${pulse_INCLUDE_DIRS} ${dbus_INCLUDE_DIRS})
link_directories (
${x_LIBRARY_DIRS} ${pulse_LIBRARY_DIRS} ${dbus_LIBRARY_DIRS})
option (WITH_GDM "Compile with GDM support" ${gdm_FOUND})
option (WITH_GDM "Compile with GDM utilities" ${gdm_FOUND})
# Generate a configuration file
configure_file (${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h)
configure_file (${PROJECT_SOURCE_DIR}/config.h.in
${PROJECT_BINARY_DIR}/config.h)
include_directories (${PROJECT_BINARY_DIR})
# Build
foreach (name brightness fancontrol-ng iexec input-switch priod siprandom)
set (targets wmstatus paswitch siprandom genpass)
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)
# Only iexec could be made to use kqueue
list (APPEND targets fancontrol-ng priod iexec)
elseif ("${CMAKE_SYSTEM_NAME}" MATCHES BSD)
# Need this for SIGWINCH in FreeBSD and OpenBSD respectively;
# our POSIX version macros make it undefined
add_definitions (-D__BSD_VISIBLE=1 -D_BSD_SOURCE=1)
elseif (APPLE)
add_definitions (-D_DARWIN_C_SOURCE)
endif ()
foreach (name big-brother ${targets})
add_executable (${name} ${name}.c)
endforeach ()
foreach (name big-brother paswitch wmstatus)
add_executable (${name} ${name}.c)
target_link_libraries (${name} ${dependencies_LIBRARIES})
endforeach ()
target_link_libraries (big-brother ${x_LIBRARIES})
target_link_libraries (paswitch ${pulse_LIBRARIES})
target_link_libraries (wmstatus
${x_LIBRARIES} ${pulse_LIBRARIES} ${dbus_LIBRARIES})
add_threads (wmstatus)
if (WITH_GDM)
include_directories (${gdm_INCLUDE_DIRS})
list (APPEND targets gdm-switch-user)
add_executable (gdm-switch-user gdm-switch-user.c)
target_include_directories (gdm-switch-user PUBLIC ${gdm_INCLUDE_DIRS})
target_link_directories (gdm-switch-user PUBLIC ${gdm_LIBRARY_DIRS})
target_link_libraries (gdm-switch-user ${gdm_LIBRARIES})
endif ()
@@ -50,28 +72,44 @@ 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)
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)
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}")
# 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 ()
install (TARGETS wmstatus paswitch brightness input-switch fancontrol-ng priod
iexec siprandom DESTINATION ${CMAKE_INSTALL_BINDIR})
# These should be accessible by users, but need to touch system devices.
# Use the setuid bit, for simplicity.
set (SETUID "SETUID" CACHE STRING "Set this empty on permission issues")
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})

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015 - 2021, Přemysl Eric Janouch <p@janouch.name>
Copyright (c) 2015 - 2025, 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.

View File

@@ -28,17 +28,17 @@ to other people as well:
- 'big-brother' tracks the title of the active window and the idle state of
the user and writes these events to standard output.
Don't expect them to work under any OS that isn't Linux.
Few of them are useful outside of Linux.
Packages
--------
Regular releases are sporadic. git master should be stable enough. You can get
a package with the latest development version from Archlinux's AUR.
Regular releases are sporadic. git master should be stable enough.
Building
--------
Build dependencies: CMake, pkg-config, liberty (included) +
Runtime dependencies: libpulse, libx11, dbus-1, libgdm (optional)
Runtime dependencies: libpulse, libx11, dbus-1 +
Optional runtime dependencies: libgdm (gdm-switch-user)
$ git clone --recursive https://git.janouch.name/p/desktop-tools.git
$ mkdir desktop-tools/build

View File

@@ -46,7 +46,7 @@ log_message_custom (void *user_data, const char *quote, const char *fmt,
static void
wait_ms (long ms)
{
struct timespec ts = { 0, ms * 1000 * 1000 };
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep (&ts, NULL);
}

View File

@@ -124,7 +124,7 @@ config_validate_nonnegative (const struct config_item *item, struct error **e)
return error_set (e, "must be non-negative");
}
static struct config_schema g_config_device[] =
static const struct config_schema g_config_device[] =
{
{ .name = "name",
.comment = "Device identifier",
@@ -137,7 +137,7 @@ static struct config_schema g_config_device[] =
{}
};
static struct config_schema g_config_pwm[] =
static const struct config_schema g_config_pwm[] =
{
{ .name = "temp",
.comment = "Path to temperature sensor output",
@@ -415,7 +415,7 @@ device_create (struct app_context *ctx, const char *path,
// There is no room for errors in the configuration, everything must be valid.
// Thus the reset to defaults on invalid values is effectively disabled here.
static bool
apply_schema (struct config_schema *schema, struct config_item *object,
apply_schema (const struct config_schema *schema, struct config_item *object,
struct error **e)
{
struct error *warning = NULL, *error = NULL;
@@ -445,7 +445,7 @@ static bool
check_device_configuration (struct config_item *subtree, struct error **e)
{
// Check regular fields in the device object
for (struct config_schema *s = g_config_device; s->name; s++)
for (const struct config_schema *s = g_config_device; s->name; s++)
if (!apply_schema (s, subtree, e))
return false;
@@ -465,7 +465,7 @@ check_device_configuration (struct config_item *subtree, struct error **e)
while ((pwm = str_map_iter_next (&iter)))
{
const char *subpath = iter.link->key;
for (struct config_schema *s = g_config_pwm; s->name; s++)
for (const struct config_schema *s = g_config_pwm; s->name; s++)
if (!apply_schema (s, pwm, &error))
{
error_set (e, "PWM `%s': %s", subpath, error->message);

View File

@@ -1,5 +1,5 @@
// Public domain
#include <gdm-user-switching.h>
#include <gdm/gdm-user-switching.h>
int
main (int argc, char *argv[])

151
genpass.c Normal file
View File

@@ -0,0 +1,151 @@
/*
* genpass.c: password generator
*
* Copyright (c) 2025, 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.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "config.h"
#undef PROGRAM_NAME
#define PROGRAM_NAME "genpass"
#include "liberty/liberty.c"
static struct str
parse_group (const char *group)
{
bool present[0x100] = {};
for (size_t i = 0; group[i]; i++)
{
unsigned char c = group[i];
if (!i || c != '-' || !group[i + 1])
present[c] = true;
else if (group[i + 1] < group[i - 1])
exit_fatal ("character ranges must be increasing");
else
for (c = group[i - 1]; ++c <= group[i + 1]; )
present[c] = true;
}
struct str alphabet = str_make ();
for (size_t i = 1; i < N_ELEMENTS (present); i++)
if (present[i])
str_append_c (&alphabet, i);
if (!alphabet.len)
exit_fatal ("empty group");
return alphabet;
}
static void
parse_program_arguments (int argc, char **argv,
unsigned long *length, struct strv *groups, struct str *alphabet)
{
static const struct opt opts[] =
{
{ 'l', "length", "CHARACTERS", 0, "set password length" },
{ '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" },
{ 0, NULL, NULL, 0, NULL }
};
struct opt_handler oh =
opt_handler_make (argc, argv, opts, "GROUP...", "Password generator.");
int c;
while ((c = opt_handler_get (&oh)) != -1)
switch (c)
{
case 'l':
if (!xstrtoul (length, optarg, 10) || *length <= 0)
print_fatal ("invalid length argument");
break;
case 'd':
g_debug_mode = true;
break;
case 'h':
opt_handler_usage (&oh, stdout);
exit (EXIT_SUCCESS);
case 'V':
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
exit (EXIT_SUCCESS);
default:
print_error ("wrong options");
opt_handler_usage (&oh, stderr);
exit (EXIT_FAILURE);
}
argc -= optind;
argv += optind;
for (int i = 0; i < argc; i++)
{
struct str alphabet = parse_group (argv[i]);
strv_append_owned (groups, str_steal (&alphabet));
}
bool present[0x100] = {};
for (size_t i = 0; i < groups->len; i++)
for (size_t k = 0; groups->vector[i][k]; k++)
{
unsigned char c = groups->vector[i][k];
if (present[c])
exit_fatal ("groups are not disjunct");
present[c] = true;
}
for (size_t i = 1; i < N_ELEMENTS (present); i++)
if (present[i])
str_append_c (alphabet, i);
if (groups->len > *length)
exit_fatal ("the requested length is less than the number of groups");
if (!groups->len)
{
opt_handler_usage (&oh, stderr);
exit (EXIT_FAILURE);
}
opt_handler_free (&oh);
}
int
main (int argc, char *argv[])
{
unsigned long length = 8;
struct strv groups = strv_make ();
struct str alphabet = str_make ();
parse_program_arguments (argc, argv, &length, &groups, &alphabet);
unsigned seed = 0;
if (!random_bytes (&seed, sizeof seed, NULL))
exit_fatal ("failed to initialize random numbers");
srand (seed);
// Select from a joined alphabet, but make sure all groups are represented.
struct str candidate = str_make ();
while (true)
{
restart:
for (size_t i = length; i--; )
str_append_c (&candidate, alphabet.str[rand () % alphabet.len]);
for (size_t i = 0; i < groups.len; i++)
if (!strpbrk (candidate.str, groups.vector[i]))
{
str_reset (&candidate);
goto restart;
}
printf ("%s\n", candidate.str);
return 0;
}
}

121
iexec.c
View File

@@ -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_inotify_event (const struct inotify_event *e, const char *base)
{
if (e->wd != g.inotify_wd || strcmp (e->name, base))
return;
if (g.child)
{
print_debug ("file changed, killing child");
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; 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;
print_debug ("file changed, killing child");
g_restarting = true;
if (kill (g_child, SIGINT))
print_error ("kill: %s", strerror (errno));
}
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" },
@@ -102,7 +124,7 @@ main (int argc, char *argv[])
};
struct opt_handler oh = opt_handler_make (argc, argv, opts,
"PROGRAM [ARG...]", "Run a program and restart on file change.");
"PROGRAM [ARG...]", "Run a program and restart it when it changes.");
// We have to turn that off as it causes more trouble than what it's worth
cstr_set (&oh.opt_string, xstrdup_printf ("+%s", oh.opt_string));
@@ -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;
}

View File

@@ -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,10 +28,59 @@
#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)
{
@@ -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))

Submodule liberty updated: 782a9a5977...75fc6f1c37

View File

@@ -290,7 +290,7 @@ on_sink_info (pa_context *context, const pa_sink_info *info, int eol,
sink->ports_len++;
struct port *port = sink->ports =
xcalloc (sizeof *sink->ports, sink->ports_len);
xcalloc (sink->ports_len, sizeof *sink->ports);
for (struct pa_sink_port_info **iter = info->ports; *iter; iter++)
{
port->name = xstrdup ((*iter)->name);

View File

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

1062
wmstatus.c

File diff suppressed because it is too large Load Diff

63
wmstatus.conf.example Normal file
View File

@@ -0,0 +1,63 @@
# vim: set ft=libertyconf:
keys = {
# This key should be labeled L on normal Qwert[yz] layouts
"Mod4 n" = "exec dm-tool lock" # gdm-switch-user
# xmodmap grep -e Alt_R -e Meta_R -e ISO_Level3_Shift -e Mode_switch
# can be used to figure out which modifier is AltGr
"Mod4 Up" = "mpd-play-toggle"
"Mod4 Down" = "mpd stop"
"Mod4 Left" = "mpd previous"
"Mod4 Right" = "mpd next"
"Mod4 Shift Left" = "mpd seekcur -10"
"Mod4 Shift Right" = "mpd seekcur +10"
"XF86AudioPlay" = "mpd-play-toggle"
"XF86AudioPrev" = "mpd previous"
"XF86AudioNext" = "mpd next"
"Mod4 F1" = "xkb-lock-group 0"
"Mod4 F2" = "xkb-lock-group 1"
"Mod4 F3" = "xkb-lock-group 2"
"Mod4 F4" = "xkb-lock-group 3"
"Mod4 Control F1" = "exec input-switch vga 1"
"Mod4 Control Shift F1" = "exec input-switch vga 2"
"Mod4 Control F2" = "exec input-switch dvi 1"
"Mod4 Control Shift F2" = "exec input-switch dvi 2"
"Mod4 Control F3" = "exec input-switch hdmi 1"
"Mod4 Control Shift F3" = "exec input-switch hdmi 2"
"Mod4 Control F4" = "exec input-switch dp 1"
"Mod4 Control Shift F4" = "exec input-switch dp 2"
"Mod4 Home" = "exec brightness +10"
"Mod4 End" = "exec brightness -10"
"XF86MonBrightnessUp" = "exec brightness +10"
"XF86MonBrightnessDown" = "exec brightness -10"
# We need to wait a little while until user releases the key
"Mod4 F5" = "exec sh -c 'sleep 1; xset dpms force standby'"
"Mod4 Shift F5" = "insomnia"
"Mod4 Pause" = "exec sh -c 'sleep 1; xset dpms force standby'"
"Mod4 Shift Pause" = "insomnia"
"Mod4 Insert" = "audio-switch"
"Mod4 Delete" = "audio-mute"
"Mod4 Shift Delete" = "audio-mic-mute"
"Mod4 Page_Up" = "audio-volume +5"
"Mod4 Shift Page_Up" = "audio-volume +1"
"Mod4 Page_Down" = "audio-volume -5"
"Mod4 Shift Page_Down" = "audio-volume -1"
" XF86AudioRaiseVolume" = "audio-volume +5"
"Shift XF86AudioRaiseVolume" = "audio-volume +1"
" XF86AudioLowerVolume" = "audio-volume -5"
"Shift XF86AudioLowerVolume" = "audio-volume -1"
" XF86AudioMute" = "audio-mute"
" XF86AudioMicMute" = "audio-mic-mute"
"Control XF86AudioRaiseVolume" = "noise-adjust +1"
"Control XF86AudioLowerVolume" = "noise-adjust -1"
# Turns on or off Pioneer integrated amplifiers
"Mod4 Control Delete" = "exec elksmart-comm --nec A538"
}