# 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