Applescript opening wrong version of OS X app - applescript

My script is opening an old version of the app (which I wrote). I have searched the HD and cannot find the old app. The new version is in the applications folder. The script is in the scripts folder.
I made a new folder and put the script and the new app in it. Running the script still opens the wrong app. App2 is the problem child.
Where is the wrong path coming from?
How to:
Point the script at the correct app? I don't want a path in the script.
Find the old app and delete it?
property checkInterval : 5 -- Number of seconds between checks. Adjust to requirement.
global App1WasOpen, GUIScriptingWasEnabled, previousText
on run
-- When the script starts up, note if App1 is running and GUI Scripting is enabled.
tell application "App1" to activate
tell application "System Events"
set App1WasOpen to (application process "App1" exists)
set GUIScriptingWasEnabled to (UI elements enabled)
end tell
-- Enable GUI Scripting if nec. and give the 'previousText' variable an initial value.
switchGUIScripting(true)
set previousText to ""
end run
on idle
-- Each time the script's polled by the system, check that App1's open.
tell application "System Events" to set App1IsOpen to (application process "App1" exists)
if (App1gIsOpen) then
set App1WasOpen to true
-- Get the latest value for 'beam'.
tell application "App1"
set hdg to getHeading
set beam to hdg as string
end tell
if ((count beam) < 3) then set beam to text -3 thru -1 of ("000" & beam)
-- If it's changed since the last check, enter it into App2 and keep it for later checks.
if (beam is not previousText) then
--display dialog "Opening App2" buttons {"OK"}
tell application "App2" to launch
--activate application "App2"
tell application "System Events"
set startTime to current date
repeat until exists (text field 1 of window "App2" of application process "App2")
if (current date) - startTime is greater than 5 then
error "Could not find text field 1 of window AppB of application process App2"
exit repeat
end if
delay 0.2
end repeat
tell application process "App2"
try
set value of text field 1 of window "App2" to beam
end try
end tell
end tell
--tell application "App1" to activate
set previousText to beam
end if
-- Request the next 'idle' event in 'checkInterval' seconds' time.
return checkInterval
else if (App1WasOpen) then
-- App1 was open at the last check, but isn't now. Tell this script applet to quit.
quit
-- It'll actually quit on the next idle event, so request a short interval.
return 1
end if
end idle
-- Unless GUI Scripting was already on when the script started to run, turn it on or off as per the parameter.
on switchGUIScripting(onOff) -- 'onOff' is 'true' for on, 'false' for off.
if (not GUIScriptingWasEnabled) then
tell application "System Events"
activate
set UI elements enabled to (onOff)
end tell
end if
end switchGUIScripting
-- When this applet's told to quit, restore the previous GUI Scripting state before it does.
on quit
switchGUIScripting(false)
continue quit
end quit
Followup:
I used "Show in Finder" on the app's icon in the dock to point me to 17 Xcode archives, which I deleted. Now the script has a recurring message of "An error of type -10660 has occurred", and App2 never opens.
I opened the script editor, copied the code to a new script window and compiled it with a different name. Still doesn't open App2.

Try finding the Applications id with:
set appID to get id of application "/Applications/Safari.app"
Once you have found it, refer to the id rather than
tell application id "com.apple.Safari" to launch

Related

Get process id after spawning new application via applescript(osascript) using tell

tell application "Google Chrome"
make new window
open location "https://google.com"
end tell
The above command spawns up an instance of google chrome. I want to get the process id of this process so that I can kill it later. Please note that I am using Google chrome for example, but I can spawn up any process any number of times. Just need to get the process id.
You can store a reference to the window you make in a variable, and use that variable to close it later. The following opens two windows (to Google and Yahoo), waits three seconds, the closes the Google window:
tell application "Google Chrome"
set windowGoog to make new window
tell windowGoog to open location "https://google.com"
set windowYah to make new window
tell windowYah to open location "http://Yahoo.com"
end tell
(*
You can do whatever you need to do here. I've added a three second delay just
to give a sense of time, but that's just for show.
*)
delay 3
tell application "Google Chrome"
close windowGoog
end tell
If you want to keep a reference to the window across multiple runs of the script (e.g., you run the script once to open the window, then run it again later to close it) make the variable a property, and use if statement to check if it has a value, like so:
(*
These two lines set 'windowGoog' and 'windowYah' to 'missing value' on the
first run, and then remember whatever value you set until the next time
you recompile the script
*)
property windowGoog : missing value
property windowYah : missing value
tell application "Google Chrome"
if windowGoog is missing value then
set windowGoog to make new window
tell windowGoog to open location "https://google.com"
else
close windowGoog
set windowGoog to missing value
end if
if windowYah is missing value then
set windowYah to make new window
tell windowYah to open location "http://Yahoo.com"
else
close windowYah
set windowYah to missing value
end if
end tell

