Check via AS if an app is currently launching (not just running)?

I’m working on an AS which turns incoming emails (if they match the required syntax) into Things To Dos. In case you don’t know: Things is a very slick GTD (getting things done) Manager by Cultured Code.

The problem I’m facing is that if Things isn’t fully up & running, the creation of the newToDo in Things tends to fail, as the script will fire the newToDo cmd too early, before launch of Things has been completed.

My current work-around is this routine which checks if Things is running. If not it’ll launch it and wait 5 seconds (default value as defined through ‘LaunchDelay’ preference) for the launch to hopefully be complete:

		
set LaunchDelay to "5" -- Number of seconds to wait, allowing Things to complete launching (only if not already up & running), in order to avoid new To Do requests being fired too early and thus not being 'heard' by Things.

		if application "Things" is not running then -- Things IS NOT running? Launch it!
			tell application "Things"
				activate
			end tell
			delay LaunchDelay -- Wait for launch completion, so that newToDo doesn't fail
		end if

The app appears unfortunately immediately in the ProcessList, and to my knowledge there is no way to distinguish between a launching and an up & running app, so a “check if launched and if not wait” loop doesn’t work.

Question: Is there any method to check if an app is still in the process of launching? Perhaps through calling a Shell cmd?

Model: MacBook Pro 13"
Browser: Safari 536.26.17
Operating System: Mac OS X (10.8)

Just came across these discussions related to this topic:
#1http://macscripter.net/viewtopic.php?id=27050
#2http://macscripter.net/viewtopic.php?pid=115150
#3http://macscripter.net/viewtopic.php?id=20588
#4http://macscripter.net/viewtopic.php?id=26583

#1: doesn’t work, see my post #8 in that discussion. #3 and #4: no clue about those.

#2 however leads to this solution, which seems to work pretty well (post a reply if you see any problems):


launch application "Things"
set launchCompleted to false

repeat while (not launchCompleted)
	tell application "System Events"
		tell process "Things"
			set launchCompleted to (exists entire contents of first UI element)
		end tell
	end tell
end repeat

display dialog "The script won't continue, thus this message won't appear, unless all elements of Things's first UI element (its main window) are fully loaded and drawn. In other words: Things has completed its launch." buttons {"Cool!"}

Hi, it doesn’t work for me (on Mavericks) - the script stays in the loop forever…

First of all to understand how applications runs inside a desktop you have to understand a desktop and applications but also processes.

The whole desktop (something like Mac OS X) is an collections of servers that creates an environment of a background, menus, applications, windows etc. A process can make use of the programming interface (API) of the desktop to make itself accessible in the desktop by creating windows for example. This whole presentations of the proccess inside the Desktop are called application.

As you may expect there are two forms of launching, the process and application. First the process is launching which is done quite fast, it’s procedural so in fact it is launched the minute it starts executing the first line of code. In the world of Unix, where everything is a process and no such thing as applications exists, the application is finished launching and not in a busy state quite fast. So, we don’t have to look in the world of Unix if an application is busy in the desktop.

When the process wants to run also as an application in the Desktop we have an second stage of launching. This however is more an initializer than actually launching an process/application. The process opens an interface with the desktop and is registering itself to the desktop (somewhere at this moment the application icon starts jumping in your Dock). After that (after creating an NSApplication object) a method is called from the Desktop willFinishLaunching where you can initialize your application. In Objective-C applications this is where you normally start writing your code. This method is actually called to tell the process that the process is successful connected to the desktop and the application object is created successful too.

Now we know how these two stages of launching an application works we can start figuring out what went wrong. We know that AppleEvents are send on process level through the kernel. So your script is sending the event to the AppleEvent manager and then the event manager is sending the event to the process or set the event in a queue and wait for the previous event to be finished. By default, when an application object is created and launching is completed, it will tell the event manager to be ready to receive events. It seems that in the application it doesn’t work that way and somewhere during launching (or launching of the application is not done in the willFinishLaunching method) the application accepting events while it’s not ready.

