On Xfce with compositing off, X11 has no alpha to blend against, so the transparent background came out as a black box around the cat. When a window comes up without an alpha channel, TNCat now cuts the window down to the pixels the drawing covers, using the X11 shape extension, and refreshes that 15 times a second so it follows the animation. A sitting cat in a 120 x 106 window comes out as 96 rectangles over 29 percent of the window, so most of the box is gone. Edges are harder than with a compositor, one bit per pixel, and the log says so and names the Xfce setting that gives smooth ones instead. The image-to-rectangles step is platform independent and folds every device row into its window row, which both halves the rectangle count on a scaled display and keeps a pixel that is opaque in only one of them. xcb and xcb-shape are picked up through pkg-config on Unix and the build still works without them. Opaque mode now paints a neutral card rather than the coat colour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
163 lines
8.2 KiB
Markdown
163 lines
8.2 KiB
Markdown
# TNCat
|
|
|
|
A little cat that wanders along the bottom edge of the screen, sits down, grooms
|
|
itself, stretches, dashes off and takes naps. Every now and then a curled steel
|
|
chip skitters past and the cat goes after it, or a mug appears and the cat takes
|
|
a coffee break. Drag it around, tap it to pet it, and it purrs.
|
|
|
|
It announces what it is doing in the machine's own language: `G00` when it
|
|
sprints, `G01` when it strolls, `M08` while it washes, `G28` when it stretches
|
|
back to reference, `M30` when it goes to sleep, `M01` when it stops for coffee.
|
|
|
|
The name is `TNC` plus `cat`, because the intended home is a HEIDENHAIN control
|
|
(TNC7, TNC 640). Primary target is therefore **Linux / X11**; development happens
|
|
on macOS and both are supported by the same code.
|
|
|
|
Inspired by [workcat.app](https://workcat.app/en/), rebuilt from scratch as a
|
|
plain Qt 6 / QML project.
|
|
|
|
## Layout
|
|
|
|
| Path | Purpose |
|
|
|---|---|
|
|
| `CMakeLists.txt` | `qt_add_executable` + `qt_add_qml_module` (URI `TNCat`), macOS bundle, `.desktop` file on Linux |
|
|
| `src/main.cpp` | Wires `AppSettings` and `CatController` into the QML engine, warns on Wayland |
|
|
| `qml/AppButton.qml`, `qml/AppSlider.qml`, `qml/AppToggle.qml`, `qml/SettingsGroup.qml` | The controls, built from primitives |
|
|
| `src/catcontroller.*` | Mood machine (walk, run, sit, groom, stretch, sleep, love, alert, chase, bat, drink), movement tick, chip chase, coffee break, cursor tracking |
|
|
| `src/appsettings.*` | `QSettings`-backed coat, size, pace, ground line, eye tracking, pet counter |
|
|
| `src/platforminfo.*` | QML singleton `Platform`: platform name plus the X11 escape hatches |
|
|
| `qml/Main.qml` | Non-visual root that picks the window layout for the platform |
|
|
| `qml/CatWindow.qml`, `qml/ChipWindow.qml`, `qml/CupWindow.qml` | One small window each, positioned by the app. X11, macOS, Windows |
|
|
| `qml/OverlayWindow.qml` | One screen-filling click-through window holding both. Wayland |
|
|
| `qml/Cat.qml` | The drawing: rounded primitives plus `Shape` paths for tail, ears and mouth |
|
|
| `qml/Chip.qml` | The curled chip, a stroked `Shape` spiral |
|
|
| `qml/Cup.qml` | The coffee mug, with `Shape` steam wisps |
|
|
| `qml/SettingsWindow.qml` | Coat swatches, size, pace, ground line, eye tracking, codes, chips, coffee, tricks |
|
|
|
|
The cat is drawn in a fixed 100 x 90 design space and scaled by `width / 100`,
|
|
so every size setting stays crisp. There are no image assets, which keeps the
|
|
whole thing to one binary plus Qt.
|
|
|
|
## Build
|
|
|
|
macOS with the Qt online installer:
|
|
|
|
```bash
|
|
~/Qt/6.11.1/macos/bin/qt-cmake -S . -B build -G Ninja -DCMAKE_MAKE_PROGRAM=$HOME/Qt/Tools/Ninja/ninja
|
|
```
|
|
|
|
Linux with distribution Qt packages:
|
|
|
|
```bash
|
|
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
|
|
```
|
|
|
|
```bash
|
|
cmake --build build
|
|
```
|
|
|
|
Needs Qt 6.5 or newer. Required modules: Core, Gui, Quick, QuickShapes. There is
|
|
no dependency on Qt Quick Controls and none on Qt Widgets: every control in the
|
|
settings window is built from Qt Quick primitives, and there is no tray icon,
|
|
which is the only thing that pulled Widgets in.
|
|
|
|
Check what actually got linked with:
|
|
|
|
```bash
|
|
otool -L build/tncat.app/Contents/MacOS/tncat | grep -o 'Qt[A-Za-z]*\.framework' | sort -u
|
|
```
|
|
|
|
## Environment switches
|
|
|
|
| Variable | Effect |
|
|
|---|---|
|
|
| `TNCAT_X11_BYPASS=1` | Adds `Qt::X11BypassWindowManagerHint`, making an override-redirect window. Use when the window manager refuses to keep the cat on top or shows it in the taskbar. |
|
|
| `TNCAT_OVERLAY=1` | Forces the screen-filling overlay layout that Wayland needs, for testing it on X11. |
|
|
| `TNCAT_OPAQUE=1` | Paints a solid background instead of relying on transparency. Use when no compositor runs and the cat sits in a black box. |
|
|
| `TNCAT_POSE=Sitting` | Freezes the cat in one mood. Handy for screenshots. Accepts any `CatController::Mood` name. |
|
|
| `TNCAT_DEBUG=1` | Logs the cat window's geometry and the screen it sits on, every time either changes. First thing to try when a window comes up the wrong size. |
|
|
| `QT_QUICK_BACKEND=software` | Qt Quick's software rasteriser, for machines without a usable OpenGL driver. `Shape` falls back to its geometry renderer on its own. |
|
|
|
|
## Two window layouts
|
|
|
|
On X11, macOS and Windows the cat, the chip and the mug each get their own small,
|
|
frameless, always-on-top window, and the app moves those windows around. Nothing
|
|
else on screen is covered and no clicks are intercepted.
|
|
|
|
Wayland does not let a client place its own window, so that layout cannot work
|
|
there. In overlay mode the app instead opens one screen-filling transparent
|
|
window, moves the cat inside it, and restricts the window's input region to the
|
|
cat's rectangle with `QWindow::setMask`, so every click outside the cat lands on
|
|
whatever is behind. The mask is refreshed about 30 times a second while the cat
|
|
walks.
|
|
|
|
Overlay mode switches on automatically on Wayland. `TNCAT_OVERLAY=1` turns it on
|
|
anywhere for testing. It is not the default elsewhere because macOS ignores the
|
|
input mask, which would make the overlay swallow every click on the desktop.
|
|
|
|
## Xfce and X11
|
|
|
|
This is the main target. Two things to know.
|
|
|
|
**Transparency needs a compositor.** Without one, X11 has no alpha channel to
|
|
composite against and the transparent window background renders as a black box
|
|
around the cat. In Xfce it is one checkbox: Settings, Window Manager Tweaks,
|
|
Compositor, Enable display compositing. That is the best answer, because alpha
|
|
gives smooth edges.
|
|
|
|
When TNCat sees a window come up without an alpha channel it says so and falls
|
|
back to shaping the window with the X11 shape extension: the window is cut down
|
|
to the pixels the cat covers, so there is no box left to be black. The shape is
|
|
one bit per pixel, so edges are harder than with a compositor, and it is
|
|
refreshed 15 times a second to follow the animation. Measured on a sitting cat
|
|
in a 120 x 106 window, the shape is 96 rectangles covering 29 percent of the
|
|
window.
|
|
|
|
Shaping needs `xcb` and `xcb-shape` at build time (`libxcb-shape0-dev` on
|
|
Debian and Ubuntu, `xcb-util-devel` on SUSE). CMake says so if they are
|
|
missing, and the build still works without them. `TNCAT_OPAQUE=1` skips the
|
|
whole question and paints a solid background.
|
|
|
|
**Keeping the cat on top.** The default is a frameless `Qt::Tool` window that
|
|
stays on top. If the window manager puts it behind other windows or shows it in
|
|
the taskbar, `TNCAT_X11_BYPASS=1` makes it an override-redirect window that the
|
|
window manager does not manage at all.
|
|
|
|
## Running on a HEIDENHAIN control
|
|
|
|
Untested on real hardware so far. What the code already does for that target:
|
|
|
|
- **X11 today, Wayland later.** Both layouts are in the build; the platform picks
|
|
one at startup.
|
|
- **No tray, no menu bar item.** The cat itself is the whole interface:
|
|
right-click or long-press opens the settings window. Quit from the button
|
|
there, with Ctrl+C in the terminal that started it, or by killing the process.
|
|
- **Touch works without hover.** Tap pets the cat, drag picks it up. The blush on
|
|
hover is a mouse-only extra, not a requirement.
|
|
- **Ground line setting.** The cat normally stands on the bottom of the available
|
|
screen area. On a control whose lower edge carries softkeys, raise the ground
|
|
line in the settings so the cat walks above them.
|
|
|
|
What still needs checking on the actual machine:
|
|
|
|
- **Qt version and libraries on HEROS.** Build against what the control has, or
|
|
ship a self-contained bundle with the Qt libraries next to the binary. Building
|
|
on a newer distribution than the control runs will fail at load time on glibc.
|
|
- **Graphics stack.** If Qt Quick cannot get an OpenGL context, start with
|
|
`QT_QUICK_BACKEND=software`. The drawing is simple enough for that path.
|
|
- **Window management.** The NC user interface runs fullscreen. Try the default
|
|
flags first, then `TNCAT_X11_BYPASS=1` if the cat disappears behind it.
|
|
- **Installing anything on a control is subject to your site's rules.** Keep the
|
|
cat away from anything the operator needs to read, and clear it with whoever
|
|
administers the machine before it runs on production hardware.
|
|
|
|
## Interaction
|
|
|
|
| Input | Result |
|
|
|---|---|
|
|
| Click or tap | Pet the cat, it closes its eyes and purrs |
|
|
| Drag | Pick the cat up and put it somewhere else |
|
|
| Hover | Blush and purr wiggle |
|
|
| Double-click, right-click or long-press | Settings window |
|
|
| Settings window | Coat, size, pace, ground line, habits, tricks, quit |
|