Pipeline
XDragMover runs as a background menu bar app that installs a global event monitor via the Quartz Event Services API, watching modifier-key and mouse state system-wide. When a qualifying gesture is detected, it resolves the target window through the macOS Accessibility API and drives its position or frame directly.
A shared AppSettings layer (backed by UserDefaults) feeds
the active modifier, dwell delay and exclusion patterns into every tap/controller
pair live, so changes in Settings apply immediately — no restart required. A
StatusMenuController supplies the menu bar item and Settings/Debug
windows around this core pipeline.
Stages in detail
- Global Event Monitor. A Quartz Event Services tap observes keyboard modifier flags and mouse button/movement events for the entire system, not just this app's own windows.
- Event Tap.
WindowMoveEventTap/WindowResizeEventTap/FocusFollowsMouseEventTapeach compare incoming events against the configuredGestureModifier(any combination of Command/Option/Control/Shift except Shift alone) and forward qualifying events to a testable controller. - Controller.
WindowMoveController/WindowResizeControllerresolve which window is under the cursor, check it against the regex-based exclusion list (matched on the owning app's name), and — if not excluded — track mouse deltas for the duration of the drag. - Accessibility API. Position and size changes are applied directly via
AXUIElementattributes (AXWindowHandling), the same mechanism System Settings' Accessibility permission gates. - Target Window. The window being moved or resized belongs to whatever app is under the cursor — XDragMover works uniformly across all standard macOS apps, with no per-app integration required.
Permissions
Because it observes input events system-wide and repositions windows belonging to other applications, XDragMover requires the Accessibility permission (System Settings → Privacy & Security → Accessibility), granted once on first launch. No other special entitlements, kernel extensions, or background daemons are used.