I’ve seen similar applications with the same problem and basically the only thing you can do is sending an event to the application. Note that getting the name from of the application is not sending an event to the application like many other standard commands. So getting window names won’t work either. To send an real event you need to send an Application specific command. For instance getting the state of a specific object that always exists after it’s completely launched.

To check if the Finder is completely launched I can use something like this:

set bootVolume to text 1 thru -2 of (POSIX file "/" as string)
tell application "Finder"
	set attemps to 0
	repeat
		try
			if name of first folder = bootVolume then exit repeat
		end try
		set attemps to attemps + 1
		if attemps = 40 then # Application is not respoding for 20 seconds
			error "Application is not responding" number 2
		end if
		delay 0.5
	end repeat
	# Application is repsoning; continue
end tell

When the Finder is abruptly quit (the first line of the tell finder block is quit) you’ll see that the finder is not responding properly and the method above will wait 1 or 2 attempts before continuing it’s code. The only thing you’ll need to do is find the proper “test” command for your application.

Hello.

I just saw this during a break in the Olympics. :slight_smile: So I am not presenting anything that I have tested.

But, since the running state is something you get from AppleScript; shouldn’t that state indicate that the app is ready for receiving AppleEvents? -Just wondering.

if running of application "Things" then log "hola"

Nope, as described in my previous post

Hello.

I realized that, since AppleScript just queries the LaunchDB/LaunchServices, and gets returned whether the process is running or not.

And I think you have a very robust way of handling the situation. :slight_smile:

Congratz with your most golden medals on this Olympics (at this moment). We dominated speed skating, but only that (the Netherlands is a flat country, that’s the only thing we can do).

Hello.

Thank you. Well, we used to dominate in speed skating as well some years ago, now you are unbeatable. what I think is so fantastic, is that we have 1 Gold Medal per 500K inhabitatants.

I have been pondering, this code. What I have used to do; and it has never as far as I remember failed me, been waiting until an app is running by the “running of”. Then I dare say that 2 minutes should be sufficient for getting a reply with an app. Now, Finder, especially on Mavericks is some kind of hog, and Finder on Mavericks , together with a 5400 rpm disk is really the only thing I see can make your code necessary. On the other hand, it never hurts to play safe. :slight_smile:

My code for the Finder is indeed safe for a once-in-a-billion situation. However the TS asked for his application Things that apparently has this problem every time it launches the application. Is running is an state of the process, not how far the application is launching or quiting. It is when the application is launched by the script by the tell application block. This is because AppleScript will need it’s dictionary and wait for the application (normally) to response. But what if we have the dictionary and quit the application and re-launch it to look again the running state up:

For instance:


tell application "Finder"
	quit
	launch
	if running then name of first folder
end tell

Running will return true because the process is running. However the application is initializing/launching but not ready to receive AppleEvents. The result is that name of first folder will return a connection error (the socket for sending and receiving AppleEvents isn’t open yet). That only proves my point that running is indeed an property from the process manager and not from the application itself (as I explained in my previous post).

Now try it with my code:

tell application "Finder"
	quit
	launch
end tell

--Now wait for the finder to be ready to receive events again
set bootVolume to text 1 thru -2 of (POSIX file "/" as string)
tell application "Finder"
	set attemps to 1
	repeat
		try
			if name of first folder = bootVolume then exit repeat
		end try
		set attemps to attemps + 1
		if attemps = 40 then # Application is not respoding for 20 seconds
			error "Application is not responding" number 2
		end if
		delay 0.5
	end repeat
	# Application is repsoning; continue
end tell

attemps

Attemp will not return 1, If it’s 1 you need a slower machine ;). Depending on the performance of your machine it will be 2 or maybe 3. That means that the event listener inside the Finder isn’t open or not ready to receive AppleEvents the first time. After a delay of 0.5 seconds it will try again to get the name of first folder. It’s maybe a cumbersome solution but at least you know that the AppleEvent listener in the Application is working properly or has passed a certain point during launch by “testing” the right event.

Quiting will behave exactly the same:


tell application "Finder"
	quit
	return running
end tell

When the finder is open and run this code it will return true. The application received an event to quit, the process however is still running as normal so running property will be true. Only the second run it will be false (correctly) because meanwhile the process Finder has been killed.