I've found a way to directly write the Preferred Position values using the shell command defaults
. I'll leave the automation part out since I don't know the specifics of your project (I assume you know how to automate shell commands as the current user.) This should allow you to change the preferred values but won't move the menu bar items without a restart.
Background
The Defaults system is used to store certain user preferences on macOS. This happens to include the Preferred Position for Menu Bar items. I'll let Apple explain the basics better:
From man defaults
:
Defaults allows users to read, write, and delete Mac OS X user defaults from a command-line shell. Mac OS X applications and other programs use the defaults system to record user preferences and other information that must be maintained when the applications aren't running (such as default font for new documents, or the position of an Info panel). Much of this information is accessible through an application's Preferences panel, but some of it isn't, such as the position of the Info panel.
User defaults belong to domains, which typically correspond to individual applications. Each domain has a dictionary of keys and values representing its defaults; for example, "Default Font" = "Helvetica". Keys are always strings, but values can be complex data structures comprising arrays, dictionaries, strings, and binary data. These data structures are stored as XML Property Lists.
In short, Defaults are categorized under Domains (the app or service the setting belongs to), are identified using Keys (the name of the particular setting), and each *Key has a Value assigned to it.
The Preferred Position defaults we care about are not all under one domain, since individual apps can add new items to the Menu Bar. However, the keys all share this format:
NSStatusItem Preferred Position <menu-item-name>
where <menu-item-name>
is the name of each item a particular app or service adds.
The values are all stored as float
numbers, usually integers but some have a decimal point.
Here are the macOS built-in Menu Item Defaults on my machine as an example.
'com.apple.systemuiserver': {
"NSStatusItem Preferred Position Item-0" = 23;
"NSStatusItem Preferred Position Siri" = 61;
"NSStatusItem Preferred Position com.apple.menuextra.TimeMachine" = 548;
"NSStatusItem Preferred Position com.apple.menuextra.airport" = 483;
"NSStatusItem Preferred Position com.apple.menuextra.battery" = 179;
"NSStatusItem Preferred Position com.apple.menuextra.bluetooth" = 513;
"NSStatusItem Preferred Position com.apple.menuextra.textinput" = 127;
"NSStatusItem Preferred Position com.apple.menuextra.volume" = 260;
}
com.apple.systemuiserver
is a domain containing the key NSStatusItem Preferred Position Siri
with value 61
.
Listing All Current Preferred Position Defaults
In order to list all the domains, keys, and values for our Preferred Position Defaults, we can use the defaults find
command to search for matches.
The command we need in this instance is defaults find "NSStatusItem Preferred Position"
.
$ defaults find "NSStatusItem Preferred Position"
Found 1 keys in domain 'com.coconut-flavour.coconutBattery-Menu': {
"NSStatusItem Preferred Position Item-0" = "344.5";
}
Found 1 keys in domain 'com.lastpass.LastPass': {
"NSStatusItem Preferred Position Item-0" = 795;
}
Found 8 keys in domain 'com.apple.systemuiserver': {
"NSStatusItem Preferred Position Item-0" = 23;
"NSStatusItem Preferred Position Siri" = 61;
"NSStatusItem Preferred Position com.apple.menuextra.TimeMachine" = 548;
"NSStatusItem Preferred Position com.apple.menuextra.airport" = 483;
"NSStatusItem Preferred Position com.apple.menuextra.battery" = 179;
"NSStatusItem Preferred Position com.apple.menuextra.bluetooth" = 513;
"NSStatusItem Preferred Position com.apple.menuextra.textinput" = 127;
"NSStatusItem Preferred Position com.apple.menuextra.volume" = 260;
}
Found 1 keys in domain 'org.pqrs.Karabiner-Menu': {
"NSStatusItem Preferred Position Item-0" = 750;
}
Found 1 keys in domain 'com.google.GoogleDrive': {
"NSStatusItem Preferred Position Item-0" = 607;
}
... and so on ...
Reading and Writing the Value of a Given Domain & Key
In order to read the value of a given domain and key, we need to use the defaults read
command. To write, we use defaults write
.
Here, I will read the value of the key NSStatusItem Preferred Position Siri
at the com.apple.systemuiserver
domain.
Note that the domain and key must be enclosed in double quotes.
$ defaults read "com.apple.systemuiserver" "NSStatusItem Preferred Position Siri"
61
Here, I will change the the key NSStatusItem Preferred Position Siri
at the com.apple.systemuiserver
domain to the value 42.7
.
Note that the domain and key must be enclosed in double quotes, and the -float
before the value
$ defaults write "com.apple.systemuiserver" "NSStatusItem Preferred Position Siri" -float 42.7
$ defaults read "com.apple.systemuiserver" "NSStatusItem Preferred Position Siri"
42.7
Again, I'll leave exactly how you automate this up to you, but this can all be easily integrated into your code.
If this doesn't work out for you, here are some links to the Apple Developer AppKit docs for adding items to the Menu Bar as well as for accessing the Defaults system using objective-c and swift. Not sure if they'll be any use to you but maybe they'll set you on the right track.
https://developer.apple.com/documentation/appkit/nsstatusitem
https://developer.apple.com/documentation/appkit/nsstatusbar
https://developer.apple.com/documentation/foundation/userdefaults