Odd issue with activation/responsiveness

I’ve found this odd issue with ASS apps where the app will be completely unresponsive during any of will finish launching, launched, open, or open untitled (if these were called on launch). Windows won’t even be greyed out when switching to another app. Other events called after the app has launched are fine, including activated. I’ve been having to do odd workarounds like this:


property FileNames : {}
property DidLaunch : false
on open names
	if DidLaunch
		doStuff(names)
	else
		set FileNames to names
	end if
end open
on activated
	if not DidLaunch then
		set DidLaunch to true
		if FileNames is not {} then doStuff(FileNames)
	end if
end activated

(open or open untitled are called after launched but before activated)
This seems really strange to me and the workaround is imperfect (if the app was launched in the background then activated won’t be called). Has anyone else experienced this or have an explanation/solution for it?

It is because by default applescript-studio applications doesn’t support the on open handler. This can be turned on by changing the info.plist file of your project to enabled the droplet support. Maybe this post can help you further.

Sorry, I don’t understand. If the Info.plist isn’t set up to accept file drops then you won’t be able to drop files onto the app and the open handler simply isn’t going to get called (well this isn’t really true - you can still force it by holding cmd+opt). This issue has nothing to do with that though. The problem occurs with any of the handlers that I mentioned that are called as part of the launch sequence, including open if you dropped files onto the app when it was closed.

As a real example, try running this applet. This is exactly the same as the Test Applet I posted on the AppleScript forum earlier but the processing has been moved from idle to run (run is called by Application.scpt during open untitled).

Thanks for the link I know what happened

First of all you’re using a will application finish launched instead of just launched. Any on will handler in studio is asking for permission. You never tell your app that he’s allowed to finish his launching state. Return true at the end of the handler and your application will be enabled.

Then the unresponsiveness of your application ramains because applescript-studio is by default single threaded which means the first command needs to be finished before the second command can be run. Run handlers of yoru secondary script into a separate process and your application remains responsive even if it’s busy executing code. I’ve written a large article here how you can do soem sort of threading in Applescript.

No, that’s a “should” handler :wink:

Right! But an ASS app still runs its UI on a separate thread - it is quite capable of remaining responsive while the script is performing a task. So what is the “second command” that’s waiting to run? I would have thought that at this point (launched has completed) there’s nothing else that’s waiting to happen. It isn’t activated since the problem still happens if you launch the app in the background. But if you wait until the activated handler to perform the operation then it works fine (or idle - see what happens when you shift the contents of the run handler back into the idle handler).

Sorry you’re right, I haven’t programmed studio for more than a year, but the fact is when you return a boolean it will become active (i’ve tested it myself).

Well your facts are right but your conclusion is wrong. GUI is wide and is not a single object in your or any system. Graphical and interaction are two different things and also two different layers in your system because the screen doesn’t need to know anything about responders and visa versa. The presentation of your object will be called from the system, in other words it is running from a separate thread (you were right about that). Studio gives you the feeling that you decide when an object appears in your display but it isn’t, the system decided and ask the object what he would like to show on the screen and does that for you. The NSApplication object in studio application has only a single threaded main event loop. Which means your application can handle one event at the same time. So when an event busy in your application, other events has to wait till the event before him is finished, which can result in a temporarily frozen interface of your application. It is not the graphical part who is the problem but the interaction-layer/responders who causes the problem.

What do you mean by this? Active as in activated gets called and the application becomes frontmost? I’m not observing any difference between returning true and returning anything else.

What? No, this is not quite right. The main difficulty with threading in ASS is how to trigger a new event in a non-blocking way. Just try the other version of the applet that I posted (here) where the processing is in the idle handler. The app remains completely responsive while in the idle event and happily handles the clicked event when you click the cancel button. No special threading tricks for this to work.

The issue I’m dealing with here is specifically to do with events and processing during the app’s launch sequence. Once the app has launched properly and we’re outside of the launch sequence, there’s no issue. I could use threading tricks to trigger an event during the launch sequence but I’m always hopeful there’s some explanation and a proper solution for this :slight_smile:

The idle handler is called from the system and not your own application so it isn’t part of the main event loop. The cancel button can therefore simply execute because the main event loop is in a waiting state and it’s event queue is empty.

If I move the processing into the open handler and drop a file on the app it will again stay responsive, provided the app is already running. The point is, once an app has launched then it will remain responsive through any events it receives*. But trying to do things immediately after launch, via launched, open or open untitled will lock up the app. It just seems odd to me that there’s a difference here. Ah well, I guess I do have to work around it.

*New events will interrupt a previous event and the previous event will continue once the new event finishes (it works more like a stack than a queue here). So while the events aren’t threaded I would say most of the time you don’t need true threading anyway. This behaviour is sufficient for things like progress bars with cancel buttons.

