aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShav Kinderlehrer <shav@trinket.icu>2026-05-08 02:47:47 -0400
committerShav Kinderlehrer <shav@trinket.icu>2026-05-08 02:47:47 -0400
commite85467ec272826bed113c29042ea4db355b851a3 (patch)
tree3879fe821e7f050bcfa77a45d63eecfb9357c6d7
downloadextant-e85467ec272826bed113c29042ea4db355b851a3.tar.gz
extant-e85467ec272826bed113c29042ea4db355b851a3.zip
Initial commit
-rw-r--r--.gitignore3
-rw-r--r--README1
-rw-r--r--data/resources.xml6
-rw-r--r--data/window.css21
-rw-r--r--flake.lock59
-rw-r--r--flake.nix25
-rw-r--r--main.c81
-rw-r--r--meson.build27
8 files changed, 223 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..80f4056
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.cache/
+build
+*\~
diff --git a/README b/README
new file mode 100644
index 0000000..73537c1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+EXTENdable assisTANT
diff --git a/data/resources.xml b/data/resources.xml
new file mode 100644
index 0000000..456a445
--- /dev/null
+++ b/data/resources.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/ski/frog/assistant">
+ <file>window.css</file>
+ </gresource>
+</gresources>
diff --git a/data/window.css b/data/window.css
new file mode 100644
index 0000000..64357a3
--- /dev/null
+++ b/data/window.css
@@ -0,0 +1,21 @@
+window {
+ background: transparent;
+ border-radius: 999px;
+}
+
+#prompt-box {
+ border: none;
+}
+
+#prompt-box button {
+ border: none;
+ border-radius: 0px;
+}
+
+#prompt-box entry {
+ border: none;
+ outline-width: 0px;
+ border-radius: 0px;
+}
+
+
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..3984f72
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,59 @@
+{
+ "nodes": {
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1778036283,
+ "narHash": "sha256-62EWg6lI0qyzm7oAx5cAnGkLutvJsRBe0KkEW2JDZCE=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "ed67bc86e84e51d4a88e73c7fd36006dc876476f",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs",
+ "utils": "utils"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..1450caf
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,25 @@
+{
+ inputs = {
+ utils.url = "github:numtide/flake-utils";
+ };
+ outputs = { self, nixpkgs, utils }: utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = nixpkgs.legacyPackages.${system};
+ in
+ {
+ devShell = pkgs.mkShell {
+ buildInputs = with pkgs; [
+ gcc
+ pkg-config
+ clang-tools
+ gtk4
+ glib
+ gtk4-layer-shell
+ meson
+ ninja
+ guile
+ ];
+ };
+ }
+ );
+}
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..0d71046
--- /dev/null
+++ b/main.c
@@ -0,0 +1,81 @@
+#include "gdk/gdk.h"
+#include "gio/gio.h"
+#include "glib-object.h"
+#include "gtk/gtkcssprovider.h"
+#include <gtk/gtk.h>
+#include <gtk4-layer-shell/gtk4-layer-shell.h>
+#include <libguile.h>
+
+static void setup_window_styles(GtkWindow *window) {
+ GtkCssProvider *css_provider = gtk_css_provider_new();
+ gtk_css_provider_load_from_resource(css_provider,
+ "/ski/frog/assistant/window.css");
+
+ gtk_style_context_add_provider_for_display(
+ gdk_display_get_default(), GTK_STYLE_PROVIDER(css_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+}
+
+static gboolean on_escape_key_pressed(GtkEventControllerKey *controller, guint keyval,
+ guint keycode, GdkModifierType state,
+ gpointer user_data) {
+ GtkWindow *window = GTK_WINDOW(user_data);
+ if (keyval == GDK_KEY_Escape) {
+ gtk_window_close(window);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void setup_close_on_escape(GtkWindow *window) {
+ GtkEventController *controller = gtk_event_controller_key_new();
+ g_signal_connect(controller, "key-pressed", G_CALLBACK(on_escape_key_pressed),
+ window);
+ gtk_widget_add_controller(GTK_WIDGET(window), controller);
+}
+
+static void on_submit(GtkWidget *widget, gpointer data) {
+ GtkEntry *entry = GTK_ENTRY(data);
+ const char *text = gtk_editable_get_text(GTK_EDITABLE(entry));
+ g_print("Got: %s\n", text);
+}
+
+static void activate(GtkApplication *app, gpointer user_data) {
+ GtkWidget *window = gtk_application_window_new(app);
+
+ gtk_layer_init_for_window(GTK_WINDOW(window));
+ gtk_layer_set_layer(GTK_WINDOW(window), GTK_LAYER_SHELL_LAYER_OVERLAY);
+ gtk_layer_set_keyboard_mode(GTK_WINDOW(window),
+ GTK_LAYER_SHELL_KEYBOARD_MODE_EXCLUSIVE);
+
+ gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
+
+ setup_window_styles(GTK_WINDOW(window));
+ setup_close_on_escape(GTK_WINDOW(window));
+
+ GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
+ gtk_widget_set_name(hbox, "prompt-box");
+
+ GtkWidget *entry = gtk_entry_new();
+ GtkWidget *submit_button = gtk_button_new_from_icon_name("send-to-symbolic");
+ g_signal_connect(submit_button, "clicked", G_CALLBACK(on_submit), entry);
+ g_signal_connect(entry, "activate", G_CALLBACK(on_submit), entry);
+
+ gtk_box_append(GTK_BOX(hbox), entry);
+ gtk_box_append(GTK_BOX(hbox), submit_button);
+
+ gtk_window_set_child(GTK_WINDOW(window), hbox);
+
+ gtk_window_present(GTK_WINDOW(window));
+}
+
+int main(int argc, char *argv[]) {
+ GtkApplication *app =
+ gtk_application_new("ski.frog.assistant", G_APPLICATION_DEFAULT_FLAGS);
+ g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+
+ int status = g_application_run(G_APPLICATION(app), argc, argv);
+ g_object_unref(app);
+
+ return status;
+}
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..b8c1d8f
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,27 @@
+project('assistant', 'c')
+
+gtk = dependency('gtk4')
+glib = dependency('glib-2.0')
+layer_shell = dependency('gtk4-layer-shell-0')
+libguile = dependency('guile-3.0')
+
+gnome = import('gnome')
+
+resources = gnome.compile_resources(
+ 'resources',
+ 'data/resources.xml',
+ source_dir: 'data',
+ c_name: 'resources'
+)
+
+executable(
+ 'assistant',
+ 'main.c',
+ resources,
+ dependencies: [
+ gtk,
+ glib,
+ layer_shell,
+ libguile,
+ ]
+) \ No newline at end of file