Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-06-12
35 changes: 35 additions & 0 deletions openspec/changes/archive/2026-06-12-hypr-monitor-binds/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Context

Hyprland bindings are organized in `configs/binds/` as modular sub-modules (`window.lua`, `layout.lua`, `apps.lua`, `workspace.lua`), loaded by `configs/binds.lua` orchestrator. The codebase follows a `register(mainMod)` pattern where `mainMod = "SUPER"` is passed to each module.

No existing module covers monitor-level operations. The user needs two plain-ALT bindings (no SUPER prefix) for moving windows between monitors and maximizing.

## Goals / Non-Goals

**Goals:**
- Add `configs/binds/monitor.lua` with two keybindings as module-level constant definitions
- Load via existing orchestrator with one `require()` line
- Follow existing sub-module conventions (return `M` table with `register()` function)
- Keep binding logic minimal — YAGNI

**Non-Goals:**
- No changes to Hyprland `.conf` files, monitor configuration, or DMS IPC
- No multi-monitor workspace management (focus/move workspace to monitor)
- No profile system or conditional monitor detection

## Decisions

| Decision | Choice | Rationale |
|----------|--------|-----------|
| **Modifier keys as constants** | Define `MOD_ALT` constant at module top, use it in bind definitions | User requirement: "key configs as constants, no inline strings"; matches pattern of `mainMod` elsewhere |
| **Plain ALT (no SUPER)** | `hl.bind("ALT + O", ...)` without `mainMod` prefix | User explicitly wants ALT+O and ALT+M; multimedia keys already use this no-prefix pattern in `window.lua` |
| **Monitor move dispatch** | `hl.dsp.window.move({ monitor = "+1" })` | Hyprland `monitor = "+1"` moves to the next monitor in the list, cycling forward (1→2→3→1). For 2 monitors this behaves as a toggle; for 3+ it cycles through all connected monitors |
| **Maximize dispatch** | `hl.dsp.window.fullscreen({ mode = "maximize" })` | Fills workspace area while keeping bar visible (`maximized` hides decorations) |
| **Sub-module location** | `configs/binds/monitor.lua` | Consistent with existing modular split; loaded after `window` in orchestrator |
| **No custom dispatcher** | Use `hl.dsp.*` directly | The Hyprland Lua API already provides these; no need for custom helper functions (YAGNI) |

## Risks / Trade-offs

- **[Key collision]** ALT+O/M might conflict with application-level shortcuts → Low risk since Hyprland captures at compositor level before apps see the event
- **[Single monitor systems]** `monitor = "+1"` on single-monitor is a no-op (no crash, no error) → Graceful no-op by design
- **[Maximize mode mismatch]** If `fullscreen({ mode = "maximize" })` doesn't behave as expected, fallback is `fullscreen({ mode = "maximized" })` → Easy tweak, single constant change at module top
26 changes: 26 additions & 0 deletions openspec/changes/archive/2026-06-12-hypr-monitor-binds/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Why

Hyprland currently lacks dedicated keybindings for window-to-monitor movement and window maximize. The user needs quick keyboard shortcuts to move the active window between monitors (ALT+O) and maximize it (ALT+M) without reaching for the mouse or relying on workspace-based workflows.

## What Changes

- Add new `configs/binds/monitor.lua` sub-module with two keybindings:
- **ALT + O**: Toggle active window between monitors (cycles forward with 3+ monitors)
- **ALT + M**: Maximize active window (fill workspace area, keep bar visible)
- Define all modifier keys as module-level constants (no inline strings)
- Load via `configs/binds.lua` orchestrator in existing require chain
- No changes to existing binds, no config files, no DMS IPC

## Capabilities

### New Capabilities
- `monitor-binds`: Two keybindings for monitor-level window management — move to other monitor and maximize

### Modified Capabilities
*(none — this is purely additive, no existing capability changes)*

## Impact

- **New file**: `configs/binds/monitor.lua` (~30 lines)
- **Modified file**: `configs/binds.lua` — add one `require("configs.binds.monitor").register(mainMod)` line
- **Zero impact** on existing bindings, workspaces, DMS IPC, or Hyprland config
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## ADDED Requirements

### Requirement: Toggle window between monitors
The system SHALL bind ALT+O to toggle the active window between monitors. If the window is on monitor 1, it moves to monitor 2. If pressed again, it moves back to monitor 1.

#### Scenario: Toggle from primary to secondary
- **WHEN** user presses ALT+O with an active window on the primary monitor
- **THEN** the window moves to the secondary monitor

#### Scenario: Toggle back to primary
- **WHEN** user presses ALT+O again with the window now on the secondary monitor
- **THEN** the window moves back to the primary monitor

#### Scenario: Cycle forward with 3+ monitors
- **WHEN** user presses ALT+O on a system with three or more monitors
- **THEN** the window moves forward to the next monitor in the list (1→2→3→1)

#### Scenario: No-op on single monitor
- **WHEN** user presses ALT+O on a system with only one monitor connected
- **THEN** no change occurs (graceful no-op, no error)

### Requirement: Maximize active window
The system SHALL bind ALT+M to maximize the active window, filling the workspace area while keeping the bar/panel visible.

#### Scenario: Maximize tiled window
- **WHEN** user presses ALT+M on a tiled window
- **THEN** the window expands to fill the workspace (excluding panel/bar area)

#### Scenario: Maximize floating window
- **WHEN** user presses ALT+M on a floating window
- **THEN** the window snaps to fill the workspace (excluding panel/bar area)

#### Scenario: Toggle maximize off
- **WHEN** user presses ALT+M on an already-maximized window
- **THEN** the window returns to its previous size and position

### Requirement: Key constants
All modifier keys SHALL be defined as module-level constants at the top of the file, not inlined in bind registration calls.

#### Scenario: Constants precede usage
- **WHEN** reading the monitor.lua module
- **THEN** all modifier key strings are defined as local constants before any `hl.bind()` call

### Requirement: Integration with orchestrator
The module SHALL export a `register(mainMod)` function following the existing sub-module convention, loaded by `configs/binds.lua`.

#### Scenario: Module loaded on startup
- **WHEN** Hyprland starts with `require("configs.binds").register(mainMod)` in the load chain
- **THEN** the ALT+O and ALT+M bindings are active
14 changes: 14 additions & 0 deletions openspec/changes/archive/2026-06-12-hypr-monitor-binds/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## 1. Create monitor.lua sub-module

- [x] 1.1 Create `configs/binds/monitor.lua` with ALT and SUPER constants at module top
- [x] 1.2 Add ALT+O bind using `hl.dsp.window.move({ monitor = "+1" })` (toggle/cycle between monitors)
- [x] 1.3 Add ALT+M bind using `hl.dsp.window.fullscreen({ mode = "maximize" })`

## 2. Register in orchestrator

- [x] 2.1 Add `require("configs.binds.monitor").register(mainMod)` to `configs/binds.lua`

## 3. Verify

- [x] 3.1 Run `task validate` for pre-commit hooks
- [x] 3.2 Verify Lua syntax with `luac -p` or `stylua --check`
Loading