I have a weird setup for my home office that allows me to switch from a standing desk to a sitting desk. The only problem is that when I alternate positions, my laptop's external monitor switches sides. (When standing it is off to the left of my laptop, when sitting it is on the right). At the moment, every time I go from sitting to standing, or vise-versa I have to go into System Preferences -> Displays -> Arrangement
and rearrange them. What I would love is some sort of terminal command that moves the 2nd monitor relative to first one. Doesn't matter how long the command is since I can just alias it.
2 Answers
I wrote a small C program to accomplish this, as this cannot be done any other way effectively.
You'll need Xcode installed to compile it.
https://github.com/stnvh/cgorigin
#import <Foundation/Foundation.h>
#import <ApplicationServices/ApplicationServices.h>
#define MAX_DISPLAYS 10
static CGDisplayCount dispCount = MAX_DISPLAYS;
static CGDirectDisplayID dispOnline[MAX_DISPLAYS];
int main(int argc, const char * argv[]) {
CGDisplayCount dispOnlineCount;
CGDisplayErr errActive = CGGetOnlineDisplayList(dispCount, dispOnline, &dispOnlineCount);
CGDisplayConfigRef configRef;
CGError err = CGBeginDisplayConfiguration(&configRef);
if(!argv[1]) {
printf("usage: [-l | --list] [[-o | --origin] x y index] \n");
return 1;
}
for(int i = 0; i < dispOnlineCount; i++) {
if(dispOnline[i]) {
int dispWidth = CGDisplayPixelsWide(dispOnline[i]);
int dispHeight = CGDisplayPixelsHigh(dispOnline[i]);
CGPoint dispOrigin = CGDisplayBounds(dispOnline[i]).origin;
if(strcmp(argv[1], "--list") == 0 || strcmp(argv[1], "-l") == 0) {
printf("display %d: %dx%d %ldx%ld\n", i, dispWidth, dispHeight, (long)dispOrigin.x, (long)dispOrigin.y);
}
if(strcmp(argv[1], "--origin") == 0 || strcmp(argv[1], "-o") == 0) {
int posX = dispOrigin.x;
int posY = dispOrigin.y;
int dispInd = 1;
if(argv[2]) {
posX = strtol(argv[2], NULL, 0);
}
if(argv[3]) {
posY = strtol(argv[3], NULL, 0);
}
if(argv[4]) {
long _dispInd = strtol(argv[4], NULL, 0);
if(_dispInd < dispOnlineCount) {
dispInd = _dispInd;
}
}
if(dispInd == i) {
err = CGConfigureDisplayOrigin(configRef, dispOnline[i], posX, posY);
}
}
}
}
err = CGCompleteDisplayConfiguration(configRef, kCGConfigurePermanently);
if(err != 0) NSLog(@"Error with applying configuration: %d\n", err);
return 1;
}
Save to a file called main.m
, then run:
clang -Wall -framework Foundation -framework ApplicationServices main.m -o cgorigin
Example (from Github):
assuming we have two monitors connected, both at 1920x1080
cgorigin --origin -1920 0 # positions the second monitor to the left of the main display
cgorigin --origin 0 0 # positions the second monitor to the right of the main display
cgorigin --origin -1920 1080 0 # positions the first monitor below the second display
I wrote a free terminal tool called displayplacer that let's you describe your layout and re-apply that same layout. It will let you set up profiles for changing the resolution, rotation, and positioning of your monitors.
For example, he's my 4 monitor setup profile. I have this command tied to a hotkey using BetterTouchTool. displayplacer "id:A46D2F5E-487B-CC69-C588-ECFD519016E5 res:3840x2160 hz:60 color_depth:8 scaling:off origin:(0,0) degree:0" "id:F466F621-B5FA-04A0-0800-CFA6C258DECD res:1440x900 color_depth:4 scaling:on origin:(-1440,1437) degree:0" "id:4C405A05-8798-553B-3550-F93E7A7722BB res:1440x2560 color_depth:8 scaling:off origin:(3840,-363) degree:270" "id:18173D22-3EC6-E735-EEB4-B003BF681F30 res:1920x1200 color_depth:8 scaling:off origin:(960,-1200) degree:0"
It's also available via Homebrew brew tap jakehilborn/jakehilborn && brew install displayplacer
osascript