How do I bring a processes window to the foreground on OS X? - macos

I have a simple shell/python script that opens up other windows. I'd like to bring the terminal where the script is running to the foreground when the script has finished.
I know the process ID of my parent window. How can I bring a given window to the foreground? I imagine I have to find out the window name from the PID along the way.

Not sure if there's a proper way, but this works for me:
osascript<<EOF
tell application "System Events"
set processList to every process whose unix id is 350
repeat with proc in processList
set the frontmost of proc to true
end repeat
end tell
EOF
You can do it with osacript -e '...' too.
Obviously change the 350 to the pid you want.

Thanks to Mark for his awesome answer!
Expanding on that a little:
# Look up the parent of the given PID.
# From http://stackoverflow.com/questions/3586888/how-do-i-find-the-top-level-parent-pid-of-a-given-process-using-bash
function get-top-parent-pid () {
PID=${1:-$$}
PARENT=$(ps -p $PID -o ppid=)
# /sbin/init always has a PID of 1, so if you reach that, the current PID is
# the top-level parent. Otherwise, keep looking.
if [[ ${PARENT} -eq 1 ]] ; then
echo ${PID}
else
get-top-parent-pid ${PARENT}
fi
}
function bring-window-to-top () {
osascript<<EOF
tell application "System Events"
set processList to every process whose unix id is ${1}
repeat with proc in processList
set the frontmost of proc to true
end repeat
end tell
EOF
}
You can then run:
bring-window-to-top $(get-top-parent-pid)
Quick test using:
sleep 5; bring-window-to-top $(get-top-parent-pid)
And swap to something else. After 5 seconds the terminal running your script will be sent to the top.

Related

how to close an active document in Mac OS using shell script

I am closing active document using apple script as below
tell application "Microsoft Word"
activate
try
if not (exists active document) then error number -128
close active document saving yes
on error
end try
end tell
want to do similar action using shell script. I want to gracefully close it and don't want to use kill command . And I don't want to use osascript to call an apple script . I want a graceful way using native shell commands
Hi you can use osascript in the shell code
#!/bin/sh
osascript <<EOF
tell application "$1"
close (every window whose name is "$2")
end tell
EOF
Compile this code and make filename.sh
or you can use
#!/bin/sh
osascript <<EOF
tell application "Preview"
close (every window whose name is "$1")
end tell
EOF
To use this from cmd type $./file_name Preview application name
Here I used the reference of https://ss64.com/osx/osascript.html

Using apple script to find out and compare process path by PID

I am using Apple Script to find the process PID by name, like ...
set appName to "KKK"
tell application "System Events"
set processPID to (unix id of processes whose name is appName)
end tell
With this script, I can know about PIDs of all processes which name is "KKK".
But I have a question here.
For example, there has three "KKK" process, "/FolderA/KKK", "FolderB/KKK", "FolderC/KKK"
I want to kill the process of "/FolderA/KKK", so I need to know which PID is belong to "/FolderA/KKK".
After run my script, I can get three PIDs, what can I actually do in Apple Script to distinguish which PID is what I want? (Maybe to get the process path by PID?)
Thank you
Instead of the name check for the path of the application, this is an example checking for Messages.app.
set appPath to "/Applications/Messages.app"
tell application "System Events"
set processPID to (unix id of 1st process whose POSIX path of application file is appPath)
end tell
It also can be done using the following:
do shell script "kill -9 $(ps -x | awk '/[F]olderA\\/KKK/{print $1}')"
You can also add ; exit 0 to the end to eat an error if the app isn't running and have no need to check or trap otherwise:
do shell script "kill -9 $(ps -x | awk '/[F]olderA\\/KKK/{print $1}'); exit 0"

Get PIDs of all open windows on MacOS

I tried to use the following AppleScript to get the PIDs of all the windows (including ones that are minimized). This script doesn't get the PIDs of windows on other desktops.
Is there any workaround for this so I can still get a list of opened windows across all desktops without having to activate individual processes and checking if they have windows?
tell application "System Events"
repeat with proc in (every process)
if exists(first window of proc) then
set pid to unix id of proc
log pid
end if
end repeat
end tell
PS, I'm not too proficient with AppleScript. I've managed to hack this together using StackOverflow. This might not be the most efficient way to do what I'm trying to do.
Looks like I got this to work with this ugly bash-applescript hack
osascript -e "tell application \"System Events\"
repeat with proc in (processes where background only is false)
set pname to name of proc
log pname
end repeat
end tell" 2>&1 |
while read line
do
echo "process " $line
pgrep $line
done
This prints something like
process Finder
818
process Google Chrome
3730
3734
3740
5838
process iTerm2
3750
4210
process Sublime Text
3822
Where PID 818 belongs to the Finder process and so on.

Bring Chrome started from script to front

