summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore3
-rw-r--r--Makefile62
-rw-r--r--waytils.146
-rw-r--r--waytils.c230
4 files changed, 341 insertions, 0 deletions
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 <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/timerfd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <wayland-client.h>
+#include <wayland-server.h>
+
+#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, &reglistener, 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);
+}