From 30bea0c6c1b068cd00dc3429cffeeed3c6766b43 Mon Sep 17 00:00:00 2001 From: Squibid Date: Sat, 30 Mar 2024 14:55:57 -0400 Subject: initial commit --- .gitignore | 3 + Makefile | 62 +++++++++++++++++ waytils.1 | 46 +++++++++++++ waytils.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 341 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 waytils.1 create mode 100644 waytils.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8151d43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*-protocol.* +*.o +waytils diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e85901a --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +PKG_CONFIG = pkg-config +VERSION = 0.1 + +# flags and incs +PKGS = wayland-client wayland-server +CFLAGS = -DVERSION=\"$(VERSION)\" -Wall +LIBS = `$(PKG_CONFIG) --libs $(PKGS)` + +PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man + +# compiler and linker +CC = cc + +# wayland-scanner is a tool which generates C headers and rigging for Wayland +# protocols, which are specified in XML. wlroots requires you to rig these up +# to your build system yourself and provide them in the include path. +WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` +WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner` + +all: zwp-idle-inhibit-manager-v1-protocol.o xdg-shell-client-protocol.o ext-idle-notify-v1-protocol.o waytils +waytils: waytils.o + $(CC) -o $@ *.o $(CFLAGS) $(LIBS) +waytils.o: waytils.c +zwp-idle-inhibit-manager-v1-protocol.o: zwp-idle-inhibit-manager-v1-protocol.c zwp-idle-inhibit-manager-v1-protocol.h +xdg-shell-client-protocol.o: xdg-shell-client-protocol.c xdg-shell-client-protocol.h +ext-idle-notify-v1-protocol.o: ext-idle-notify-v1-protocol.c ext-idle-notify-v1-protocol.h + +zwp-idle-inhibit-manager-v1-protocol.h: + $(WAYLAND_SCANNER) client-header \ + $(WAYLAND_PROTOCOLS)/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml $@ +zwp-idle-inhibit-manager-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml $@ + +xdg-shell-client-protocol.h: + $(WAYLAND_SCANNER) client-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +xdg-shell-client-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ + +ext-idle-notify-v1-protocol.h: + $(WAYLAND_SCANNER) client-header \ + $(WAYLAND_PROTOCOLS)/staging/ext-idle-notify/ext-idle-notify-v1.xml $@ +ext-idle-notify-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/staging/ext-idle-notify/ext-idle-notify-v1.xml $@ + +clean: + rm -f waytils *.o *-protocol.* + +install: waytils + mkdir -p $(PREFIX)/bin + cp -f waytils $(PREFIX)/bin + chmod 755 $(PREFIX)/bin/waytils + mkdir -p $(MANDIR)/man1 + cp -f waytils.1 $(MANDIR)/man1 + chmod 644 $(MANDIR)/man1/waytils.1 + +uninstall: waytils + rm -f $(PREFIX)/bin/waytils $(MANDIR)/man1/waytils.1 diff --git a/waytils.1 b/waytils.1 new file mode 100644 index 0000000..5f688f5 --- /dev/null +++ b/waytils.1 @@ -0,0 +1,46 @@ +.Dd February 16, 2024 +.Dt WAYTILS 1 +.Sh NAME +.Nm waytils +.Nd information about the current wayland session +.Os +.Sh SYNOPSIS +.Nm +.Op Fl v +.Op Fl h +.Sh DESCRIPTION +.Nm +is a small program to check information about the current wayland session. +.Nm +requires a compositor that implements the following protocols: +.TS +tab(;) allbox; +c;c. + Protocol; Version +Idle Inhibit; 1 +XDG Shell Client; 1 +Idle Notify; 1 +.TE +.Sh OPTIONS +.Pp +When given the +.Fl v +option, +.Nm +writes it's name and version to standard error and exits with a return value of +1. +.Pp +When given the +.Fl h +option, +.Nm +displays some information about flags to standard error and exits with a return +.Pp +When given the +.Fl f +option, +.Nm +forks into the background, and the parent process returns 0 +value of 1. +.Sh BUGS +Works on my machine. diff --git a/waytils.c b/waytils.c new file mode 100644 index 0000000..d50af85 --- /dev/null +++ b/waytils.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "zwp-idle-inhibit-manager-v1-protocol.h" +#include "ext-idle-notify-v1-protocol.h" +#include "xdg-shell-client-protocol.h" + +#define LEN(X) (sizeof(X) / sizeof(X[0])) + +static struct wl_compositor *compositor; +static struct wl_display *display; +static struct wl_registry *registry; +static struct wl_surface *surface; +static struct wl_seat *seat; + +static struct xdg_surface *xdgsurface; +static struct xdg_wm_base *base; +static struct xdg_toplevel *toplevel; + +static struct zwp_idle_inhibitor_v1 *inhibitor; +static struct zwp_idle_inhibit_manager_v1 *inhibitmanager; + +static struct ext_idle_notification_v1 *notif; +static struct ext_idle_notifier_v1 *notifier; + +static int subcommand = -1; +enum { INSOMNAIC, INHIBITCHECK, PROTOCOLS }; + +static void die(const char *fmt, ...); +static void pong(void *data, struct xdg_wm_base *base, uint32_t serial); +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 interrupt(); + +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 +pong(void *data, struct xdg_wm_base *base, uint32_t serial) +{ + xdg_wm_base_pong(base, serial); +} + +static const struct xdg_wm_base_listener xdglistener = { + .ping = pong, +}; + +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, xdg_wm_base_interface.name) == 0) { + base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(base, &xdglistener, NULL); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, id, &wl_seat_interface, 7); + } else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) { + if (subcommand == INSOMNAIC) { + inhibitmanager = wl_registry_bind(registry, id, + &zwp_idle_inhibit_manager_v1_interface, 1); + } + } else if (strcmp(interface, ext_idle_notifier_v1_interface.name) == 0) { + if (subcommand == INHIBITCHECK) { + notifier = wl_registry_bind(registry, id, &ext_idle_notifier_v1_interface, 1); + } + } + if (subcommand == PROTOCOLS) + fprintf(stdout, "%s (%d)\n", interface, version); +} + +static const struct wl_registry_listener reglistener = { + .global = reghandler, +}; + +static void +idling(void *data, struct ext_idle_notification_v1 *notif) +{ + printf("No idle inhibitor found :)\n"); + exit(0); +} + +static void +interrupt() +{ + printf("Idle inhibitor found :(\n"); + exit(1); +} + +static const struct ext_idle_notification_v1_listener idlelistener = { + .idled = idling, +}; + +int +main(int argc, char *argv[]) +{ + int i, c; + struct timeval start, end; + pid_t pid; + + while ((c = getopt(argc, argv, "hvf")) != -1) { + switch (c) { + case 'v': die("%s-%s", argv[0], VERSION); break; + case 'f': + if (fork() != 0) + exit(0); + break; + case 'h': + default: die("usage: %s [-hvf]", argv[0]); break; + } + } + + for (i = 0; i < argc; i++) { + if (strcmp("insomniac", argv[i]) == 0) { + fprintf(stderr, "Adding an idle lock on the compositor\n"); + subcommand = INSOMNAIC; + } else if (strcmp("inhibitcheck", argv[i]) == 0) { + fprintf(stderr, "Checking for an idle inhibitor\n"); + subcommand = INHIBITCHECK; + } else if (strcmp("protocols", argv[i]) == 0) { + fprintf(stderr, "Checking for protocols\n"); + subcommand = PROTOCOLS; + } else if (argv[i] == argv[argc - 1]) { + fprintf(stderr, "No valid command specified\n"); + exit(-1); + } + } + + /* get the parent process pid to make killing it easier later */ + pid = getpid(); + + /* setup wayland stuff */ + 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 (subcommand == PROTOCOLS) + exit(0); + if (!compositor || !seat) + die("%s: compositor doesn't meet necesary protocols", argv[0]); + if (!notifier && subcommand == INHIBITCHECK) + die("%s: compositor doesn't support the idle notify protocol", argv[0]); + if (!inhibitmanager && subcommand == INSOMNAIC) + die("%s: compositor doesn't support the inhibit manager protocol", argv[0]); + + /* register event */ + if (subcommand == INHIBITCHECK) { + notif = ext_idle_notifier_v1_get_idle_notification(notifier, 1, seat); + ext_idle_notification_v1_add_listener(notif, &idlelistener, NULL); + + /* event should be registered now get starting time so we can end command + * if we should've seen the idle event by now */ + gettimeofday(&start, NULL); + } + wl_display_roundtrip(display); + + surface = wl_compositor_create_surface(compositor); + xdgsurface = xdg_wm_base_get_xdg_surface(base, surface); + toplevel = xdg_surface_get_toplevel(xdgsurface); + + wl_display_roundtrip(display); + wl_surface_commit(surface); + + /* register stuff */ + switch (subcommand) { + case INSOMNAIC: + inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(inhibitmanager, surface); + break; + case INHIBITCHECK: + /* check in a seperate thread so wayland doesn't block or get blocked */ + if (fork() == 0) + while (1) { + gettimeofday(&end, NULL); + /* check if the program has been running for 10 milliseconds, and then + * terminate because at this point we should've seen an idle event */ + if (end.tv_usec - start.tv_usec > 10000) { + kill(pid, SIGPOLL); + exit(1); + } + } + + /* listen for the SIGPOLL signal */ + signal(SIGPOLL, interrupt); + break; + } + wl_display_roundtrip(display); + + /* start listening for wayland events */ + while (wl_display_dispatch(display) != -1); + + /* cleanup time */ + if (subcommand == INSOMNAIC) + zwp_idle_inhibitor_v1_destroy(inhibitor); + zwp_idle_inhibit_manager_v1_destroy(inhibitmanager); + ext_idle_notifier_v1_destroy(notifier); + wl_registry_destroy(registry); + wl_display_destroy(display); + wl_compositor_destroy(compositor); +} -- cgit v1.2.1