/* Copyright (C) 2019 C. McEnroe * * 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 * 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. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #import #import #import #import #import #import static volatile sig_atomic_t sleeping; 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(); if (pid < 0) err(EX_OSERR, "fork"); if (pid) return pid; execvp(argv[0], argv); err(EX_NOINPUT, "%s", argv[0]); } static pid_t pid; int main(int argc, char *argv[]) { if (argc < 2) return EX_USAGE; sigset_t mask; sigemptyset(&mask); struct sigaction action = { .sa_handler = sigchld, .sa_mask = mask, .sa_flags = SA_NOCLDSTOP | SA_RESTART, }; sigaction(SIGCHLD, &action, NULL); pid = spawn(&argv[1]); [ [[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); } ]; [ [[NSWorkspace sharedWorkspace] notificationCenter] addObserverForName: NSWorkspaceDidWakeNotification object: nil queue: nil usingBlock: ^(NSNotification *note) { (void)note; sleeping = 0; pid = spawn(&argv[1]); } ]; [[NSApplication sharedApplication] run]; }