Script for "switchies" and other forgetful people

Common-sense behavior in folks who came to Mac OS from Windows is to regard any app where there are no open windows as exited or quit.
With applications such as browsers and email clients, this may even make some sense for long-time Mac users. I would like to write a script that takes the name of the frontmost running application, checks it for open windows and when it finds none, puts up a dialog (either immediately or with a five- or ten-second delay) asking the user if they’d like to quit the application “some name”.

I think this is a somewhat milder approach than one that quit apps that were neither running in the foreground or whose names were not on a preconfigured “preferred apps” list in the script itself.

This may also prove practical for those on CoreDuos running apps in need of Rosetta emulation support (in other words, “PowerPC coded applications”). I don’t know if this is true from a programmer’s or any other point of view, but just from personal experience, such apps, with Rosetta supporting them, seem to be real memory-hogs on Intel Macs with off-the-rack memory configurations (such as my dad’s Mini). Getting a friendly reminder to quit an app you just closed the last window on, and subsequently (if only perceptually) freeing up some app memory and getting back some speed, makes everyone happy, imo.

Silversleeves

I wasn’t aware that anything in windows worked according to ‘common sense’. People like me who abhor windows consider many things that windows does to be outside the realm of common sense. While every platform has it’s merits (some less than others :stuck_out_tongue: ) you’d be hard-pressed to get me to agree that quitting an app because it’s last window just closed should be a default behavior. While sometimes it saves me a step to not have to quit it manually, I’m of the opinion that most apps should stay open until I tell them not to be. Sometimes, the frontmost running app is important even though it may not have any windows. I realize that’s why you’d prompt the user before quitting, but that’s kind of beside the whole concept behind how this OS works. Take for example, the Finder. The finder could go for days without ever showing a window, but never in that time would I want to quit it. In fact, of all of the 6 apps showing in my dock right now as active, only firefox is actually in use. But, in 2 minutes when I’m done writing this, I still want all 6 of them running, even though I won’t be using but 1 or 2 at a time. While you could obviously test for certain key apps before displaying your alert, it seems you’d end up creating more confusion, and using more memory running a script or app to check for windowed processes. Being a long-time mac user, I would NEVER assume that because a window closes that the whole app goes away. In fact, I rather value the ability to close an app’s window but still have it running… waiting patiently and respectfully for me to use it again should I so choose. If I had to wait for apps like photoshop to launch every time I opened an image, I think I’d have to shoot myself. And I certainly wouldn’t want some script asking me every so often if I wanted to quit it just because I don’t happen to be working on something in it at the moment.

While I see that there might be some novelty to this, as you said this is probably not of much use to people who already know what’s going on with their mac. As far as memory ‘hogging’ goes, I find it hard to believe that the performance is so significantly limited by running even a handful of apps in rosetta. Eventually, most significant apps should be made available as universal binaries, so that should take care of most of the problems. Regardless, it seems kind of beside the point of having a core duo machine that processes so significantly faster. If you’ve got problems running apps, I’d put more memory in before I’d piddle over closing apps just to save a couple mb of ram.

There are also some technical details that need to be addressed. First does the script run in the background ALL the time? This would be the only way to logically use the app. Otherwise, you’d have to run it, which would be just as easy or easier than just quitting the app manually. The other thing, is that your app will steal focus every time it needs to display a message. It can’t display a dialog in the background, although it could possiblly try to display the dialogs through the apps it’s trying to quit. Sounds dangerous, though. What if you don’t want to quit the app? Does it record that and not ask you again? How often do you check for frontmost app? What if you change apps before the next check, and the app you closed the window to is now in the background somewhere? That app will then stay open until you go back to it and wait for your check to happen. Also, many apps have “windows” when there aren’t actually any ever on screen in the course of using the app. While you could test for visible windows, sometimes there are windows in the applications memory, off screen, in the dock, or carbon apps with no windows accessible to applescript, etc… that technically count as windows but are never visible. From a programmatic point of view, you may end up running into conflicts… or just plain annoying yourself… by trying to determine whether the windows exist, and whether you want to evaluate them as valid windows or not. There are lots of details that are unclear, but enough to make managing this whole system quite a bit more complex than a couple simple lines of code. While a simple idle script that displays a message is easy to write, you’ll find pretty quickly that it’s more of a pain to deal with it asking you to quit everything than it is to just work until you notice things getting a bit slow and just quitting the apps yourself.

