redshift: Add hooks for user actions on period switch
Hooks are executable scripts in ~/.config/redshift/hooks/ that
are run when a certain event happens. The first parameter to the
script indicates the event and further parameters may indicate
more details about the event.
The event "period-changed" is indicated when the period changes
("night", "daytime", "transition"). The second parameter is the old
period and the third is the new period. The event is signaled when
Redshift starts up with the old period set to "none".
This commit is contained in:
@@ -15,6 +15,7 @@ redshift_SOURCES = \
|
||||
location-manual.c location-manual.h \
|
||||
solar.c solar.h \
|
||||
systemtime.c systemtime.h \
|
||||
hooks.c hooks.h \
|
||||
gamma-dummy.c gamma-dummy.h
|
||||
|
||||
EXTRA_redshift_SOURCES = \
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/* hooks.c -- Hooks triggered by events
|
||||
This file is part of Redshift.
|
||||
|
||||
Redshift is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Redshift is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright (c) 2014 Jon Lund Steffensen <jonlst@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifndef _WIN32
|
||||
# include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include "hooks.h"
|
||||
#include "redshift.h"
|
||||
|
||||
#define MAX_HOOK_PATH 4096
|
||||
|
||||
|
||||
/* Names of periods supplied to scripts. */
|
||||
static const char *period_names[] = {
|
||||
"none",
|
||||
"daytime",
|
||||
"night",
|
||||
"transition"
|
||||
};
|
||||
|
||||
|
||||
/* Try to open the directory containing hooks. HP is a string
|
||||
of MAX_HOOK_PATH length that will be filled with the path
|
||||
of the returned directory. */
|
||||
static DIR *
|
||||
open_hooks_dir(char *hp)
|
||||
{
|
||||
char *env;
|
||||
|
||||
if ((env = getenv("XDG_CONFIG_HOME")) != NULL &&
|
||||
env[0] != '\0') {
|
||||
snprintf(hp, MAX_HOOK_PATH, "%s/redshift/hooks", env);
|
||||
return opendir(hp);
|
||||
}
|
||||
|
||||
if ((env = getenv("HOME")) != NULL &&
|
||||
env[0] != '\0') {
|
||||
snprintf(hp, MAX_HOOK_PATH, "%s/.config/redshift/hooks", env);
|
||||
return opendir(hp);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
struct passwd *pwd = getpwuid(getuid());
|
||||
snprintf(hp, MAX_HOOK_PATH, "%s/.config/redshift/hooks", pwd->pw_dir);
|
||||
return opendir(hp);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Run hooks with a signal that the period changed. */
|
||||
void
|
||||
hooks_signal_period_change(period_t prev_period, period_t period)
|
||||
{
|
||||
char hooksdir_path[MAX_HOOK_PATH];
|
||||
DIR *hooks_dir = open_hooks_dir(hooksdir_path);
|
||||
if (hooks_dir == NULL) return;
|
||||
|
||||
struct dirent* ent;
|
||||
while ((ent = readdir(hooks_dir)) != NULL) {
|
||||
/* Skip hidden and special files (., ..) */
|
||||
if (ent->d_name[0] == '\0' || ent->d_name[0] == '.') continue;
|
||||
|
||||
char *hook_name = ent->d_name;
|
||||
char hook_path[MAX_HOOK_PATH];
|
||||
snprintf(hook_path, sizeof(hook_path), "%s/%s",
|
||||
hooksdir_path, hook_name);
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Fork and exec the hook. We close stdout
|
||||
so the hook cannot interfere with the normal
|
||||
output. */
|
||||
pid_t pid = fork();
|
||||
if (pid == (pid_t)-1) {
|
||||
perror("fork");
|
||||
continue;
|
||||
} else if (pid == 0) { /* Child */
|
||||
close(STDOUT_FILENO);
|
||||
|
||||
int r = execl(hook_path, hook_name,
|
||||
"period-changed",
|
||||
period_names[prev_period],
|
||||
period_names[period], NULL);
|
||||
if (r < 0 && errno != EACCES) perror("execl");
|
||||
|
||||
/* Only reached on error */
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/* hooks.h -- Hooks triggered by events
|
||||
This file is part of Redshift.
|
||||
|
||||
Redshift is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Redshift is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright (c) 2014 Jon Lund Steffensen <jonlst@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef REDSHIFT_HOOKS_H
|
||||
#define REDSHIFT_HOOKS_H
|
||||
|
||||
#include "redshift.h"
|
||||
|
||||
void hooks_signal_period_change(period_t prev_period,
|
||||
period_t period);
|
||||
|
||||
|
||||
#endif /* ! REDSHIFT_HOOKS_H */
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "config-ini.h"
|
||||
#include "solar.h"
|
||||
#include "systemtime.h"
|
||||
#include "hooks.h"
|
||||
|
||||
|
||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
@@ -1422,6 +1423,18 @@ main(int argc, char *argv[])
|
||||
perror("sigaction");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Ignore CHLD signal. This causes child processes
|
||||
(hooks) to be reaped automatically. */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigact.sa_mask = sigset;
|
||||
sigact.sa_flags = 0;
|
||||
|
||||
r = sigaction(SIGCHLD, &sigact, NULL);
|
||||
if (r < 0) {
|
||||
perror("sigaction");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif /* HAVE_SIGNAL_H && ! __WIN32__ */
|
||||
|
||||
if (verbose) {
|
||||
@@ -1517,6 +1530,12 @@ main(int argc, char *argv[])
|
||||
print_period(period, transition);
|
||||
}
|
||||
|
||||
/* Activate hooks if period changed */
|
||||
if (period != prev_period) {
|
||||
hooks_signal_period_change(prev_period,
|
||||
period);
|
||||
}
|
||||
|
||||
/* Ongoing short transition */
|
||||
if (short_trans_delta) {
|
||||
/* Calculate alpha */
|
||||
|
||||
Reference in New Issue
Block a user