Quit app if idle for X minutes

Marco has an app called Quitter which will hide or quit applications if you have not used them in X minutes.

This seems like something that I ought to be able to do with Keyboard Maestro instead of needing a separate app for it, but I'm not sure how to do it.

It occurs to me that someone may have already invented this wheel, and if so I'm hoping they'll read this and share their solution.

Here are the two ideas that I've come up with… in a theoretical sense (versus the "I have actually written this and have it working" sense):

The Easy-But-Annoying Way…

It seems like the easiest way to do this it to have Keyboard Maestro do some sort of Pause for X seconds when an app loses focus, and then quit the app.

Create another macro for when the app gains focus which cancels the previous macro, and it seems like you're on your way.

BUT! …the thing I wouldn't like about this method is that Keyboard Maestro's menu bar icon would be flashing the entire time that the first macro running Pause for X seconds. That would be annoying.

The Write A Timestamp To A Temp File Way…

The only other idea that I have is for 1 macro which would write a timestamp to a temp file, and then have another macro which would check the temp file to see if the elapsed time since that timestamp had exceeded the idle time.

Assuming that the second macro ran, say, once a minute, you might end up with your app running for, say, almost 11 minutes when you wanted it to quit after 10, but that doesn't seem like a huge deal.

You'd also need a third macro that would delete the temp file whenever the app took focus.

BUT… this seems hacky and terrible, like there has to be a more elegant way to do it.

So…

Anyone cracked this nut?

(Yes, I realize I could have downloaded, installed, and configured “Quitter” in the time it wrote to write this post. But it's the principle of the thing…)

1 Like

Solutions can have false positives and false negatives, or be perfect. In this case a false positive would be to occasionally not detect that someone used the app and close it despite the fact that the app was briefly used in the last 10 minutes. A false negative would be to not close the app in 10 minutes, but maybe in 15 or 20 minutes. Are any of these deficiencies acceptable? And would you consider it acceptable for a solution to require a macro for each app that you want to shut down after 10 minutes? Or is that not acceptable? Would you consider it acceptable for the solution to be running and using a heavy amount of CPU, or do you require that it use only KM's triggers? And what about apps that refuse to close, do you need those to be Forced Quit?

For me, this app seems fairly non-critical, so false negatives aren't important, and false positives aren't too bad. And a separate macro for each app seems reasonable to me. So here's how I would do it.

Step 1. I would create a macro that triggers on the launch of the app. When the app launches, say Safari, a global variable called Safari countdown would be set to 10. (ie, minutes).

Step 2. I would create a macro that triggers every one minute while Safari was active (there is a builtin trigger for that) and decrements the counter by 1 if Safari is NOT the front window (and puts it back to 10 if the window is in front.) If the counter reaches 0 it terminates the program.

The main problem with this approach is that it doesn't terminate any app that's in the front, because it assumes that apps that are in the front are active. So that's a false negative. It will also cause some false positives because the user might be busy switching between windows a lot. But I would say the odds of that happening ten times in ten minutes are extremely low.

So in short, this is a very CPU-efficient solution. It has a very low rate of false positives but there's always going to be one false negative.

Personally, I think you're going about it the wrong way. In my opinion the computer is inactive if there has been no mouse or keyboard action in a period of time. Therefore the simple solution is to just create a KM macro with a trigger that triggers if the IDLE() function is above 10 minutes (then optionally send some warning beeps to the user so he can avoid the next step if he's present) then the macro can delete any or all running apps, or could even shut down the computer.

Hmm, stop the press. I think I have an even better solution. One that will be much more accurate. Let me do some tests.

Here's a whole new approach. It works on all applications. It does have one deficiency, which I will explain later, but I think that can be addressed. For now, let me show you my approach. My approach requires three macros.

The first macro looks like this:

Examine it carefully. That macro stores the current time, in milliseconds, (Edit: change that to TIME, not MS) of any process "that's deactivated", into a dictionary. They key for the dictionary entry is the full path of the app. I think that's exactly what we need. What a great idea.

