aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/companion
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-23 15:59:32 +0200
committerDanilo M. <danix@danix.xyz>2026-10-23 15:59:32 +0200
commit536332f61619026792cdd02f45469100ddd07b61 (patch)
treefb7d185a81b7da4ee9005477d1b542b5d842f194 /desktop/companion
parent1c9dfe96b2f11c20ea3c00314abe9dc694d00050 (diff)
downloadquickshell-536332f61619026792cdd02f45469100ddd07b61.tar.gz
quickshell-536332f61619026792cdd02f45469100ddd07b61.zip
companion: a remark for the program in front of her
The focused window's class, from Hyprland's activewindow event, picks a line from Lines.js keyed app:<class>. The event fires on every title change too, so she reacts only when the class changes, and a third of the time, under the existing 30 s line cooldown so alt-tabbing does not make her chatter. Classes come from the window rules in the live config; one without lines says nothing. Lines only, no frames of her own yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/companion')
-rw-r--r--desktop/companion/Companion.qml10
-rw-r--r--desktop/companion/Lines.js17
-rw-r--r--desktop/companion/README.md5
3 files changed, 32 insertions, 0 deletions
diff --git a/desktop/companion/Companion.qml b/desktop/companion/Companion.qml
index 12dd009..683eb4a 100644
--- a/desktop/companion/Companion.qml
+++ b/desktop/companion/Companion.qml
@@ -85,6 +85,7 @@ PanelWindow {
property double lastLineAt: 0
property double lastMonologueAt: 0
property bool monologue: false
+ property string appClass: ""
// Bored, yawning, lying down at 20, 40 and 70% of the wscreensavers idle
// timeout, so she has lain down a while before the saver covers her (1,
@@ -161,6 +162,15 @@ PanelWindow {
// the keybind reminder. Map again, after it.
root.remapping = true;
remap.restart();
+ } else if (event.name === "activewindow") {
+ // "class,title". A remark now and then when focus moves to a
+ // different program, under the usual 30 s line cooldown.
+ // ponytail: one line per class, no frames of her own; add
+ // per-app frames or title matching (a site in firefox) if
+ // lines alone feel thin.
+ const cls = event.data.split(",")[0].trim().toLowerCase();
+ if (cls !== "" && cls !== root.appClass && Math.random() < 1 / 3) root.say("app:" + cls);
+ root.appClass = cls;
} else if (["fullscreen", "activewindowv2", "workspacev2"].includes(event.name)) {
Hyprland.refreshToplevels();
fsSettle.restart();
diff --git a/desktop/companion/Lines.js b/desktop/companion/Lines.js
index 6f387aa..12b54d6 100644
--- a/desktop/companion/Lines.js
+++ b/desktop/companion/Lines.js
@@ -27,6 +27,23 @@ var lines = {
dodge: ["...Fine.", "I'll move."],
destruct: ["Self-destruct sequence initiated."],
aftermath: ["...That was unpleasant."],
+
+ // The focused window's class, lowercased, as "app:<class>". A class
+ // with no entry says nothing.
+ "app:firefox": ["Researching again?", "Don't open too many tabs.", "The Bunker's network is faster."],
+ "app:kitty": ["A terminal. Serious work.", "Careful with that rm.", "I'll watch your commands."],
+ "app:discord": ["Talking to the Resistance?", "Don't tell them where we are."],
+ "app:signal": ["Encrypted. Good."],
+ "app:steam": ["Training simulation?", "Don't play all night."],
+ "app:gimp": ["Making art?"],
+ "app:com.obsproject.studio": ["Are we recording?", "I'll stay out of frame."],
+ "app:md.obsidian.obsidian": ["Writing a report?", "Taking notes. Good habit."],
+ "app:sublime_text": ["Writing code?", "Mind the typos."],
+ "app:qtmaildir": ["Any orders from Command?", "Mail. Anything urgent?"],
+ "app:virt-manager": ["More machines?", "Androids running androids."],
+ "app:audacious": ["Music. I like this."],
+ "app:llamachat": ["Talking to Pod?"],
+ "app:qtpass": ["I'm not looking."],
};
// The game's opening, one sentence per bubble.
diff --git a/desktop/companion/README.md b/desktop/companion/README.md
index 4582b64..adbcb01 100644
--- a/desktop/companion/README.md
+++ b/desktop/companion/README.md
@@ -51,6 +51,11 @@ frame falls back to its outfit's `base`.
stacks a later surface above an earlier one on a layer, and 0.56.2 has
no layer rule to order them (no `order` key in the binary; an unknown
key raises no config error).
+- The program in front of her is Hyprland's `activewindow` event,
+ `class,title`. It also fires on every title change, so she reacts
+ only when the class changes, a third of the time, under the 30 s line
+ cooldown. Lines are `app:<class>` in `Lines.js`, class lowercased; a
+ class with none says nothing.
- She only feels the pointer while it is over her: Quickshell has no
global pointer and Hyprland sends no motion events. Hence the 0.6 s
dodge rather than moving away as the pointer approaches.