How can I change the main display via AppleScript? - applescript

From the Displays pane in System Preferences, I can manually change the main monitor by dragging the menu bar from one display to the other. I'd like to automate this and make it part of an AppleScript.

The tool I wrote, displayplacer, does this.
Configure your screens how you like, drag the "white bar" to your primary screen in the macOS system settings, and then execute displayplacer list. It will output the command to run to put your screens in their current configuration. The screen with origin:(0,0) is the main display with the "white bar". Run this terminal command through a script, Automator, BetterTouchTool, etc.
Example profile 1 puts the white bar on the menu bar on the left monitor.
displayplacer "id:<leftScreenId> res:1920x1080 scaling:on origin:(0,0) degree:0" "id:<rightScreenId> res:1920x1080 scaling:on origin:(1920,0) degree:0"
Example profile 1 puts the white bar on the menu bar on the right monitor.
displayplacer "id:<leftScreenId> res:1920x1080 scaling:on origin:(1920,0) degree:0" "id:<rightScreenId> res:1920x1080 scaling:on origin:(0,0) degree:0"
Also available via Homebrew brew tap jakehilborn/jakehilborn && brew install displayplacer

The displays are controlled by the /Library/Preferences/com.apple.windowserver.plist preference file:
A flag controls whether the main display is the onboard screen the DisplayMainOnInternal key.
The DisplaySets key contains the list of the display sets. The first set is the one used (fact to check).
In the set, each item contains the screen properties. The IOFlags key seems to indicate if the display is the main one (value of 7) or not (value of 3).
Before going Apple Script, you may change the display configuration by hand, and save a copy of the /Library/Preferences/com.apple.windowserver.plist file to study it.
Note that the following procedure has not been tested !!!
With AppleScript, the keys in the plist file are changed individually, in order to change the main display:
Make a backup of the /Library/Preferences/com.apple.windowserver.plist (in case of)
Alter the display set the select the main display (DisplaySets and IOFlags keys) by using the defaults command
Restart the Window Server: killall -KILL SystemUIServer

You should see if you can do it via AppleScript's User Interface Scripting. It allows you to manipulate an application's GUI elements; useful when the app doesn't support scripting directly. I'd test it myself but I don't have any extra displays lying around.
Here's a pretty good overview by MacTech.

Much like you can tell System Events.app to sleep your Mac, you can tell Image Events.app to mess with your displays. The Image Events application provides a "displays" collection. Each display has a "profile" with lots of goodies. However, everything I just mentioned is read-only, so I don't have a good way to do it from within script.
You might have better luck in Automator – Hit record, run System Preferences, go to Displays, drag the menu bar to the other screen, and hit stop. I bet something will work.

Using AppleScript, you can invoke default to write the setting to change the main monitor.

Related

How to modify MacOS Dock shortcuts/hotkeys?

