OmaDrop
A floating dropzone for Omarchy inspired by Dropover (macOS): collect files in a temporary shelf, then move, share, or process everything at once.
Shake the mouse and a shelf appears right under your cursor. Drag files into it — including files you are already dragging — then carry them to the real destination: a browser, another app, another workspace. Drag them out of it there.
The shake only opens the shelf; it never grabs files on its own. To shelve the current selection without dragging, press the capture hotkey.
<img width="1029" height="766" alt="image" src="https://github.com/user-attachments/assets/390d366e-6d5b-46ea-b95c-5ec6c3d70977" />Install
omarchy plugin add git@github.com:lucascnunes/omadrop.git --enable
# or, while developing:
ln -s "$(pwd)" ~/.config/omarchy/plugins/lucas.omadrop
omarchy plugin enable lucas.omadrop
The icon joins the bar (right section). It is the body of the plugin: removing it from the bar disables OmaDrop entirely.
After updating an existing install, restart the shell:
omarchy-restart-shell
Editing plugin files hot-reloads the QML, but a new IPC verb is only registered on a full shell restart — without it a shake reaches nothing and silently does nothing.
Usage
| Action | How |
|---|---|
| Open a shelf under the cursor | Shake the mouse — mid-drag too: the shelf appears under the files you are already carrying |
| Capture the selection | Press Super+Shift+D, or right-click the bar icon |
| Open the current shelf | Super+Shift+A or left-click the icon |
| Collect by dragging | Drag files from any app into the shelf |
| Use the shelf | Drag a tile into any application (browser upload, e-mail attachment, file manager move…) — double-click opens the file |
| Configure | Right-click the bar icon (or the button on the shelf) |
The suggested hotkeys need one line each in ~/.config/hypr/bindings.lua
(the settings panel copies ready-made lines — combos are editable there):
o.bind("SUPER SHIFT, D", "OMADROP CAPTURE", "omarchy-shell omadrop capture")
o.bind("SUPER SHIFT, A", "OMADROP OPEN", "omarchy-shell omadrop open")
How capture works: Wayland exposes no "selected files" API, so when you trigger the hotkey OmaDrop copies the selection behind the scenes (an invisible synthesized keypress), reads the list from the clipboard, and restores your previous clipboard content. You never press Ctrl+C; if you prefer copying manually, use
omarchy-shell omadrop clip, which only reads whatever is already on the clipboard. In terminals the key synthesis is skipped automatically (avoids sending SIGINT).
Settings
Available in the panel (the button) and persisted in your shell.json
(~/.config/omarchy/shell.json, inside this widget's entry):
| Setting | Default | What it does |
|---|---|---|
shakeEnabled |
true |
Enables/disables shake detection |
shakeReversals |
4 |
Direction reversals that count as a shake (lower = more sensitive) |
shelfPosition |
cursor |
cursor, topLeft, topCenter, topRight, bottomLeft, bottomCenter, bottomRight |
maxItems |
20 |
Item cap for the active shelf |
showNotifications |
true |
"N files shelved" toasts |
language |
auto |
UI language: auto (follow system locale), en, pt. Changing it updates the settings panel, shelf, and toasts immediately |
hotkeyCapture / hotkeyOpen |
SUPER SHIFT, D / SUPER SHIFT, A |
Editable combos; the panel's copy chip emits the matching o.bind(...) line |
Shelf history ("New shelf")
New shelf archives the current one and starts fresh. The panel's Recent
shelves section lists everything: reopen any shelf (making it active again)
or delete old entries. State lives in ~/.local/state/omadrop/shelf.json and
survives shell restarts.
IPC (for scripts and keybinds)
omarchy-shell omadrop shake # opens a shelf under the cursor (what a shake does)
omarchy-shell omadrop capture # selection -> shelf (full pipeline)
omarchy-shell omadrop clip # reads the current clipboard only
omarchy-shell omadrop open # shows the shelf
omarchy-shell omadrop toggle # toggles visibility
omarchy-shell omadrop settings # opens the settings panel
omarchy-shell omadrop archive # new shelf (archives the current one)
omarchy-shell omadrop clear # empties the active shelf
omarchy-shell omadrop suspend # pauses the shake detector (session-scoped)
omarchy-shell omadrop resume
omarchy-shell omadrop status # JSON snapshot of current state
Troubleshooting
- Shake never fires — check
~/.local/state/omadrop/shaked.log; raise sensitivity (shakeReversals: 3). Smoke-test risk-free withomarchy-shell omadrop shake. - Shake fires too often — raise
shakeReversalsto 5–6, or pause withomarchy-shell omadrop suspend. - Capture finds no files — the focused app must respond to Ctrl+C with
text/uri-list(Nautilus, Dolphin, Thunar and Nemo all do). Capture keys go through ydotool (kernel-level, immune to input-method conflicts); its daemon auto-starts on first capture and stays resident (~1 MB). With fcitx5 running, wtype alone silently fails — inspect~/.local/state/omadrop/capture.logwithOMADROP_DEBUG=1. - Dragging into apps fails — remote entries (e.g.
network://) do not take part in native drags; local paths do.
Architecture
manifest.json hybrid bar-widget + panel (keepLoaded)
OmaDrop.qml root: IPC, settings, state, daemon, geometry
BarWidget.qml bar icon + badge (reads shelf.json)
ShelfWindow.qml layer-shell window: drag-out tiles, DropArea, settings
SettingsPanel.qml settings + history popout under the bar icon
ShelfModel.js pure logic (URIs, dedupe, serialization), node-testable
Strings.js i18n (en/pt); callers pass settings.language into tLang()
scripts/capture-selection.sh clipboard snapshot → wtype → uri-list → restore
scripts/read-shelf-state safe bounded state reader (no symlinks/special files)
scripts/omadrop-shaked Python daemon (~80 Hz over Hyprland socket1)
tests/shelf-model-test.js node tests/shelf-model-test.js
CHANGELOG.md release history (English)
Why Python for the detector: the loop is I/O-bound (~0.02 ms/request
measured; asleep ~98% of the time) so CPU stays under 1% in any language,
and Python needs no build toolchain in a git-distributed plugin. Documented
future upgrades: an in-shell detector via Quickshell.Io.Socket (saves
~20 MB RSS) or a native Hyprland C++ plugin (pointer events and button state).
Uninstall
omarchy plugin remove lucas.omadrop --yes
Then clean up what the plugin leaves behind:
rm -rf ~/.local/state/omadrop # shelf history, logs, daemon lock
And remove the two o.bind(... omadrop ...) lines you added to
~/.config/hypr/bindings.lua, followed by omarchy reload hyprland
(or omarchy restart shell).
Support
OmaDrop is free and open source. If it saves you time every day, consider supporting the project:
- ⭐ Star the repo: github.com/lucascnunes/omadrop
- ☕ Buy a coffee: ko-fi.com/lucascnunes
License
MIT — see LICENSE.