# PineNote Shell Widget A fullscreen GTK widget designed for Pine64 PineNote running Arch Linux with Hyprland, controllable via hyprgrass gestures. ## Overview This Astal-based GTK application provides: - Screen rotation (portrait/landscape) - Display brightness control (100%, 75%, 25%, 0% steps) - Power operations (suspend, shutdown, reboot) - Quick launch shortcuts for terminal, browser, and e-reader - Display refresh functionality - Audio waveform switching ## Requirements - **OS**: Arch Linux with Hyprland - **Desktop Environment**: AGS (Aylur's GTK Shell) v3 / Astal - **Dependencies**: GJS, GTK 3, Astal (`libastal-*-git`), `ags`, hyprgrass - **Display**: Pine64 PineNote (or any compatible monitor) ## Installation ### Prerequisites Astal and AGS are not distributed via npm. Install the system packages from the AUR: ```bash # Install AGS and Astal core libraries (GTK3 + GJS bindings) yay -S ags libastal-meta libastal-gjs-git libastal-hyprland-git libastal-brightness-git # Base GTK/Layer-Shell support sudo pacman -S gjs gtk3 gtk-layer-shell ``` ### Clone and Setup ```bash cd ~/projects/pineNoteShell # Project already set up in pinenote-shell/ # No npm dependencies are required cd pinenote-shell # Make widget executable chmod +x ./src/main.js ``` > **Note:** `npm install` is not needed for this project. The previous `package.json` referenced a package (`@agi/gtk3`) that does not exist on the npm registry. ## Running The entry point uses an `ags run` shebang, so you can start it directly: ```bash ./src/main.js ``` Or use the `ags` CLI explicitly: ```bash ags run ./src/main.js ``` You can toggle the window from another terminal: ```bash ags toggle pinenote-fullscreen -i pinenote-shell ``` ### Hyprland Configuration Add the following to your `~/.config/hypr/hyprgrass.conf`: > **Note:** AGS v3 uses `ags toggle` / `ags request` instead of the old `--js-evaluate` flag. ```ini [gesture:toggle_widget] hotkeys = [Mod1, T] shorthand = "pinch open" actions = [ { command = "exec ags toggle pinenote-fullscreen -i pinenote-shell", timeout = 300, target = "window:pinenote-fullscreen" } ] [gesture:brightness_up] hotkeys = [Mod1, B] shorthand = "swipe up" actions = [ { command = "exec ags request 'brightness 100' -i pinenote-shell", timeout = 300, target = "window:pinenote-fullscreen" } ] [gesture:brightness_down] hotkeys = [Mod1, V] shorthand = "swipe down" actions = [ { command = "exec ags request 'brightness 0' -i pinenote-shell", timeout = 300, target = "window:pinenote-fullscreen" } ] ``` If you want the brightness requests to actually work, add a `requestHandler` to `app.start` in `src/main.js`, for example: ```js app.start({ instanceName: "pinenote-shell", css: readFile(cssPath), requestHandler(argv, response) { if (argv[0] === "brightness") { const level = parseInt(argv[1], 10) brightness.set(level) response(`brightness set to ${level}`) } response("unknown command") }, main() { PinenoteShell() }, }) ``` (You'll need to lift the `brightness` manager out of the component scope for this.) ### Additional Gestures Add more gestures for other controls: ```ini [gesture:rotate_landscape] hotkeys = [Mod1, R] shorthand = "swipe left" actions = [ { command = "exec ags request 'rotate landscape' -i pinenote-shell", timeout = 300, target = "window:pinenote-fullscreen" } ] [gesture:launch_terminal] hotkeys = [Mod1, T] shorthand = "double tap left" actions = [ { command = "exec ags request 'launch terminal' -i pinenote-shell", timeout = 300, target = "window:pinenote-fullscreen" } ] ``` ## Usage ### Basic Controls 1. **Open/Close**: Activate with hyprgrass gesture (see configuration) 2. **Screen Rotation**: Tap landscape/portrait icons to rotate display 3. **Brightness**: Click brightness level buttons or use gestures in config 4. **System Actions**: Use suspend/shutdown buttons for power operations 5. **Launch Apps**: Click terminal, browser, or e-reader shortcuts ### Advanced Features - **Waveform Switching**: Use the waveform control to switch between audio output modes - **Display Refresh**: Force display refresh with the refresh button - **Status Display**: Monitor rotation and brightness levels in footer ## Configuration ### Custom Applications Edit `src/main.js` and modify the `LauncherManager.launch()` method: ```javascript const launchers = { terminal: "alacritty", // Your preferred terminal browser: "brave-browser", // Or chromium/firefox/edge "e-reader": "calibre", // Your e-reader application }; ``` ### Hyprland Integration The widget uses `hyprctl` and the `AstalHyprland` library to communicate with Hyprland: - **Screen rotation**: Monitors the focused monitor's `transform` property - **Display refresh**: Uses `pdlc-cli --refresh` for PineNote e-ink refresh - **Brightness**: Uses `AstalBrightness` (`/sys/class/backlight/`) ## Styling The widget uses CSS styling loaded from `$HOME/.config/ags/style.css`. The `style.css` file in this directory is the source of truth; copy or symlink it there before running: ```bash mkdir -p ~/.config/ags cp ./style.css ~/.config/ags/style.css ``` Common customization options: - `background-color`: Change widget background - `border-radius`, `margin`: Adjust widget borders and spacing - Icon sets: Use different icon themes for better visual consistency ## Troubleshooting ### Widget Won't Appear 1. **Check Astal/AGS installation**: Ensure `ags`, `gjs`, and the Astal libraries are installed correctly 2. **Verify CSS path**: Make sure `~/.config/ags/style.css` exists; otherwise the app will crash on start 3. **Verify hyprgrass config**: Make sure your gesture bindings are correct 4. **Debug output**: Run with `ags run ./src/main.js` in a terminal to see console errors ### Controls Not Working 1. **Permission issues**: Some operations may require appropriate permissions 2. **Missing applications**: Ensure your preferred terminal/browser exist 3. **Hyprland compatibility**: Test basic `hyprctl` commands manually first ### E-ink / PineNote-specific Tweaks The code and CSS are already tuned for e-ink: - **No CSS transitions or animations** in `style.css` to avoid ghosting. - **E-ink refreshes are triggered automatically** after rotation, brightness changes, waveform changes, and when the widget opens. - If you still see ghosting, increase the refresh frequency or add `einkRefresh()` after other interactive actions in `src/main.js`. ### Performance Issues - The widget is designed to be lightweight and efficient - For best performance on PineNote, avoid animations and continuous polling - E-ink displays update slowly; the app uses GObject signals instead of polling wherever possible - Monitor system resources with `htop` or similar tools ## Future Enhancements Potential features for future development: - [ ] Multi-monitor support - [ ] Advanced brightness curves (not just discrete steps) - [ ] Custom app launcher configuration - [ ] Audio waveform visualization - [ ] System monitoring widgets - [ ] Integration with PineNote-specific settings ## License This project is provided as-is for your PineNote setup. Use responsibly and test changes before deploying to production hardware.