I want to modify/change/add MacOS Dock shortcuts/hotkeys.
e.g., of a shortcut that is available by default:
Option-Click on Dock app icon of an app that is not currently open = Hide the currently active app and then Open the app that was clicked
(from: https://support.apple.com/kb/PH21922?locale=en_US)
One very specific ability that I want:
Open and then Hide an app
Shift-Click on Dock app icon = Open and then Hide that app
(or use another easy modifier-key-combo with the click)
I am aware of the bash command open -a App --hide (e.g., open -a TextEdit --hide). I want to implement this exact functionality with a convenient Dock shortcut like the one mentioned above. If you're wondering "why?": sometimes I just want to open an app because I know that I will need it soon, but I'm still busy with another app, so just open this second app and then immediately hide it so it doesn't get in my way while I'm still busy with that first app.
How do I do this?
You can't.
These keyboard bindings are built into the Dock application, and cannot be modified.
The Mac utility program, Keyboard Maestro, does what you've asked, with shortcut keys, without using the Dock:
open, then immediately hide/minimize
option+open
I came up with a related solution: (in case anyone is interested)
an AppleScript App that presents a pick list
Method:
create a plain text document containing a list of the apps you want to handle (use correct name, no path, no extension, one name per line, no commas)
open 'Script Editor' (/Applications/Utilities)
copy-pasta the following code (and edit the first code line for the path to your text file from first step)
set apps_file to ("path:apps_list.txt")
set apps_list to paragraphs of (read file apps_file)
set apps_pick to choose from list apps_list with prompt "Select one or more apps." with multiple selections allowed
if result is false then return
set path_base to "Macintosh HD:Applications:"
set path_msft to path_base & "Microsoft Office 2011:"
set path_utly to path_base & "Utilities:"
set spec_msft to "Microsoft"
set spec_utly to "Activity Monitor, Terminal"
repeat with apps_this in apps_pick
if apps_this contains spec_msft
set path_this to path_msft
else if apps_this is in spec_utly
set path_this to path_utly
else
set path_this to path_base
end if
set apps_open to path_this & apps_this & ".app"
run application apps_open
end repeat
return
i. navigate menu 'File -> Export...'; ii. use the option 'File Format: Application'; iii. Save; (put the resulting app in your Dock)
Its not quite as convenient as I hoped, but, not too shabby.

Xcode, default window layouts?

No-one has been able to answer this question.
It would seem to be impossible to have XCode open this way.
However Youssef provided the most useful answer - so Youssef gets the points, thank you Youssef.
Note for future readers .. the mac utility Moom is excellent for some, but not all, problems of this nature. Again it is not a total solution.
Using the current up-to-date XCode,
Whenever I OPEN a project in XCode (or start a new project),
it looks like this:
However, I want it to look like this:
Again that's when I OPEN a project.
Is there any way to achieve this? Thanks.
Go to Xcode (in the top menu bar) --> Preferences...
Switch to the Behaviors tab and modify what you want in the Running section
You'll get something like this:
You can choose to show/hide what you need, and specify the default behavior
Cheers
EDIT:
After understanding what you need, I will modify my answer.
There is no way to force XCode to automatically enter a behavior at startup.
The best you can do is to create a custom behavior and give it a keyboard shortcut. And when you start XCode just use the keyboard shortcut to enter the desired behavior.
This is how it is done:
In the behaviors tab (above) click on the + sign at the bottom
Then enter the desired name of this behavior (Maybe StartupBehavior)
Click on the left button to modify the shortcut key. My preferred shortcut key is Command + ` (the button to the left of the '1' key). This is because it will not override any other command and it is easy to click.
Note: you can specify any shortcut you like and dont be afraid to override one that already exists if you don't use it.
Now you need to configure your behavior the way you like it
Close the preference windows.
Now everytime you start XCode just use the shortcut key you specified (Command + ` in my case) to quickly load your behavior
Note:
If you dont like keyboard shortcuts you can also load your behavior by going to Xcode (menu bar) --> Behaviors --> Select your behavior
That is the quickest way you can achieve what you want. I dont think you will be able to force Xcode to run your behavior automatically on startup.
Hope it helped.
Cheers
(not really default layout, you have to hit at least 2 keys simultaneously once XCode is open) You could set up a behavior for "Build->Starts" and hit "CMD + B"
after opening XCode / any Project. This way it will 1. change to your
Layout even if there are any errors and Build fails and 2. you don't
have to Stop it again.
As already said, it's not a default layout, but I like to let the compiler run through projects of other people at the beginning anyway.
You could search for some Keys in XCodes preference file in
~/Library/Preferences/com.apple.Xcode.plist as already suggested in
my comment, I'm not experienced enough to know which are the right
ones, sorry.
Wrap the .xcodeproj File opening in an application. E.g. in no way "clean", but anyway:
Set up an XCode behavior like in option 1
Open Automator, choose Application, drag "open Finder Items" and "run AppleScript" inside.
on run {input, parameters}
set frontmostAppName to name of (info for (path to frontmost application))
repeat while frontmostAppName is not "XCode.app"
set frontmostAppName to name of (info for (path to frontmost application))
delay 0.5
end repeat
try
tell application "System Events" to keystroke "b" using {command down} --simulates CMD + B
end try
return input
end run
Insert some applescript like the above and save the Automator application.
RightClick -> getInfo on any .xcodeproj File in Finder/on Desktop, in "open with" select your new Automator app, click add and back in the info panel -> check "Change All"
You can obviously create a new Behavior instead of using Build->starts, assign a different Hotkey in XCode and script e.g. tell application "System Events" to keystroke "i" using {command down, control down, shift down, alt down} , optimize the applescript somehow or do everything via a real cocoa app if you want
Well, you may be able to approach it using preconfigured xcuserstate files nested in your project templates' default workspace directory, but that is going to be a pain to tweak and maintain. I'm not even sure it would work.
I would personally just approach it by using Behaviors.
So:
1) create a Behavior
2) Give it a convenient key binding
3) Then define the Behavior. For example:
ASCII Behavior Editor:
...
√ Show *Debugger* with *Console View*
√ *Hide* utilities
...
That should do it. Just hit the assigned key command when you want to restore that display state, regardless of its initial state.
Of course, you can do a few other things or all sorts of arbitrary stuff by running an external AppleScript (triggered with a Behavior's run script facility).

Have one application execute an action when another application is given a command using AppleScript?

I know nothing about AppleScript, but I wonder if it could make my life easier: is there a way to write an AppleScript that tells Safari / Firefox / Chrome to refresh the current tab when I save a document in another application, say TextWrangler? Essentially, I want to map the Command+S keyboard shortcut to do two things at once in two separate applications.
If that’s not possible, can you script one application so that saving one file executes a command in another window in that same application?
There are different possible approaches to implement this, but the most straightforward would probably be to create a script that executes all steps you need (i.e. save the document and refresh the window) and bind that to the Cmd+S keyboard combo in the triggering application.
What you need for this approach to work, is, in order:
a method to bind a key combo to a script effective only in a specific application. OS X’ Automator Services fit that bill: their scope can be restricted to a single application (select it in the “only in” drop down at the top of the workflow actions), and they can be assigned a shortcut in the Keyboard preference pane of System Preferences.
a way to relay your commands to the applications they target. AppleScript can help you in two different ways, depending on the fact if your applications are scriptable, i.e. if they have a scripting dictionary you can inspect in the AppleScript editor:
if they do, and their terminology includes the saving action for the editor on one side (most scriptable document based apps do so in the form save <document>), the page refreshing for the browser(s) on the other (Chrome has reload <tab>, Safari gets the same result via a JavaScript detour, i.e. do JavaScript "window.location.reload()" in <document> – I don’t use Firefox), you are set.
if they do not, GUI Scripting might help, i.e. simulating a click on the right UI element (menu or toolbar) via tell application "System Events" to tell process <your process> to click item x of menu y.
That script can then be embedded into the Automator workflow (in an “Run AppleScript” action, to be precise).
As you can see, a lot depends on the exact software you are using. if you are new to AppleScript and the above baffles you, I’d suggest spending a bit of time on the AppleScript pages of Mac OS X Automation (where you’ll also find example scripts which will kick start you into things like GUI Scripting).
One final note: as of this writing, sandboxed applications do not honor key combos assigned to them in the Keyboard Preference pane (they do honor global key combos set there – just not those specifically targeting them). This means you cannot, for instance, currently override TextEdit’s Cmd+S shortcut for saving in Lion. As long as your editor is not sandboxed (easily checked in Activity Monitor), you should have no issue with this.
One solution would be to create a folder action to refresh the current tab when a new file is saved in the folder.
on adding folder items to theFolder after receiving theFiles
tell application "Google Chrome"
activate
tell window 1 to tell active tab
set URL to (get URL)
end tell
end tell
end adding folder items to

OS X kernel extension graphical uninstaller

XCode doesn't include uninstallation options for their packager. Generally users simply drag the app to the trash if they want to uninstall it - most apps are self contained in the app package.
However, I have a kernel extension which must be uninstalled using a few simple command lines. There is a script that works, but I am required to provide a graphical uninstaller.
I don't expect there's a plug-n-play example code out there that provides a way to run the script while showing a progress bar, but I'm hoping someone has dealt with this or has a few pointers on how to accomplish this quickly and easily
The script is only two lines with no feedback, so we can execute the commands in the app, as long as we can easily request and use root permissions securely (ie, let OS X handle the permissions - we merely ask for OS X to give them to us which should cause it to ask the user for them similar to how it happens with the package installer) inside the app.
There's a reasonably good approach using a Cocoa-Applescript project in xcode to run a shell script here:
http://www.mactech.com/articles/mactech/Vol.22/22.08/GUI-upyourScript/index.html
It covers using a progress bar, handling errors, and getting the correct root permissions to run the shell script.
Unfortunately it's a bit long to cut and paste here, but the general steps are:
Create new xcode project of type Cocoa-Applescript app
Create and test the intended shell script, add it to your project
Edit the MainMenu.nib to add and name a button(theObject) and progress bar(pMainProgress), then edit title and other aspects of the ui to taste
Tie the button to the applescript in the project (in the Inspector with the button selected check the action box and put in myprojectname.applescript)
Edit the applescript to something akin to the following:
on clicked theObject
-- setup
set myPath to POSIX path of (path to me) as string
-- Start progress bar
set uses threaded animation of progress indicator "pMainProgress" of window "wMain" to true
tell progress indicator "pMainProgress" of window "wMain" to start
-- Do it!
try
do shell script quoted form of myPath & "Contents/Resources/backup.sh" with administrator privileges
on error number 255
display dialog "Sorry, an error occurred. I can't make the copy."
end try
-- Stop progress bar
tell progress indicator "pMainProgress" of window "wMain" to stop
set uses threaded animation of progress indicator "pMainProgress" of window "wMain" to false
end clicked
You can further customize the app (name, for instance) and add text boxes to the window to alert the user what step is happening if you're running multiple scripts (put set the contents of text field "efStatus" of window "wMain" to "Copying files..." in your script after adding a text field to the ui with the name "efStatus")

Run another application using AppleScript without showing it on the dock

Using AppleScript you can create a script that runs another application, and then save that script itself as an application and place it in the dock. The problem (not really a problem) is that when you click it, it will still show the other application on the dock. Is it possible to prevent the other application from showing in the dock, yet show its GUI as it would normally do when executed?
Thanks
The only solution I can think of is to actually modify the 'other app' to have no Dock icon. It works, but it's nasty:
•Yep, you're directly modifying the other app—not doing something from your script.
•Accordingly, it will change every launch of said other app, not just invocation from your script.
•It prevents OtherApp from having a menubar (though key combos and any in-window controls will still work).
It's easily reversed though, and can almost always be done just by adding a GUI mode flag to the app's Info.plist file:
Right- or Ctrl-click the other app and Choose 'Show Package Contents'
Open the 'Contents' folder
Open the Info.plist in your text/xml editor of choice*
Add these two lines right after the first line that says <dict>
<key>NSUIElement</key>
<true/>
Save, then fire up the app. Remember… no menubar, so make sure one of its windows has focus and -Q to quit when you verify it runs with no Dock icon.
*If you're squeamish with editing xml, or if the plist file is the binary variety, you'll need a dedicated plist editor. Apple's own Property List Editor is included with their free Dev Tools.
Add a Child to the root ("Information Property List").
Set the name to NSUIElement.
From the Edit (or context) menu, set the Value Type to Boolean.
Click the checkbox ON (sets the bool to true).
Building off the previous answer -- you can modify the Info.plist of your Applescript application with the same XML code. This will prevent the Applescript app from displaying an icon (and having a menubar, which in my experience is unusable anyway for this type of 'app'), but your main application -- the one you're launching from the applescript -- will display in the Dock as usual.
I tried this on OSX 10.7 Lion and it worked successfully.

Resources