commit 1e631b46b0575ff95e1d8cb091abe7a0e8e15ecd
parent 82cb7d852e77800c94cc577e793a11ef1e8f9d49
Author: mtmn <miro@haravara.org>
Date: Wed, 6 May 2026 22:00:18 +0200
feat: add monofetch
Diffstat:
6 files changed, 748 insertions(+), 0 deletions(-)
diff --git a/monofetch/BUILD b/monofetch/BUILD
@@ -0,0 +1,27 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary")
+load("@rules_shell//shell:sh_binary.bzl", "sh_binary")
+load("@rules_shell//shell:sh_library.bzl", "sh_library")
+load("//bazel:local-deploy.bzl", "local_deploy")
+
+package(default_visibility = ["//visibility:public"])
+
+# sh_library(
+# name = "saturn",
+# data = [
+# ":saturn_common",
+# ":saturn_fetch_tracks",
+# ":saturn_make_cover",
+# ],
+# )
+
+sh_binary(
+ name = "monofetch",
+ srcs = ["monofetch.sh"],
+)
+
+local_deploy(
+ name = "deploy",
+ srcs = [
+ ":monofetch",
+ ],
+)
diff --git a/monofetch/monofetch.sh b/monofetch/monofetch.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+
+if [[ -n "$1" ]]; then
+ url="$1"
+else
+ wl_focused_title="$(wlr-river-title)"
+ if [[ "$wl_focused_title" == *"Mozilla Firefox"* ]]; then
+ /usr/bin/wtype "yy" && sleep 0.5
+ url=$(wl-paste 2>/dev/null)
+ else
+ notify-send -u critical "Error" "Focused window is not a web browser ($wl_focused_title)"
+ exit 1
+ fi
+fi
+
+if [[ -z "$url" ]]; then
+ notify-send "No URL found"
+ exit 1
+fi
+
+if [[ ! "$url" =~ ^https?:// ]]; then
+ notify-send "Invalid URL format" "$url"
+ exit 1
+fi
+
+domain=$(echo "$url" | sed -e 's|^https\?://||' -e 's|/.*||' -e 's|^www\.||')
+path_part=$(echo "$url" | sed -e 's|^https\?://||' -e 's|[?#].*||')
+
+if [[ "$path_part" == */ ]] || [[ "$path_part" != */* ]]; then
+ if [[ "$path_part" != */* ]]; then
+ full_rel_path="$path_part/index.html"
+ else
+ full_rel_path="${path_part}index.html"
+ fi
+else
+ full_rel_path="$path_part"
+fi
+
+target_file_path="$HOME/misc/www/$full_rel_path"
+target_dir=$(dirname "$target_file_path")
+
+md_slug=$(echo "$path_part" | tr '/' '-' | sed 's/^-//;s/-$//')
+if [[ -z "$md_slug" ]] || [[ "$md_slug" == "index.html" ]]; then
+ md_slug="index"
+fi
+
+md_filename="${domain}-${md_slug%.html}.md"
+target_md_path="$HOME/misc/notes/www/$md_filename"
+
+mkdir -p "$target_dir" || {
+ notify-send -u critical "Error" "Failed to create directory"
+ exit 1
+}
+if monolith -o "$target_file_path" "$url"; then
+ notify-send "Saved" "$url"
+else
+ notify-send -u critical "Error" "Failed to download $url"
+ exit 1
+fi
+
+cat "$target_file_path" | html2markdown >"$target_md_path"
+
+if [[ ! -s "$target_md_path" ]]; then
+ notify-send -u critical "Error" "Conversion failed"
+fi
+
diff --git a/monofetch/wlr-river-title/BUILD b/monofetch/wlr-river-title/BUILD
@@ -0,0 +1,34 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+load("//bazel:local-deploy.bzl", "local_deploy")
+
+package(default_visibility = ["//visibility:public"])
+
+COMMON_COPTS = [
+ "-Wall",
+ "-Wextra",
+ "-O2",
+ "-fanalyzer",
+ "-Wshadow",
+]
+
+cc_library(
+ name = "river-status",
+ srcs = ["river-status.c"],
+ hdrs = ["river-status.h"],
+ copts = COMMON_COPTS,
+ linkopts = ["-lwayland-client"],
+)
+
+cc_binary(
+ name = "wlr-river-title",
+ srcs = ["wlr-river-title.c"],
+ copts = COMMON_COPTS,
+ deps = [":river-status"],
+)
+
+local_deploy(
+ name = "deploy",
+ srcs = [
+ ":wlr-river-title",
+ ],
+)
diff --git a/monofetch/wlr-river-title/river-status.c b/monofetch/wlr-river-title/river-status.c
@@ -0,0 +1,95 @@
+/* Generated by wayland-scanner 1.24.0 */
+
+/*
+ * Copyright 2020 The River Developers
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface zriver_output_status_v1_interface;
+extern const struct wl_interface zriver_seat_status_v1_interface;
+
+static const struct wl_interface *river_status_unstable_v1_types[] = {
+ NULL,
+ &zriver_output_status_v1_interface,
+ &wl_output_interface,
+ &zriver_seat_status_v1_interface,
+ &wl_seat_interface,
+ &wl_output_interface,
+ &wl_output_interface,
+};
+
+static const struct wl_message zriver_status_manager_v1_requests[] = {
+ { "destroy", "", river_status_unstable_v1_types + 0 },
+ { "get_river_output_status", "no", river_status_unstable_v1_types + 1 },
+ { "get_river_seat_status", "no", river_status_unstable_v1_types + 3 },
+};
+
+WL_PRIVATE const struct wl_interface zriver_status_manager_v1_interface = {
+ "zriver_status_manager_v1", 4,
+ 3, zriver_status_manager_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zriver_output_status_v1_requests[] = {
+ { "destroy", "", river_status_unstable_v1_types + 0 },
+};
+
+static const struct wl_message zriver_output_status_v1_events[] = {
+ { "focused_tags", "u", river_status_unstable_v1_types + 0 },
+ { "view_tags", "a", river_status_unstable_v1_types + 0 },
+ { "urgent_tags", "2u", river_status_unstable_v1_types + 0 },
+ { "layout_name", "4s", river_status_unstable_v1_types + 0 },
+ { "layout_name_clear", "4", river_status_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zriver_output_status_v1_interface = {
+ "zriver_output_status_v1", 4,
+ 1, zriver_output_status_v1_requests,
+ 5, zriver_output_status_v1_events,
+};
+
+static const struct wl_message zriver_seat_status_v1_requests[] = {
+ { "destroy", "", river_status_unstable_v1_types + 0 },
+};
+
+static const struct wl_message zriver_seat_status_v1_events[] = {
+ { "focused_output", "o", river_status_unstable_v1_types + 5 },
+ { "unfocused_output", "o", river_status_unstable_v1_types + 6 },
+ { "focused_view", "s", river_status_unstable_v1_types + 0 },
+ { "mode", "3s", river_status_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zriver_seat_status_v1_interface = {
+ "zriver_seat_status_v1", 3,
+ 1, zriver_seat_status_v1_requests,
+ 4, zriver_seat_status_v1_events,
+};
+
diff --git a/monofetch/wlr-river-title/river-status.h b/monofetch/wlr-river-title/river-status.h
@@ -0,0 +1,438 @@
+/* Generated by wayland-scanner 1.24.0 */
+
+#ifndef RIVER_STATUS_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define RIVER_STATUS_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_river_status_unstable_v1 The river_status_unstable_v1 protocol
+ * @section page_ifaces_river_status_unstable_v1 Interfaces
+ * - @subpage page_iface_zriver_status_manager_v1 - manage river status objects
+ * - @subpage page_iface_zriver_output_status_v1 - track output tags and focus
+ * - @subpage page_iface_zriver_seat_status_v1 - track seat focus
+ * @section page_copyright_river_status_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright 2020 The River Developers
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct wl_seat;
+struct zriver_output_status_v1;
+struct zriver_seat_status_v1;
+struct zriver_status_manager_v1;
+
+#ifndef ZRIVER_STATUS_MANAGER_V1_INTERFACE
+#define ZRIVER_STATUS_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_zriver_status_manager_v1 zriver_status_manager_v1
+ * @section page_iface_zriver_status_manager_v1_desc Description
+ *
+ * A global factory for objects that receive status information specific
+ * to river. It could be used to implement, for example, a status bar.
+ * @section page_iface_zriver_status_manager_v1_api API
+ * See @ref iface_zriver_status_manager_v1.
+ */
+/**
+ * @defgroup iface_zriver_status_manager_v1 The zriver_status_manager_v1 interface
+ *
+ * A global factory for objects that receive status information specific
+ * to river. It could be used to implement, for example, a status bar.
+ */
+extern const struct wl_interface zriver_status_manager_v1_interface;
+#endif
+#ifndef ZRIVER_OUTPUT_STATUS_V1_INTERFACE
+#define ZRIVER_OUTPUT_STATUS_V1_INTERFACE
+/**
+ * @page page_iface_zriver_output_status_v1 zriver_output_status_v1
+ * @section page_iface_zriver_output_status_v1_desc Description
+ *
+ * This interface allows clients to receive information about the current
+ * windowing state of an output.
+ * @section page_iface_zriver_output_status_v1_api API
+ * See @ref iface_zriver_output_status_v1.
+ */
+/**
+ * @defgroup iface_zriver_output_status_v1 The zriver_output_status_v1 interface
+ *
+ * This interface allows clients to receive information about the current
+ * windowing state of an output.
+ */
+extern const struct wl_interface zriver_output_status_v1_interface;
+#endif
+#ifndef ZRIVER_SEAT_STATUS_V1_INTERFACE
+#define ZRIVER_SEAT_STATUS_V1_INTERFACE
+/**
+ * @page page_iface_zriver_seat_status_v1 zriver_seat_status_v1
+ * @section page_iface_zriver_seat_status_v1_desc Description
+ *
+ * This interface allows clients to receive information about the current
+ * focus of a seat. Note that (un)focused_output events will only be sent
+ * if the client has bound the relevant wl_output globals.
+ * @section page_iface_zriver_seat_status_v1_api API
+ * See @ref iface_zriver_seat_status_v1.
+ */
+/**
+ * @defgroup iface_zriver_seat_status_v1 The zriver_seat_status_v1 interface
+ *
+ * This interface allows clients to receive information about the current
+ * focus of a seat. Note that (un)focused_output events will only be sent
+ * if the client has bound the relevant wl_output globals.
+ */
+extern const struct wl_interface zriver_seat_status_v1_interface;
+#endif
+
+#define ZRIVER_STATUS_MANAGER_V1_DESTROY 0
+#define ZRIVER_STATUS_MANAGER_V1_GET_RIVER_OUTPUT_STATUS 1
+#define ZRIVER_STATUS_MANAGER_V1_GET_RIVER_SEAT_STATUS 2
+
+
+/**
+ * @ingroup iface_zriver_status_manager_v1
+ */
+#define ZRIVER_STATUS_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_status_manager_v1
+ */
+#define ZRIVER_STATUS_MANAGER_V1_GET_RIVER_OUTPUT_STATUS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_status_manager_v1
+ */
+#define ZRIVER_STATUS_MANAGER_V1_GET_RIVER_SEAT_STATUS_SINCE_VERSION 1
+
+/** @ingroup iface_zriver_status_manager_v1 */
+static inline void
+zriver_status_manager_v1_set_user_data(struct zriver_status_manager_v1 *zriver_status_manager_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zriver_status_manager_v1, user_data);
+}
+
+/** @ingroup iface_zriver_status_manager_v1 */
+static inline void *
+zriver_status_manager_v1_get_user_data(struct zriver_status_manager_v1 *zriver_status_manager_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zriver_status_manager_v1);
+}
+
+static inline uint32_t
+zriver_status_manager_v1_get_version(struct zriver_status_manager_v1 *zriver_status_manager_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zriver_status_manager_v1);
+}
+
+/**
+ * @ingroup iface_zriver_status_manager_v1
+ *
+ * This request indicates that the client will not use the
+ * river_status_manager object any more. Objects that have been created
+ * through this instance are not affected.
+ */
+static inline void
+zriver_status_manager_v1_destroy(struct zriver_status_manager_v1 *zriver_status_manager_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zriver_status_manager_v1,
+ ZRIVER_STATUS_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zriver_status_manager_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zriver_status_manager_v1
+ *
+ * This creates a new river_output_status object for the given wl_output.
+ */
+static inline struct zriver_output_status_v1 *
+zriver_status_manager_v1_get_river_output_status(struct zriver_status_manager_v1 *zriver_status_manager_v1, struct wl_output *output)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zriver_status_manager_v1,
+ ZRIVER_STATUS_MANAGER_V1_GET_RIVER_OUTPUT_STATUS, &zriver_output_status_v1_interface, wl_proxy_get_version((struct wl_proxy *) zriver_status_manager_v1), 0, NULL, output);
+
+ return (struct zriver_output_status_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zriver_status_manager_v1
+ *
+ * This creates a new river_seat_status object for the given wl_seat.
+ */
+static inline struct zriver_seat_status_v1 *
+zriver_status_manager_v1_get_river_seat_status(struct zriver_status_manager_v1 *zriver_status_manager_v1, struct wl_seat *seat)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zriver_status_manager_v1,
+ ZRIVER_STATUS_MANAGER_V1_GET_RIVER_SEAT_STATUS, &zriver_seat_status_v1_interface, wl_proxy_get_version((struct wl_proxy *) zriver_status_manager_v1), 0, NULL, seat);
+
+ return (struct zriver_seat_status_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zriver_output_status_v1
+ * @struct zriver_output_status_v1_listener
+ */
+struct zriver_output_status_v1_listener {
+ /**
+ * focused tags of the output
+ *
+ * Sent once binding the interface and again whenever the tag
+ * focus of the output changes.
+ * @param tags 32-bit bitfield
+ */
+ void (*focused_tags)(void *data,
+ struct zriver_output_status_v1 *zriver_output_status_v1,
+ uint32_t tags);
+ /**
+ * tag state of an output's views
+ *
+ * Sent once on binding the interface and again whenever the tag
+ * state of the output changes.
+ * @param tags array of 32-bit bitfields
+ */
+ void (*view_tags)(void *data,
+ struct zriver_output_status_v1 *zriver_output_status_v1,
+ struct wl_array *tags);
+ /**
+ * tags of the output with an urgent view
+ *
+ * Sent once on binding the interface and again whenever the set
+ * of tags with at least one urgent view changes.
+ * @param tags 32-bit bitfield
+ * @since 2
+ */
+ void (*urgent_tags)(void *data,
+ struct zriver_output_status_v1 *zriver_output_status_v1,
+ uint32_t tags);
+ /**
+ * name of the layout
+ *
+ * Sent once on binding the interface should a layout name exist
+ * and again whenever the name changes.
+ * @param name layout name
+ * @since 4
+ */
+ void (*layout_name)(void *data,
+ struct zriver_output_status_v1 *zriver_output_status_v1,
+ const char *name);
+ /**
+ * name of the layout
+ *
+ * Sent when the current layout name has been removed without a
+ * new one being set, for example when the active layout generator
+ * disconnects.
+ * @since 4
+ */
+ void (*layout_name_clear)(void *data,
+ struct zriver_output_status_v1 *zriver_output_status_v1);
+};
+
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+static inline int
+zriver_output_status_v1_add_listener(struct zriver_output_status_v1 *zriver_output_status_v1,
+ const struct zriver_output_status_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zriver_output_status_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZRIVER_OUTPUT_STATUS_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+#define ZRIVER_OUTPUT_STATUS_V1_FOCUSED_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+#define ZRIVER_OUTPUT_STATUS_V1_VIEW_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+#define ZRIVER_OUTPUT_STATUS_V1_URGENT_TAGS_SINCE_VERSION 2
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+#define ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_SINCE_VERSION 4
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+#define ZRIVER_OUTPUT_STATUS_V1_LAYOUT_NAME_CLEAR_SINCE_VERSION 4
+
+/**
+ * @ingroup iface_zriver_output_status_v1
+ */
+#define ZRIVER_OUTPUT_STATUS_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zriver_output_status_v1 */
+static inline void
+zriver_output_status_v1_set_user_data(struct zriver_output_status_v1 *zriver_output_status_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zriver_output_status_v1, user_data);
+}
+
+/** @ingroup iface_zriver_output_status_v1 */
+static inline void *
+zriver_output_status_v1_get_user_data(struct zriver_output_status_v1 *zriver_output_status_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zriver_output_status_v1);
+}
+
+static inline uint32_t
+zriver_output_status_v1_get_version(struct zriver_output_status_v1 *zriver_output_status_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zriver_output_status_v1);
+}
+
+/**
+ * @ingroup iface_zriver_output_status_v1
+ *
+ * This request indicates that the client will not use the
+ * river_output_status object any more.
+ */
+static inline void
+zriver_output_status_v1_destroy(struct zriver_output_status_v1 *zriver_output_status_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zriver_output_status_v1,
+ ZRIVER_OUTPUT_STATUS_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zriver_output_status_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ * @struct zriver_seat_status_v1_listener
+ */
+struct zriver_seat_status_v1_listener {
+ /**
+ * the seat focused an output
+ *
+ * Sent on binding the interface and again whenever an output
+ * gains focus.
+ */
+ void (*focused_output)(void *data,
+ struct zriver_seat_status_v1 *zriver_seat_status_v1,
+ struct wl_output *output);
+ /**
+ * the seat unfocused an output
+ *
+ * Sent whenever an output loses focus.
+ */
+ void (*unfocused_output)(void *data,
+ struct zriver_seat_status_v1 *zriver_seat_status_v1,
+ struct wl_output *output);
+ /**
+ * information on the focused view
+ *
+ * Sent once on binding the interface and again whenever the
+ * focused view or a property thereof changes. The title may be an
+ * empty string if no view is focused or the focused view did not
+ * set a title.
+ * @param title title of the focused view
+ */
+ void (*focused_view)(void *data,
+ struct zriver_seat_status_v1 *zriver_seat_status_v1,
+ const char *title);
+ /**
+ * the active mode changed
+ *
+ * Sent once on binding the interface and again whenever a new
+ * mode is entered (e.g. with riverctl enter-mode foobar).
+ * @param name name of the mode
+ * @since 3
+ */
+ void (*mode)(void *data,
+ struct zriver_seat_status_v1 *zriver_seat_status_v1,
+ const char *name);
+};
+
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ */
+static inline int
+zriver_seat_status_v1_add_listener(struct zriver_seat_status_v1 *zriver_seat_status_v1,
+ const struct zriver_seat_status_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zriver_seat_status_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZRIVER_SEAT_STATUS_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ */
+#define ZRIVER_SEAT_STATUS_V1_FOCUSED_OUTPUT_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ */
+#define ZRIVER_SEAT_STATUS_V1_UNFOCUSED_OUTPUT_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ */
+#define ZRIVER_SEAT_STATUS_V1_FOCUSED_VIEW_SINCE_VERSION 1
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ */
+#define ZRIVER_SEAT_STATUS_V1_MODE_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ */
+#define ZRIVER_SEAT_STATUS_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zriver_seat_status_v1 */
+static inline void
+zriver_seat_status_v1_set_user_data(struct zriver_seat_status_v1 *zriver_seat_status_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zriver_seat_status_v1, user_data);
+}
+
+/** @ingroup iface_zriver_seat_status_v1 */
+static inline void *
+zriver_seat_status_v1_get_user_data(struct zriver_seat_status_v1 *zriver_seat_status_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zriver_seat_status_v1);
+}
+
+static inline uint32_t
+zriver_seat_status_v1_get_version(struct zriver_seat_status_v1 *zriver_seat_status_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zriver_seat_status_v1);
+}
+
+/**
+ * @ingroup iface_zriver_seat_status_v1
+ *
+ * This request indicates that the client will not use the
+ * river_seat_status object any more.
+ */
+static inline void
+zriver_seat_status_v1_destroy(struct zriver_seat_status_v1 *zriver_seat_status_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zriver_seat_status_v1,
+ ZRIVER_SEAT_STATUS_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zriver_seat_status_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/monofetch/wlr-river-title/wlr-river-title.c b/monofetch/wlr-river-title/wlr-river-title.c
@@ -0,0 +1,88 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wayland-client.h>
+#include "river-status.h"
+
+struct river_status_data {
+ struct zriver_status_manager_v1 *manager;
+ struct zriver_seat_status_v1 *seat_status;
+ struct wl_seat *seat;
+ char *focused_title;
+ int done;
+};
+
+static void seat_status_focused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, struct wl_output *output) {}
+static void seat_status_unfocused_output(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, struct wl_output *output) {}
+static void seat_status_mode(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *name) {}
+
+static void seat_status_focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, const char *title) {
+ struct river_status_data *d = data;
+ if (d->focused_title) free(d->focused_title);
+ d->focused_title = strdup(title);
+ d->done = 1;
+}
+
+static const struct zriver_seat_status_v1_listener seat_status_listener = {
+ .focused_output = seat_status_focused_output,
+ .unfocused_output = seat_status_unfocused_output,
+ .focused_view = seat_status_focused_view,
+ .mode = seat_status_mode,
+};
+
+static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
+ struct river_status_data *d = data;
+ if (strcmp(interface, zriver_status_manager_v1_interface.name) == 0) {
+ d->manager = wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ d->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
+ }
+}
+
+static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) {}
+
+static const struct wl_registry_listener registry_listener = {
+ .global = registry_handle_global,
+ .global_remove = registry_handle_global_remove,
+};
+
+int main() {
+ struct wl_display *display = wl_display_connect(NULL);
+ if (!display) {
+ fprintf(stderr, "Failed to connect to wayland display\n");
+ return 1;
+ }
+
+ struct river_status_data data = {0};
+ struct wl_registry *registry = wl_display_get_registry(display);
+ wl_registry_add_listener(registry, ®istry_listener, &data);
+
+ // Initial roundtrip to find all globals
+ wl_display_roundtrip(display);
+
+ if (!data.manager || !data.seat) {
+ fprintf(stderr, "Could not find river_status_manager or wl_seat\n");
+ return 1;
+ }
+
+ // Now bind the seat status
+ data.seat_status = zriver_status_manager_v1_get_river_seat_status(data.manager, data.seat);
+ zriver_seat_status_v1_add_listener(data.seat_status, &seat_status_listener, &data);
+
+ // Wait for events
+ while (!data.done && wl_display_dispatch(display) != -1);
+
+ if (data.focused_title) {
+ printf("%s\n", data.focused_title);
+ free(data.focused_title);
+ }
+
+ if (data.seat_status) zriver_seat_status_v1_destroy(data.seat_status);
+ if (data.manager) zriver_status_manager_v1_destroy(data.manager);
+ if (data.seat) wl_seat_destroy(data.seat);
+ wl_registry_destroy(registry);
+ wl_display_disconnect(display);
+
+ return 0;
+}