#include #include #include #include #include #include #include #include #include #include #include "ext-idle-notify-v1-protocol.h" #define LEN(X) (sizeof(X) / sizeof(X[0])) static struct ext_idle_notifier_v1 *notifier; static struct wl_compositor *compositor; static struct wl_display *display; static struct wl_registry *registry; static struct wl_seat *seat; static const struct ext_idle_notification_v1_listener idlelistener; static const struct wl_registry_listener reglistener; pid_t cpid; struct Events { uint32_t delay; /* in ms */ char **idlecmd; char **resumecmd; struct ext_idle_notification_v1 *notif; }; #include "config.h" static void die(const char *fmt, ...); static void reghandler(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version); static void idling(void *data, struct ext_idle_notification_v1 *notif); static void resuming(void *data, struct ext_idle_notification_v1 *notif); static void run(char **cmd); static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if (fmt[0] && fmt[strlen(fmt)-1] == ':') { fputc(' ', stderr); perror(NULL); } else fputc('\n', stderr); exit(1); } static void reghandler(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { if (strcmp(interface, wl_compositor_interface.name) == 0) compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1); else if (strcmp(interface, ext_idle_notifier_v1_interface.name) == 0) notifier = wl_registry_bind(registry, id, &ext_idle_notifier_v1_interface, 1); else if (strcmp(interface, wl_seat_interface.name) == 0) seat = wl_registry_bind(registry, id, &wl_seat_interface, 7); } static const struct wl_registry_listener reglistener = { .global = reghandler, }; static void idling(void *data, struct ext_idle_notification_v1 *notif) { struct Events *event = data; run(event->idlecmd); } static void resuming(void *data, struct ext_idle_notification_v1 *notif) { struct Events *event = data; run(event->resumecmd); } static const struct ext_idle_notification_v1_listener idlelistener = { .idled = idling, .resumed = resuming, }; static void run(char **cmd) { waitpid(-1, NULL, WNOHANG); if (killchild && cpid) kill(cpid, SIGINT); if (cmd && (cpid = fork()) == 0) { dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(cmd[0], cmd); die("execvp failed:"); } } int main(int argc, char *argv[]) { int i, c; while ((c = getopt(argc, argv, "hv")) != -1) { switch (c) { case 'v': die("%s-%s", argv[0], VERSION); break; case 'h': default: die("usage: %s [-hv]", argv[0]); break; } } display = wl_display_connect(NULL); if (!display) die("%s: failed to connect to wayland display :(", argv[0]); registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®listener, NULL); wl_display_roundtrip(display); if (!compositor || !notifier || !seat) die("%s: compositor doesn't support all necessary protocols", argv[0]); /* register all events */ for (i = 0; i < LEN(events); i++) { if (events[i].delay < 0) continue; events[i].notif = ext_idle_notifier_v1_get_idle_notification(notifier, events[i].delay, seat); ext_idle_notification_v1_add_listener(events[i].notif, &idlelistener, &events[i]); } wl_display_roundtrip(display); while (wl_display_dispatch(display) != -1); ext_idle_notifier_v1_destroy(notifier); wl_registry_destroy(registry); wl_display_destroy(display); wl_compositor_destroy(compositor); }