I am wondering how I can launch a fresh new Chrome instance (see my script below) that will be brought to the front. Currently the shell script opens the new Chrome instance in the background, which is less than optimal. Executing the shell script from Applescript does nothing to remedy this.
The interesting thing is that if I open Chrome using a shell command directly from AppleScript it seems to open in the foreground:
set q to "'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' --user-data-dir=/tmp/1234"
do shell script q
Applescript
do shell script "~/bin/chrome-fresh"
Shell script
#!/bin/sh
# This is quite useful for front-enders, as it will launch a fresh
# Chrome instance with no loaded plugins or extensions that messes
# with your performance profiling or network debugging
#
# Install:
# install -m 555 ~/Downloads/chrome-fresh /usr/local/bin/
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
ARGS="$#"
# make a fresh user directory
TMP_USERDIR=$(mktemp -d);
# avoid the dialog on the first startup
touch "$TMP_USERDIR/First Run";
# start chrome using a fresh user directory
"$CHROME" --user-data-dir="$TMP_USERDIR" "$ARGS"
Run the command in background (put the & at the end of the command).
Use $! to get the process ID of the last command
# start chrome using a fresh user directory
"$CHROME" --activate-on-launch --user-data-dir="$TMP_USERDIR" "$ARGS" &
chromePid=$!
sleep 2
# bring Chrome
osascript -e 'tell application "System Events"' -e "tell (first process whose its unix id is \"$chromePid\" ) to set frontmost to true" -e 'end tell'
In the script bellow, I used a mix of Applescript and Shell commands. I am not Shell expert, so may be there are most efficient way to do it. At least, this script is working :
1) it takes all process containing specific name (i.e. = Chrome)
2) it goes through all found processes, and for each, get the time since it starts using "ps" shell command.
3) it compares that time with previous times found and if lower then it keeps the process information. The lowest time value is linked to the last starting instance of the process.
4) the process with the shortest time since it starts is the last one : it sets the frontmost property to true to make it foreground.
tell application "System Events"
set lastTime to 3600 -- max possible value of start time
set lastPID to -1 -- impossible : used to check if process has been found !
set Prlist to every process whose name contains "Chrome"
repeat with aProc in Prlist
set PStext to do shell script "PS -o etime -p " & unix id of aProc -- get the start time of the process
-- output is dd-hh:mm:ss if process has been stared few days ago
-- output is hh:mm:ss if process has been stared few hours ago
-- output is mm:ss if process has been stared few minutes or seconds ago
-- assumption is made that it just started few seconds ago
-- convert in seconds = mm*60 + ss
set runningTime to ((word 1 of paragraph 2 of PStext) as integer) * 60 + (word 2 of paragraph 2 of PStext) as integer
if runningTime < lastTime then
set lastTime to runningTime
set lastPID to unix id of aProc
set MyProc to aProc
end if
end repeat
if lastPID > 0 then -- if a process has been found
set the frontmost of MyProc to true -- set it in foreground
end if
end tell
I made several comments to make it clear about the "ps" command. If anyone knows how to get directly time in second from ps output, thanks. (I am quite sure there should be an easiest way !)

Access built-in Power Manager? states

Im trying to write a super simple applescript that will launch the OneDrive App, or ensure it is open, whenever the machine's power source is set to plugged in, and will quit, or make sure is closed, when the power source is set to battery.
I'm having trouble finding how to access the built-in "power indicator" in Yosemite. All of my searches lead to old, irrelevant results from years ago.
Edit: I think I will have to use a do shell script within the applescript using pmset -g batt
Now drawing from 'AC Power'
-InternalBattery-0 100%; charged; 0:00 remaining
And parse this result, but I am not sure how.
Edit: Here it is for anyone in the future who may want something similar:
global appName
on appIsRunning()
tell application "System Events" to (name of processes) contains appName
end appIsRunning
on acIsConnected()
return (do shell script "system_profiler SPPowerDataType | grep -q 'Connected: Yes' && echo \"true\" || echo \"false\"") as boolean
end acIsConnected
on toggleApp()
if my acIsConnected() then
if not my appIsRunning() then
tell application "Finder"
open application file (appName & ".app") of folder "Applications" of startup disk
end tell
end if
else
tell application appName
quit
end tell
end if
end toggleApp
-- This will only be executed once.
on run
set appName to "OneDrive"
end run
-- This will be executed periodically, specified in seconds, every return.
on idle
my toggleApp()
-- Execute every 2 minutes.
return 120
end idle
-- Not mandatory, but useful for cleaning up before quiting.
on quit
-- End handler with the following line.
continue quit
end quit
Here is a one-liner that polls for connected status, since I guess you can have less than 100% and still be connected (charging).
set acConnected to (do shell script "system_profiler SPPowerDataType |grep -q 'Connected: Yes' && echo \"true\" || echo \"false\"") as boolean
Here's another one liner...
set acConnected to last word of paragraph 1 of (do shell script "ioreg -w0 -l | grep ExternalChargeCapable")
If you are happy to use a third party tool, you can avoid polling for the battery state. This will make your script more efficient.
Power Manager can run AppleScripts when the battery state changes. How to Run a Command When Switching to Battery Power, walks through how to set this up for scripts.
Swap out the #!/bin/sh for #!/usr/bin/osascript in the script, and you can use AppleScript.
Disclaimer: I wrote Power Manager and can answer comments about how it works.
Provided you have battery icon on screen's top right:
tell application "System Events" to tell process "SystemUIServer" ¬
to value of attribute "AXDescription" of ¬
(first menu bar item whose value of attribute "AXDescription" ¬
begins with "Battery") of menu bar 1
You get "Battery: Charged" or "Battery: Calculating Time Remaining… " or something else

Resources