Everyone has some sort of mechanism for managing open apps… i.e. the dock or a similar app launcher… that should give you easy access to all of the windowed, user processes. It doesn’t take long to learn how to click on an icon and quit an app if you’re not using it any more. I do think it’s a good idea to avoid having too many apps open at once. In the course of everyday use, my machine gradually takes on more and more unreleased memory. Because of poor memory management by apps… including apple’s apps… the ram usage slowly builds on every machine. On a day of serious development, especially when I’m working on memory management of my own, I might have to restart a couple times to clear the ram and boost my processing and rendering speeds. This has less to do with how many apps are open and more to do with what kind of apps are open and what they do.

I certainly don’t want to rain on your parade, it just seems like such an unnecessary step to have to take. If you were to write it as a background app/daemon that ran outside the windowed process realm, you might actually have something remotely useful (for you). This would also give you the ability to do some more complex things with your interface. Perhaps popping up a list of all processes a little less frequently would be better, and quitting all selected at once… just to do a ‘purge’ of unused apps. Might make it easier and more predictable than trying to deal with just the frontmost app.

j

I concede your points. My reach quite defnitely exceeds my grasp.

Do you know if any utlilty for timing scripts has been brought forward into OS X? I seem to recall something in legacy Mac OS days called “ScriptTimer.” The script I vaguely referred to being talked about in another thread to quit all but a few select visible processes might make a good pairing with a timing utility – run once an hour, with tweaks to the original “quit” script that allowed for alterations in the “select apps” list by way of editing and saving a text file, perhaps, may be just as useful. I guess what I was really looking for was a way to make the other “quit” script both more user-friendly and idiot-proof.

I’ll elaborate briefly. If the list were “hardwired” so that the Finder, as one process, was never made to quit, then selecting the other “preferred” processes to be left open would be made easier. How often would the list have to read from the text file? Every time it ran, of course: one couldn’t predict how often the user might change their mind about which apps they’d like to have left running. My father, for instance, keeps Safari, TextEdit, Mail, and a network monitor program running whenever his Mac is on. On occasion he’ll add such things as PrintShop OS X to that, particularly around holiday times or in advance of someone’s birthday (cards and banners being something he vigorously indulges in creating).

So that’s the line I’d like to pursue – timing the other “My App Quitter” script via utility (or another script with an above-average idle timer/handler) and modifying it to read the “preferred never quit” processes from an editable text list.

Now does anyone have any ideas how all this could be achieved?

Silversleeves

Putting the issue of how long an app has been idle for the moment (because figuring that out would be a matter of recording what was running without any visible windows periodically and comparing times) the safest approach would be something like this (which I don’t use - I’m of Jobu’s persuasion - do it yourself periodically by observing what’s in the dock):


tell application "System Events" to set R to name of processes whose visible is true and name is not "Finder" and name is not in {anythingElseToExclude}

set K to choose from list R OK button name "Leave Running" with prompt "Select applications you'd like to leave running and quit all others)" with title "Clean up Applications" with multiple selections allowed
if K is not false then -- not cancel button
	repeat with p in R
		if contents of p is not in K then tell application p to quit with saving
	end repeat
end if

I actually like the idea of part of this. Not the close window -exit app bit, As I have never found that useful even in windows.
But the quitting more than one app easily instead of doing each, one at time.

I did notice that hidden apps did not come up in Adams script.
So I looked for a way to get all the app running but not system and helper apps…
I found this thread asking the same question
I modified one answer to suit.

I did catch one of my helper apps in my script ‘laciebackupd’, but using the shell and the Rest of Adams script works well for me.


try
	set exld to "Macintosh HD:Users:USERNAME:Desktop:Text-DeskTP:apKill.txt" as string
	set exld to read (exld as alias)
on error
	set exld to {}
end try

set a to do shell script "ps -auwwwwwwwwwwwwwx | grep [-]psn |grep psn_ | grep [/]System -v | grep [/]library -v |grep Daemon -v| grep [/]Resources -v"
-- the wwwwwwww are to wrap the result from the ps command, it only matters that there are enough w's to catch all the app name. But I made sure there was more than enough.