Restore windows by application name (within a function) in AppleScript?

I have a function where I pass in the name of an application. Within the function, one of the things I'd like to do is restore the windows of the application:
on test(applicationName)
-- do some work
-- restore all windows
-- do some more work
end test
I've found references on how to restore the windows of an application by setting the miniaturized property, ala:
tell application "Maps"
set miniaturized of windows to false
end tell
(see Un-minimizing an app with Applescript)
But this requires one to specify the name of the app at compile time - I have to hard code the name of the app into the code - I can't use "tell application applicationName" even though applicationName is a string:
on test(applicationName)
-- do some work
-- restore all windows
tell application applicationName
set miniaturized of windows to false
end tell
--- do some more work
end test
(see tell application - string vs. string?)
Is it possible to restore the windows of an application, when I reference the name of the application as a variable?
There must be another way to do this, but the only examples I've found to do this is the "tell application/set miniaturized of windows" approach.
You might have more success using System Events to access the attributes of application process windows to control their miniaturised states.
Unlike trying to do it via the application objects themselves, the applications in question do not need to be AppleScript-able. I believe all processes running under System Events that contain windows have a set of attributes that are accessible via AppleScript, including one called AXMiniaturized, whose value is either true or false.
Although I didn't attempt to diagnose the problem with your method, I did draft this method (albeit on MacOS 10.13), which appears to corroborate what I've said. Hopefully the script is pretty self-explanatory:
use application id "com.apple.systemevents"
to getProcessesWithMiniaturizedWindows()
return the name of (every process whose value of ¬
attribute "AXMinimized" of every window ¬
contains true)
end getProcessesWithMiniaturizedWindows
to restoreAllWindowsForProcess:(procName as text)
local procName
set value of attribute "AXMinimized" of (every window ¬
of the process named procName whose value of ¬
attribute "AXMinimized" = true) to false
end restoreAllWindowsForProcess:
on run
repeat with processName in getProcessesWithMiniaturizedWindows()
restoreAllWindowsForProcess_(processName)
end repeat
end run
NB. You may need to grant Assistive Access Rights for System Events in System Preferences > Security & Privacy > Privacy > Accessibility (High Sierra).
The simple and straightforward solution would be this:
on test(applicationName)
-- do some work
-- restore all windows
tell application "System Events"
tell process applicationName
tell every window
set value of attribute "AXMinimized" to false
end tell
end tell
end tell
--- do some more work
end test

AppleScript, quit an app by id, safely

It's possible to run multiple instances or copies of the same app on a Mac. But AppleScript can't seem to identify them separately. Say my app is "FileMaker Pro" and I have multiple copies of it running. Having AppleScript tell "FileMaker Pro" to quit, I believe quits the first one that ran, which might not be the one I want it to quit.
I want to write a script that first will identify the frontmost application, then go off and do some other stuff (which might bring other apps to the front) then SAFELY quit the original frontmost application that it identified at the start.
Some googling I've done has found suggestions where I identify the the frontmost application by process id and then
do shell script "kill ..."
but from what I can tell "kill" doesn't ask to save changes, etc. (so it doesn't SAFELY quit").
I want this script to do exactly what the AppleScript quit command or manually choosing quit from the file menu would do, including ask to save changes or whatever else.
Is this possible? If so how?
For a copy of an application: it's possible by using the path of the application instead of the name.
tell application "System Events"
tell (first application process whose frontmost is true)
set x to its application file -- get the path of this application (the result is an alias of "System Events")
end tell
set thisAppPath to path of x -- get the path (a string)
end tell
--- *** go off and do some other stuff ****
---
--- SAFELY quit the original frontmost application that it identified at the start.
tell application thisAppPath -- the path must be a string
try -- *** use 0 to no limit ***
with timeout of 240 seconds -- a time limit is given to the user to save changes, etc.
quit
end timeout
on error -- (timeout error): the user do nothing because the application is still open
-- do something
end try
end tell
--
-- script after the application quits
--

Bring application to front by ID

I want to use AppleScript to bring an app to the front. If I run the following script
tell application "System Events"
tell process id 916
activate
end tell
end tell
the process doesn't come to front. Instead, only the active window of the currently front-most app loses focus, but that app stays in front.
Is it even possible to do this with a process ID rather than an application name? I have tried this on Mac OS X 10.6.8 and 10.7.5.
I am looking for a plain AppleScript solution. It should not use any shell commands or any other solution. I want to use the process ID number because I might have running multiple instances of the same application (in the same file location).
I have found the following solution:
tell application "System Events"
set myProcesses to every process whose unix id is myPocessID
repeat with myProcess in myProcesses
set the frontmost of myProcess to true
end repeat
end tell
Foo's answer works too:
tell application "System Events"
set frontmost of every process whose unix id is myProcessID to true
end tell
set processID to 432--currently firefox for me
tell application "System Events" to set a to file of 1st item of (processes whose unix id = processID)
activate application (a as alias as string)
This uses the path to the app file, which is apparently necessary (not just the name).
I have another answer which uses do shell script; I could add that if you want.

