diff options
Diffstat (limited to 'sandman.m')
-rw-r--r-- | sandman.m | 111 |
1 files changed, 55 insertions, 56 deletions
diff --git a/sandman.m b/sandman.m index 94c7d1a..2e5c4db 100644 --- a/sandman.m +++ b/sandman.m @@ -1,88 +1,87 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019, 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by + * 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. * * This program 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 Affero General Public License for more details. + * GNU General Public License for more details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. */ #import <Cocoa/Cocoa.h> #import <err.h> #import <signal.h> +#import <stdio.h> #import <stdlib.h> #import <sysexits.h> #import <unistd.h> -static volatile sig_atomic_t sleeping; +typedef unsigned uint; -static void sigchld(int sig) { - (void)sig; - int status; - pid_t pid = wait(&status); - if (pid < 0) _exit(EX_OSERR); - if (WIFSIGNALED(status) && WTERMSIG(status) != SIGHUP) { - _exit(128 + WTERMSIG(status)); - } else if (!sleeping) { - _exit(WEXITSTATUS(status)); - } -} - -static pid_t spawn(char *argv[]) { - pid_t pid = fork(); +static pid_t pid; +static void spawn(char *argv[]) { + pid = fork(); if (pid < 0) err(EX_OSERR, "fork"); - if (pid) return pid; + if (pid) return; execvp(argv[0], argv); - err(EX_NOINPUT, "%s", argv[0]); + err(EX_CONFIG, "%s", argv[0]); } -static pid_t pid; +static void handler(int signal) { + (void)signal; + int status; + pid_t pid = wait(&status); + if (pid < 0) _exit(EX_OSERR); + _exit(status); +} int main(int argc, char *argv[]) { - if (argc < 2) return EX_USAGE; + uint delay = 8; + + for (int opt; 0 < (opt = getopt(argc, argv, "t:"));) { + switch (opt) { + break; case 't': delay = strtoul(optarg, NULL, 10); + break; default: return EX_USAGE; + } + } + argc -= optind; + argv += optind; + if (!argc) errx(EX_USAGE, "command required"); - sigset_t mask; - sigemptyset(&mask); - struct sigaction action = { - .sa_handler = sigchld, - .sa_mask = mask, - .sa_flags = SA_NOCLDSTOP | SA_RESTART, - }; - sigaction(SIGCHLD, &action, NULL); + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + NSNotificationCenter *notifCenter = [workspace notificationCenter]; - pid = spawn(&argv[1]); + [notifCenter addObserverForName:NSWorkspaceWillSleepNotification + object:nil + queue:nil + usingBlock:^(NSNotification *notif) { + (void)notif; + signal(SIGCHLD, SIG_IGN); + int error = kill(pid, SIGHUP); + if (error) err(EX_UNAVAILABLE, "kill"); + int status; + wait(&status); + }]; - [ - [[NSWorkspace sharedWorkspace] notificationCenter] - addObserverForName: NSWorkspaceWillSleepNotification - object: nil - queue: nil - usingBlock: ^(NSNotification *note) { - (void)note; - sleeping = 1; - int error = kill(pid, SIGHUP); - if (error) err(EX_UNAVAILABLE, "kill %d", pid); - } - ]; + [notifCenter addObserverForName:NSWorkspaceDidWakeNotification + object:nil + queue:nil + usingBlock:^(NSNotification *notif) { + (void)notif; + warnx("waiting %u seconds...", delay); + sleep(delay); + signal(SIGCHLD, handler); + spawn(argv); + }]; - [ - [[NSWorkspace sharedWorkspace] notificationCenter] - addObserverForName: NSWorkspaceDidWakeNotification - object: nil - queue: nil - usingBlock: ^(NSNotification *note) { - (void)note; - sleeping = 0; - pid = spawn(&argv[1]); - } - ]; + signal(SIGCHLD, handler); + spawn(argv); [[NSApplication sharedApplication] run]; } |