set c to count paragraphs in a
set bigList to {}
set counter to 0
repeat c times
	set counter to counter + 1
	set the_app to my removeText(paragraph counter of a, bigList, exld)
	
end repeat

set K to choose from list bigList OK button name "Leave Running" with prompt "Select applications you'd like to leave running and quit all others)" with title "Clean up Applications" with multiple selections allowed
if K is not false then -- not cancel button
	repeat with p in bigList
		if contents of p is not in K then tell application p to quit with saving
	end repeat
end if


on removeText(the_app, bigList, exld)
	set oldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {" -psn"}
	set app_name to text item 1 of the_app
	set AppleScript's text item delimiters to {"/"}
	set app_name to text item -1 of app_name
	set AppleScript's text item delimiters to oldDelims
	if app_name is not in exld then
		copy app_name to end of bigList
	end if
end removeText

bigList

**ALSO in the one I will use I have set the selection to be the ones that quit rather than the ones not selected.
If any one wants me to post that version your wish is my command :slight_smile:

If you’re running Tiger, then “background only” is a new property which unlike “visible” will include hidden apps. Then:


-- In System 10.4.x, TIGER, only
tell application "System Events" to set R to name of processes whose background only is false and name is not "Finder" and name is not "Jiggler" and name is not "Eudora" -- is not contained in a list does not work as a filter.

set K to choose from list R OK button name "Leave Running" with prompt "Select applications you'd like to leave running and quit all others)" with title "Clean up Applications" with multiple selections allowed
if K is not false then -- not cancel button
	repeat with p in R
		if contents of p is not in K then tell application p to quit with saving
	end repeat
end if

Hooray for Adam, :D, I wonder how long it would have taken me to spot that.

That one addition makes thing so much easier for getting apps.

Here is my version ( quit selection ) , I love this script. I Have set mine on a hot-key (control +esc )
very close to the force quit keys.


-- In System 10.4.x, TIGER, only
try
	set exld to "Macintosh HD:Users:USERNAME:Desktop:Text-DeskTP:apKill.txt" as string -- this file if exists will have a list off apps to exclude from list
	set exld to read (exld as alias)
on error
	set exld to {}
	
end try
set bigList to {}
tell application "System Events" to set R to name of processes whose background only is false and name is not "Finder"

repeat with i from 1 to number of items in R
	set app_name to item i of R
	if app_name is not in exld then
		copy app_name to end of bigList
	end if
end repeat

tell application "System Events"
	set target_app to name of processes whose background only is false and frontmost is true
	
	tell process target_app
		activate
		set K to choose from list bigList OK button name "Quit Selected Apps" with prompt "Select applications you'd like to  quit and leave all others running)" with title "Clean up Applications" with multiple selections allowed
	end tell
end tell
if K is not false then -- not cancel button
	repeat with p in bigList
		if contents of p is in K then tell application p to quit with saving
	end repeat
end if


This part mystifies me, Mark; (except the set K to …)


tell application "System Events"
   set target_app to name of processes whose background only is false and frontmost is true
   
   tell process target_app
       activate
       set K to choose from list bigList OK button name "Quit Selected Apps" with prompt "Select applications you'd like to quit and leave all others running)" with title "Clean up Applications" with multiple selections allowed
   end tell
end tell

Oh… it took me a minute to wonder what you meant.

This is because I will call this script from a hot-key app (spark in my case). I want the frontmost app to do the dialog. Otherwise it gets lost behind windows and other apps. There maybe a better way of doing that. But this works.

Actually just realised I could use tell current application, Which I did try with the old script but did not work as well for some reason. But does in this one.?? probably me needing sleep??

** Just found out why when I did it before I did not have activate included. without it some apps may be frontmost but will leave the dialog behind : example would be Safari


tell current application
	activate
	set K to choose from list bigList OK button name "Quit Selected Apps" with prompt "Select applications you'd like to  quit and leave all others running)" with title "Clean up Applications" with multiple selections allowed

This is the script I came up with. As a ScriptTimer item, it only glitched once (forgot to move preferred.txt to the folder ScriptTimer was in).