Anyway, here’s my current setup which just uses a shell script to trigger an event. It’s pretty simple and it works great but if I could achieve a similar thing with a method call I’d be happier. All my attempts at this have failed though. What do you think? Any ideas on the quit issue?

I would be happy if you found a solution other than using osascript in the background. I also agree that it is in some sort of way ‘dirty’ code but I couldn’t find any better code so I rely on this technique for years now. I also tried ignoring application responses to work with but then you can’t control the separate process and how would you cancel? It’s an interesting topic and I’m no quitter too but maybe if we could find another way around I would be very happy too. I’m sorry that it doesn’t work as expected for you…

Yeah, I’ve been using similar workarounds for years too. Only this time I decided to complain about it :slight_smile:
I never properly investigated the problem before though, so at least now I have a good definition of it: Don’t perform long tasks during the launch sequence. Wait for some other event to be called after launch, or queue an event via a background shell script.

Call method frustrates me because it seems like it should be easy to just call something like “performSelectorInBackground:” but there’s no obvious way of making a reference to a selector.

You mention “ignoring application responses” - can you give an example of you might use that (ignoring the problem of control)?

Ran into another problem with this little ASS template project: adding callback handlers from the nib.
If I attach an action, such as clicked, to “main.scpt” then it will run the handler okay but it loads a different instance of the script than the one already loaded by Application.scpt, meaning it can’t access global variables.
If I attach it instead to Application.scpt, I can’t work how to pass it on properly to main.scpt:

on clicked theObject
	tell MainScript to clicked theObject -- doesn't work
	tell MainScript to clicked (a reference to theObject) -- doesn't work
	tell MainScript to clicked with theObject -- doesn't work
	tell MainScript to clicked with parameter theObject -- doesn't compile
	tell MainScript to clicked {theObject} -- does work, but now it's inside a list
end clicked

Not to mention it would be a bit of hassle to add support in Application.scpt for every event a user might want to access.

[edit] Never mind this. I realised if you’re in a position to be connecting handlers to scripts then you might as well be making your own ASS app anyway.

Hi DJ Bazzie Wazzie,
I’m wondering if you can help me understand a responsiveness issue again.

Firstly, thanks heaps for all the info you provided previously. I didn’t really understand it much at the time but having just read over this thread again it has become a lot clearer to me. I’m still not sure why there’s a difference between open being called on launch vs being called any other time but that’s okay.

The issue I’m looking at here relates to changes in system behaviour in OS 10.7 - I’ve put up with it ever since 10.7 came out but have now decided to investigate it a bit more. My ASS app starts a background shell command then goes into a busy-wait loop to check progress and wait for the command to finish. The loop includes a delay of 0.1 seconds in order to not be too ‘busy’ and consume too much CPU. There is also a cancel button which can be clicked. Here are my observations of how things work in regards to responsiveness…

Pre-10.7:

  • No delay during loop: The application will update the progress and respond to the cancel button, but feels sluggish with something like a half second lag in redraw/response time.
  • ‘delay 0’: Same as above, nothing changes.
  • Positive delay (could be really tiny like ‘delay 1.0E-3’): The application will redraw and respond immediately whenever this gets called. This is great for small delays like 0.1 as it makes everything feel snappy (of course if the delay is much higher than that you start to feel it lagging again).

10.7:

  • No delay during loop: Same as on pre-10.7.
  • Any delay less than 0.17 (including ‘delay 0’): The application will redraw immediately whenever this gets called but becomes completely unresponsive!
  • Delay of 0.17 or higher. The application still redraws as above but can now respond in the same sluggish way as when there is no delay.
  • ‘if frontmost then activate’: The application will redraw and respond immediately whenever this gets called. This is good but only helpful when the application is frontmost. If the ‘delay 0.1’ is also present then the app window will still not deactivate properly when switching to another app and will retain the appearance of being frontmost. To avoid this I have to add a second line ‘if not frontmost then set active to false’.

So at the moment my app is working reasonably well with the setup described in that last part but two questions remain:

  • Why does having a small delay cause the app to be completely unresponsive?
  • Is there anything else besides calling ‘activate’ that could improve responsiveness (maybe something that could also work when the app is not frontmost)?

This may or may not be related, but FWIW I’ve noticed a change in the behaviour of delay in AppleScriptObjC with Lion.

When you called delay in ASObjC under 10.6, CPU usage shot to 100% for the duration. For that reason, the advice was never to use it. (One of its side-effects, though, was continuous screen updating.) But I just tried it with Lion out of curiosity. No jump in CPU use – but also no delay. Well, a delay of about a second, regardless of the argument provided.

So that suggests there might have been a change to delay. I think the excessive CPU use in 10.6 was because it continuously checked the event queue, and that may well have been changed to make it do it only once. If so, that could explain what you’re seeing.