uttrflow / uttrflow/uttrflow-swift

With two displays, a clipboard panel dragged on one opens jammed against the edge of the other

Open
#588 0 comments 0 reactions 0 assignees View on GitHub
area:clipboard bug P2
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

When the user drags the panel, its origin is saved in global screen coordinates (`Sources/Uttrflow/Panel/QuickPanelController.swift:260-276`). On the next open, the screen under the pointer is chosen (`:241-245`), and the remembered origin is **clamped into that screen** (`:248-257`, `Sources/UttrflowUX/PanelPlacement.swift:19-24`):

```swift
guard let remembered else { return defaultOrigin(size: size, in: visible) }
return clamped(remembered, size: size, in: visible)
```

A point from the other display is not moved to the corresponding place on this one. It is pinned to the nearest edge.

## Reproduced headlessly

`PanelPlacement.origin(remembered:size:in:)`, with a 1440 × 875 display A at x = 0 and a 2560 × 1415 display B to its right:

| Remembered | Opened on | Result |
|---|---|---|
| near A's top-left, (12, 303) | B | (1440, 303): flush against B's **left** edge, mid-height |
| near B's top-right, (3568, 843) | A | (1020, 315): flush against A's **right** edge, lower half |

The panel ends up in neither the remembered spot nor the default top-right corner. The user has to drag it back, and the next open on the other display undoes that.

A related detail: while dragging, `windowDidMove` clamps against the pointer's screen, not the panel's, so dragging the panel across the boundary between displays can pull it back.

## Why it matters

A laptop with an external display is the common desk setup. The panel follows the pointer between screens, which is right, but it lands in an awkward spot on one of them every time.

## Acceptance criteria

- The remembered position is stored per display (for example keyed by `CGDirectDisplayID` or the screen's frame), or as a position relative to the screen (a corner plus offset). A display without a remembered position uses the default corner.
- An unplugged display still falls back to clamping, so a panel is never off-screen (`Docs/ux-panel-geometry.md` "Placement").
- Tests in `Tests/UttrflowUXTests` for `PanelPlacement` cover the two rows above.

Contributor guide

Open the contributing guide

Research direction

Start with PanelPlacement.origin in Sources/UttrflowUX/PanelPlacement.swift and the placement and drag logic in Sources/Uttrflow/Panel/QuickPanelController.swift:241-276. Read the "Placement" section of Docs/ux-panel-geometry.md, then run or extend Tests/UttrflowUXTests for the two reproduced display configurations. Done means positions are retained per display or relative to it, unseen displays use the default corner, and unplugged displays still clamp onscreen.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, swift
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.