tell application "System Events" to set theProcs to name of every process whose visible is true

tell application "Finder" to set r to (container of (path to me)) as string
set HeyTheList to (r & "preferred.txt")
try
	set k to (HeyTheList) as alias
on error
	display dialog "The list of apps to keep open was not found." & return & "The script cannot continue" buttons {"Ok"} default button 1
	quit
end try
set DontTouchThese1 to (paragraphs of (read k)) as list
set DontTouchThese2 to {"Finder"} & DontTouchThese1 as list

repeat with myProc in theProcs
	if myProc is not in DontTouchThese2 then tell application myProc to quit saving no
end repeat

I have to say, if it wasn’t for the script idea of opening a series of pics in Goldberg determined by a text file, I wouldn’t have even gotten this far. Now what I’d like to do, saying as the app-quitter “guts” of this script only work in Panther, is adapt the whole mess to Tiger. I have the code for both quitter scripts from the other thread, so really it’s just a matter of testing the other one in Tiger and working the code into the script above.

Thanks to all who contributed advice, critique and direction.

Silversleeves
EDIT: Came back to peruse the previous posts more closely, and I think a careful combination of Mark’s, Adam’s and my own might do for Tiger as a counterpart to the one in this post. Again, it’s code I’d have to check out on the other Mac at a less-ungodly hour than 4:35AM.

Some preselection might be done based on processes idle times, as the original author stated.
Upon executing TOP, the TIME column says something about effective CPU time used per app:


do shell script "top -X -s2 -tl2 -u   -n20"
		"Time: 2006/12/13 12:05:46.  Threads: 277.  Procs: 74, 3 running, 71 sleeping.
LoadAvg:  0.70,  0.98,  1.37.  CPU:  33.3% user,  66.7% sys,   0.0% idle.
SharedLibs: num =  173, resident = 39.3M code, 4.12M data, 7.95M linkedit.
MemRegions: num = 14764, resident =  352M + 30.2M private,  137M shared.
PhysMem:  138M wired,  445M active,  192M inactive,  776M used,  759M free.
VirtMem: 10.4G +  123M,      39911 pageins,       1885 pageouts.

  PID USERNAME  REG RPRVT  RSHRD  RSIZE  VPRVT  VSIZE  TH PRT    TIME  %CPU COMMAND

   62 windowse  501 4.80M  35.6M  31.9M  57.2M   237M   3 324   6m55s   0.0 WindowServer
    0 root     3568 27.5M     0B   117M  46.4M  1.03G  49   2   6m16s   0.0 kernel_task
  226 ehouwink  266 6.28M  31.0M  16.0M  34.8M   245M   6 184   3m34s   0.0 Extra Suites
  301 ehouwink  616 37.7M  44.8M  47.4M  63.3M   314M  10 163   2m30s   0.0 Safari
   82 ehouwink  305 4.02M  30.9M  16.0M  33.1M   254M   4 258   1m40s   0.0 SystemUIServer
  230 ehouwink  239 2.84M  26.9M  17.2M  30.6M   238M   3  93   1m30s   0.0 System Events
   38 root       73 1020K  1.14M  1.41M  27.1M  29.4M   3 230  51.42s   0.0 configd
   56 root       18  120K   232K   228K  26.2M  26.6M   1  14  21.34s   0.0 update
   83 ehouwink  441 11.1M  44.9M  35.0M  39.3M   296M   6 163  20.32s   0.0 Finder
   95 ehouwink  173 1.82M  26.2M  15.1M  29.1M   234M   3  81   7.34s   0.0 UniversalAccess
  212 root       46 3.75M  1.63M  4.87M  32.2M  34.4M   2  59   6.36s   0.0 AppleFileServer

When divided by uptime, this is an indication of how idle the process actually is.
However, this may need another TOP query that somone may know about (I am not a Unix person…)

As an addendum to this thread, if you want to find out which, if any, of your running apps are hidden in Tiger only, this does it:

tell application "System Events" to set HiddenApps to name of processes whose visible is false and background only is false

Visible seems to mean that the application has an active GUI whether any windows are showing or not, background applications include those that are “visible” but hidden. Hiding an app seems to mean that the window_manager no longer has to deal with it, whereas if you just close all its windows, it is still actively managed.