The second macro removes the item from the dictionary any time the process is activated. It will look almost the same but instead of "Deactivates" it will be "Activates" and instead of setting the dictionary value to MS it will set it to an empty string. (Correction, it needs to be TIME, not MS, since MS resets at midnight.)

The third macro is to occasionally (perhaps every minute, or less often) loop through the dictionary to find out if the last time it was deactivated was over ten minutes ago. If it was deactivated over ten minutes ago then the app, whose path is the key, is to be terminated. However the termination can't be performed using KM's action because KM's action requires that the app paths be hidden, so we will have to use an Execute Shell Script action.

However I refuse to upload a macro that contains a kill command since this is a very dangerous command that could easily kill KM itself, or do a variety of other nasty things. It will be up to you to fix the syntax. But this screenshot should give you the general idea. If you don't know the correct syntax for killing a process by name you can google it. But it's your neck on the block if you make a mistake.

Again, this set of macros, while very good, does fail to take action on any process that has never been activated (which may be exactly what you want!) And it will also fail to take action on the current process since by being activated its counter has been reset to zero. However this last issue is easily fixed if you want to fix it. I'll let you ponder how to do that.

Overall I think this is one amazing little collection of macros. However bear in mind that I didn't test it. I'm not interested in testing something that kills processes on my computer.

3 Likes

What exactly do you imagine is happening (or going to happen) from using kill that you find so terrifying ?

Just for fun one time, I kill'd every single process on my machine (that was killable without invoking sudo). It was very underwhelming.

1 Like

I don't know. That's the point. The unknown is terrifying. Especially since my code will run on other people's computers and I have no idea what killing random processes could do to others.

Ah, well that's quite a different statement to "I refuse to upload a macro that contains a kill command since this is a very dangerous command", which is very adamant that kill is dangerous (it isn't, by the way).

kill sends signals to tell a process to stop running, and unless one specifically declares which signal to send, it defaults to SIGTERM, which is a very benign message requesting the process to please go away, but it's up to the process whether or not to do so (most, of course, will), and it's still allowed to perform any cleanup routines it needs to in order to terminate gracefully.

I'd say the only signal I would avoid sending (largely because I can't think why there would ever be a reason to do so, and don't know of any situations where the system itself would ever generate this signal) is SIGKILL, which is a total, unignorable, instant cessation of a process.

All the others get generated by the system all the time, some as a direct result of things we do, and some as a result of events beyond our control. Some will cause deletion of temporary files that the process created; some won't. Whether or not this is desirable is down to what effects you want to achieve by ending the process. The default SIGTERM tends to leave temporary files alone, so if you find these accumulating and taking up space, it's worth using a different termination signal.

In the old days, there was much more of a concern regarding data loss or corruption, but the mechanisms used by modern technology makes this less likely, in that having a document open and then terminating the parent process would previously been the last you'd see of all your hard work, but now that wouldn't be the case and you'll perhaps lose the last minute or two of edits but retain everything else. Even remote data transfers that used to be an all or nothing situation have the ability to resume transfer at the point it go to before interruption.

And, finally, fairly recently in fact, macOS started providing the option to log out and shut down one's computer in a much faster and pleasingly snappy way. I'll let you guess what it's doing to each process to get them all ending so swiftly... :slightly_smiling_face:

I agree with your statement. "Less likely". Not "zero likely". Therefore still "dangerous." I stand by my decision not to upload a macro that might harm other people.

A few days ago JM responded to me in a post that one of my macros was "very dangerous" because it used an infinite loop, by design. Would you agree with him that using an infinite loop in a macro is "very dangerous"? Or was he overstating it? Personally, I think deleting processes is much more dangerous than using an infinite loop in a macro.

Some people tell me that my macros are too dangerous and some are telling me that my macros are overly cautious. Wow.