Initial commit — CTile Cinnamon extension

Snap layout overlay for Cinnamon 6.6. Drag a window to the top edge
to reveal a picker with 14 tiling presets (halves, quarters, thirds).
Layout previews use the system theme's accent color and update live
when the theme changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
prairienerd18
2026-04-06 20:22:24 -05:00
commit f4433450ff
5 changed files with 645 additions and 0 deletions

63
AGENTS.md Normal file
View File

@@ -0,0 +1,63 @@
# Agent guidance for CTile
## What this project is
A Cinnamon desktop extension (JavaScript, GJS runtime). There is no build step — files are loaded directly by Cinnamon's JS interpreter.
## Repository layout
```
ctile/
extension.js ← all logic; entry points are init(), enable(), disable()
metadata.json ← UUID, display name, supported Cinnamon versions
stylesheet.css ← St/CSS styles for the overlay and buttons
README.md
AGENTS.md
```
Install by copying the whole directory to `~/.local/share/cinnamon/extensions/ctile@ctile/`.
## Runtime environment
- **Engine:** GJS (GNOME JavaScript, SpiderMonkey-based)
- **Cinnamon version:** 6.6.7 · **Muffin version:** 6.6.3
- **Imports:** `imports.gi.*` for GObject introspection bindings; `imports.ui.*` for Cinnamon shell modules; `imports.mainloop` for timers
- **No npm, no bundler, no transpiler** — plain ES6 classes work; `import`/`export` do not
## How to test changes
1. Copy changed files into the installed location:
```bash
cp ctile@ctile/* ~/.local/share/cinnamon/extensions/ctile@ctile/
```
2. Reload the extension without restarting Cinnamon:
```bash
dbus-send --session --dest=org.Cinnamon /org/Cinnamon org.Cinnamon.Eval \
string:'const es = imports.ui.extensionSystem; es.disableExtension("ctile@ctile"); es.enableExtension("ctile@ctile");'
```
3. Check logs: `grep '\[ctile\]' ~/.xsession-errors`
Syntax-check JS before deploying:
```bash
node --check ctile@ctile/extension.js
```
## Key implementation details
### Signal arity (important gotcha)
Muffin 6.6 fires `grab-op-begin` with **four** arguments: `(display, screen, window, op)`.
Older Muffin versions used three. Getting this wrong silently breaks everything — the op check never matches and no drag is detected.
### Overlay z-ordering
The overlay actor is added to `global.stage` (not `Main.uiGroup`) and raised to the top sibling on each show, so it appears above panels and all windows.
### Accent color
Read at build time via `Gtk.Button().get_style_context().lookup_color('accent_color')` and refreshed on both `St.ThemeContext 'changed'` and `Gtk.Settings 'notify::gtk-theme-name'` signals.
### Pointer tracking during drag
Muffin consumes pointer events during a window drag, so overlay buttons are `reactive: false`. Hover state is computed manually in a `Mainloop.timeout_add` poll loop (every 40 ms) by comparing raw pointer coordinates against each button's transformed bounding box.
### Overlay visibility logic
- Show when pointer Y ≤ `TRIGGER_Y` px below the monitor's top edge
- Stay visible while pointer is within 20 px of the overlay's bounding box
- Hide otherwise