How to check in AppleScript if an app is running, without launching it - via osascript utility

Consider the following AppleScript:
on is_running(appName)
tell application "System Events" to (name of processes) contains appName
end is_running
set safRunning to is_running("Safari")
if safRunning then
tell application "Safari"
-- Stuff I only want executed if Safari is running goes here.
end tell
return "Running"
else
return "Not running"
end if
The problem: when I run this via the osascript command line utility, if Safari is not running, it gets launched and the script reports "Running". This is not the behaviour I desire or would expect. Note that it works as desired/expected when run within AppleScript Editor.
Is this an osascript bug / known issue? Or is it somehow intended behaviour for reasons I'm missing? Can anyone get it to work as desired? (BTW I'm running OSX 10.7.5; I can't see how to get osascript to report a version number).
If you comment out the tell / end tell lines, it behaves as I'd expect: if Safari is not running, it doesn't launch it, and prints "Not running". So it seems to me like the tell is what's causing Safari to be launched, but it doesn't need to be actually executed, just present in the script...? For a while I wondered if maybe this was just how tell is supposed to work, but since it doesn't work like this in AppleScript Editor, I guess not...
In fact, here's another, madder, version with similar behaviour:
on is_running(appName)
tell application "System Events" to (name of processes) contains appName
end is_running
set safRunning to is_running("Safari")
return safRunning
if false then
tell application "Safari"
end tell
end if
This still always launches Safari, even though tell is inside an if false block after the return statement! (But again, this is fine in AppleScript Editor.)
BTW, this behaviour isn't limited to Safari, but it also isn't universal:
Affected apps include: Safari, TextEdit, iPhoto, AppleScript Editor, iTerm, ...
Non-affected apps include: Google Chrome, iTunes, Preview, Mail, Terminal, Address Book, Echofon, ...
So, does anyone have any ideas about how I might fix or route around this? Is it an osascript bug? Or am I missing something about AppleScript's semantics?
For context: I'm trying to write a script (to be embedded/called from some python) which queries open browsers for the URLs of any tabs they have open; I've got it all working fine except that it always launches Safari, whether it's open or not. I've boiled down that undesirable behaviour to the simple test case shown above. I'm not aware of any way to run this script from python without using osascript, other than appscript, which I don't want to use because it's no longer developed/supported/recommended.
Many thanks for all inputs / insights!
I suspect the reason you are getting this is because each time you call the script from the command line with osascript the script is being compiled.
The act of compiling on a tell application will afaik make the app launch.
Calling the script from the command line with osascript from a pre-compiled file i.e .scpt does not cause this behaviour because the is no compiling to be done.
But calling it from a plain text (.txt,.sh ) file will so the app will launch.
If you do not want to use a .scpt file and want to use a plain text file then you could try the trick of putting a run script command in the applescript.
on is_running(appName)
tell application "System Events" to (name of processes) contains appName
end is_running
set safRunning to is_running("Safari")
if safRunning then
run script "tell application \"Safari\"
open location \"http://google.com\"
end tell"
return "Running"
else
return "Not running"
end if
The script in the run script is only compiled when needed. You will need to escape any characters like quotes as in my example.
It will be easier if you write the script in a normal applescript document first and compiled it to check for errors.
Then copy it to the plain text file.
UPDATE **
The method I used above was from a old script I had used to solved this issue a while before I answered here.
The answer works and is not trying to be elegant. ;-)
I actually like user1804762 method below. As it does work but feel the Answer is not clear enough so I will give an example on using it.
set appName to "Safari"
if application appName is running then
tell application id (id of application appName)
open location "http://google.com"
end tell
return "Running"
else
return "Not running"
end if
This script can be run from the command line with osascript
example:
osascript /Users/USERNAME/Desktop/foo.scpt
Notice that the script is saved as a compiled script. This will work ok and you can also save and use it as a plain text script.
i.e.
osascript /Users/USERNAME/Desktop/foo.applescript
Some Info:
"Enhanced Application Object Model":
tell application "iTunes"
if it is running then
pause
end if
end tell
You can also do it that way:
if application "iTunes" is running then
tell application "iTunes" to quit
end if
You can also do this:
get name of application "iTunes"
get version of application "iTunes"
And to complete the journey:
get id of application "TextEdit" --> "com.apple.TextEdit"
tell application id "com.apple.TextEdit"
make new document
end tell
That was the "Enhanced Application Object Model". If an app still launches (for example, the first time you compile & execute the script) I assume it is because AS has to get some info from the app which it did not found in the dictionary (or something like that...?).
OK, I know this question is really old, but I stumbled on it looking for a different issue and had to pipe in considering how complicated some of these responses are.
The simple code to achieve what you want(ed) is:
tell application "System Events"
if application process "Safari" exists then
-- do stuff you want to do only if Safari exists
end if
end tell
On older systems, the syntax used to be:
tell application "System Events"
if exists of application process "Safari" is true then
-- do stuff you want to do only if Safari exists
end if
end tell
One of these should definitely work for you, intrepid searcher of Applescript solutions for action only when an app is running.
Oh! Bonus tip: And if you're not sure what the application process name is exactly (it is usually but not always the app name), before coding your final script run…
tell application "System Events"
get every application process
end tell
And find your app process name in the results.
Here's a screen grab of running that command. (Note the zillions of Google Chrome Helper instances. Thanks Google!)
HTH!
tell application "Finder"
set applicationsnames to get the name of every process whose visible is true
end tell
set appName to "Safari"
if applicationsnames does not contain appName then
say (appName & " is not running")
--add here what you want to happen
end if
return applicationsnames
This is returning {"Finder", "JavaAppLauncher", "firefox", "Microsoft Word", "iTunes", "AppleScript Editor"} for me
Hope this helps
All the previously made answers suffer from the same issue, though:
They look for the app by its name. However, the user may rename the app, and then the script will believe the app does not run, when in fact it does.
To properly check for a running app, it should be found by its bundle ID, which the user cannot change.
The bundle ID can be inquired with this command, for instance, when the app is already running:
tell application "System Events"
get bundle identifier of application process "Safari"
end tell
Or like this for any installed app:
get id of application "Safari"
To check whether an app with a particular bundle ID is running, use this code:
tell application "System Events"
set ids to bundle identifier of every application process
if ids contains "com.apple.safari" then
return "Running"
else
return "Not running"
end if
end tell
Furthermore, here's an example to check if an app is running, then quit it, then relaunch it, ensuring that the very same app is relaunched that was running before, and not some other copy that may also exist:
set bundleID to "com.apple.safari"
set apps to runningApps(bundleID)
set appCount to length of apps
if appCount is not 0 then
quit application id bundleID
repeat while length of runningApps(bundleID) = appCount
-- wait for the app to quit
end repeat
open first item of apps
end if
on runningApps(bundleID)
-- The try block is to catch the rare case of having more than one
-- copy of an app running at the same time. Unfortunately, in that
-- case this code will not run as expected, because we don't get the
-- correct list of multiple items back then. But at least the script
-- will not crash from it but handle it gracefully.
tell application "System Events"
try
return application file of (every application process whose bundle identifier = bundleID)
end try
end tell
return {}
end runningApps
I had the same problem as described here trying to set up an AppleScript (triggered by a BetterTouchTool gesture) that plays/pauses VLC or iTunes, but only iTunes if VLC is not running (due to my workflow) and, naturally, only VLC while it's running. (I use the automatic pause/play trigger for iTunes in VLC's settings, for launch and quit of the app.)
VLC was always launched on the first use of the BetterTouchTool-trigger after every relaunch of BTT as the dictionary-cache is deleted at that point and the AppleScript handler has to launch every scripted application if a tell is aimed at it in order to call its dictionary.
I didn't find anything that avoided this anywhere; there were some attempts, but none worked for me as the dictionary-call by the script handler is nothing we can influence. I came up with this dirty workaround:
Create a separate AppleScript file only containing the line that includes the tell for VLC
Save it at some place where it won't annoy you
Replace the line containing the tell in the original AppleScript with a line that runs that script
This will lead to the first compilation of the script not calling the application (VLC, in my case) directly, only the script, which means that the application will not need to launch.
VLC will need to launch once that separate file is called, but, well, if you call that file in order to tell VLC something, you will have VLC already opened (or will want it open) anyway.
The AppleScript I call through my BetterTouchTool-trigger (a specific tap on the trackpad, in my case) looks like this:
if application "iTunes" is running and not application "VLC" is running then
tell application "iTunes" to playpause
end if
if application "VLC" is running then
run script "/Users/jannis/bin/PlayVLC.scpt"
end if
The separate AppleScript file ("PLayVLC.scpt, saved in a folder called "bin" in my user folder which I created manually ages ago for such purposes) is just this:
tell application "VLC" to play
If you open that script manually, it will of course also launch VLC. But that hopefully won't be necessary often, or ever.
I actually have no idea if this creates any deeper problems I don't know of as I'm not a pro coder; if so, please notify me. I hope this helps anyone!

Resources