Cli utility for position external screen in macOS
Provide a way to position external screens with with an accuracy of one pixel. Positioning of external displays with System Preferences could be done, but with a huge steps (ex. 1px move in prefs. gives 16px move of screens) and edge snapping, for most users it's OK, but when you need something beyond this - there is no options.
CLI utility that uses CoreGraphics to place screens exactly as you want.
Since you can make screens to overlap or make a gap between then - resulting positions of screens may be not exactly as you expecting, so use --info
git clone https://github.com/rtm-ctrlz/dsporganizer.git
cd dsporganizer
xcodebuild -project dsporganizer.xcodeproj -scheme dsporganizer -configuration Release -derivedDataPath build build
./build/Build/Products/Release/dsporganizer -iThe binary is build/Build/Products/Release/dsporganizer (universal, x86_64 + arm64).
Copy it into your PATH to call it by name:
cp build/Build/Products/Release/dsporganizer /usr/local/bin/Xcode is not required to build — the compiler alone is enough (arm64 only, unsigned):
swiftc -O -o dsporganizer $(find dsporganizer -name '*.swift')DSP Organizer.app does the same as the CLI, in a window (macOS 14 or later):
- a map of the screens: drag a screen to move it, with optional edge snapping ("Snap screens"; hold ⌥ while dragging to do the opposite); move the selected screen by 1px (with Shift by 10px) with the arrow keys or with the buttons at its edges;
- exact X/Y of the selected screen, relative to the main one;
- warnings for overlapping screens and screens not touching the others (macOS would move them);
- overlays over the real screens, click-through, in the coordinates of the edited layout,
to check it against how the monitors really stand:
- seam rulers (⇧⌘G): a pair of rulers facing each other across every shared edge
(ticks every 1pt, longer every 5 and 10, labelled every 50); with the right layout
the ticks and labels meet, otherwise the offset is read off directly
(
500facing496means 4pt) — nudge the screen until they meet, then Apply; - grid (⌘G): lines over the whole screen that continue straight across the bezels;
- seam rulers (⇧⌘G): a pair of rulers facing each other across every shared edge
(ticks every 1pt, longer every 5 and 10, labelled every 50); with the right layout
the ticks and labels meet, otherwise the offset is read off directly
(
- the ready-to-use
dsporganizer -m … -p …call for the edited layout, with a Copy button; - presets: save the layout under a name, load it later (double-click, or the context menu).
xcodebuild -project dsporganizer.xcodeproj -scheme 'DSP Organizer' -configuration Release -derivedDataPath build build
open 'build/Build/Products/Release/DSP Organizer.app'Like the CLI, the app changes the layout for the current session only.
-i | --info
Display available screens with properties
$ dsporganizer --info
Screen Id: 69733378
Size: 1920x1200
Global Position: 0,0 1920,1200
Color Space: NSCalibratedRGBColorSpace
Resolution: {144, 144}
Refresh Rate: 0.0
Uses Quartz Extreme: YES
Screen Id: 637697159
Size: 3840x1080
Global Position: 0,1200 3840,2280
Color Space: NSCalibratedRGBColorSpace
Resolution: {72, 72}
Refresh Rate: 0.0
Uses Quartz Extreme: YES
Current setup positioning (call example):
$ dsporganizer -m 69733378 -p '637697159:0,1200'-s | --screens
$ dsporganizer --screens
69733378
637697159All positioning is made relativly to one (main) screen, there is no any difference which screen you choose as main. Main screen will always have position with coords 0x0.
To position screens arguments -m | --main (id of main screen) and -p | --position (positions definition) are required.
To get IDs of screens use keys --screens or --info. I suggest to use --info, which can tell screen sizes to to determine screens by their dimensions.
Postions definition is a string, containing comma-separated list of ids of screens and their positions.
Examples definitions:
// single screen
111223344:1920x1080
// two screens
1234:1920x1080,5678:3840x1080
I don't know how to describe this pattern, but in regex terms it will be \d+:-?\d+x-?\d+ - for a single screen and /^(\d+:-?\d+x-?\d+,)*\d+:-?\d+x-?\d+$/ - for one or many screens.
✅ macOS 10.13 Hight Sierra
Many our thanks goes to sel-fish with [hmscreens] project for idea and some code.