AppleScript Application Still Open On Save and Quit

I came across an interesting discovery when I was trying to find a solution for an issue that I see others on the MacScripter forum also have.

I have an AppleScript saved as an application that shuts down the computer after a 15 second delay. The script works but upon restart the computer shuts down again.

When I was trying various ideas put forward by people in the forum to solve this I made a few different AppleScripts and saved them as an application. I decided to trash a couple of earlier scripts I made and even though I had quit Script Editor the system wouldn’t let me trash them because it said they were open.

I had to force quit them from the Apple menu drop down. I saw all the AppleScript applications that I had created in the list of open apps.

Would this partially explain why the scripts firing on computer restart is such a chronic issue?

Would this be a bug in Mojave?

My OS is 10.14.5.

Would be useful to check if you saved them, as stay open applications.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 17 septembre 2019 19:02:30

No I didn’t. That’s an option you have to checkmark on purpose and I didn’t.

Model: MacBook Pro (Retina, 15-inch, Early 2013)
AppleScript: AppleScript 2.7
Operating System: macOS 10.14

I encountered the same shut-down issue as the OP when using the Finder but System Events seems to work OK.


display dialog "The computer will shut down in 15 seconds." buttons {"Cancel", "Shut Down Now"} default button 1 giving up after 15

tell application "System Events" to shut down with state saving preference

For this script to function correctly, the option in the macOS shutdown dialog–which has the label “reopen windows when logging back in”–cannot be enabled (thanks KniazidisR).

One of the explanations for this phenomenon may be this: the normal operation Shut Down (manually) has the checkbox “Reopen windows when logging back”. The user can set this check box, if desired. It seems that with a programmable restart (without parameters), this flag sets System Events automatically. Just in case. What happens in this case? When restarting, the script opens again (with it saved state) and turns off the computer again.

When the appllication which shut downs the Mac sets state saving preference to true (“not reopen windows when logging back”) then this phenomenon is avoided, as I think.

I rewrote the shut-down script utilizing an Applescript progress dialog. A few comments:

  • The script has to be saved and run as an application to display the dialog.
  • The dialog title is the file name.
  • The Stop dialog button cannot be changed and an additional button cannot be added.

set shutdownDelay to 15

set progress total steps to shutdownDelay

repeat with i from shutdownDelay to 1 by -1
	set progress description to "The computer will shut down in " & i & " seconds."
	set progress additional description to " "
	set progress completed steps to i
	delay 1
end repeat

tell application "System Events" to shut down with state saving preference

I found this old post of yours while looking for a solution to “my” shut down which produced an endless loop of startup/shut downs. Works perfectly, but would it be possible to have a countdown clock rather than the progress bar that moves from right to left? I haven’t had any luck creating a countdown clock (just numbers, 15, 14, 13, etc.) with AppleScript.

You need AsObjC code. Something like this:
 

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property wController : missing value -- outlet equivalent in AsObjC
property notificationTitle : "Restarting...                                                  "
property aWidth : 360
property aHeight : 30


my performSelectorOnMainThread:"displayNotification:" withObject:({aWidth, aHeight, notificationTitle}) waitUntilDone:true
tell application "System Events" to shut down with state saving preference


------------------------------------ HANDLERS ------------------------------------------------
on displayNotification:paramObj
	copy paramObj to {aWidth, aHeight, aTitle}
	set aColor to current application's NSColor's colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.9
	set aView to current application's NSTextView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, aWidth, aHeight))
	aView's setRichText:true
	aView's useAllLigatures:true
	aView's setTextColor:(current application's NSColor's cyanColor()) --
	aView's setBackgroundColor:aColor
	aView's setEditable:false
	aView's setFont:(current application's NSFont's fontWithName:"Menlo" |size|:20)
	repeat with i from 15 to 1 by -1
		set my wController to current application's NSWindowController's alloc()
		(aView's setString:("               " & i & " sec"))
		set aWin to makeWinWithView(aView, aWidth, aHeight, aTitle, 0.9)
		my (wController's initWithWindow:aWin)
		my (wController's showWindow:me)
		delay 1
		my wController's |close|()
	end repeat
end displayNotification:


on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
	set aScreen to current application's NSScreen's mainScreen()
	set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
	set aBacking to current application's NSTitledWindowMask
	set aDefer to current application's NSBackingStoreBuffered
	set aWin to current application's NSWindow's alloc()
	(aWin's initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
	aWin's setTitle:notificationTitle
	aWin's setDelegate:me
	aWin's setDisplaysWhenScreenProfileChanges:true
	aWin's setHasShadow:true
	aWin's setIgnoresMouseEvents:false
	aWin's setLevel:(current application's NSNormalWindowLevel)
	aWin's setOpaque:false
	aWin's setAlphaValue:alphaV --append
	aWin's setReleasedWhenClosed:true
	aWin's |center|()
	aWin's setContentView:aView
	return aWin
end makeWinWithView

 

Thank you, works beautifully. I did change the System Event from shut down to restart on your original, then made a copy so as to have both Shut Down and a Restart.

Tried a few things (still learning) but was unable to center the countdown (see image). If you can just tell me where this is controlled I’ll have something to play around with over morning coffee.

Got it centered! Thanks again.

What did you do to center it?

Can you share your full script here?

If you take a look at the two images I’ve uploaded, take a look at the “aView’s setString:(” location. If you put the cursor at the far right " mark. and step backwards. there are 15 spaces in the original, which when changed to 12 spaces, centers the numbers. I’ve included the modified script.

Original Script

Centered Script

use scripting additions
use framework "Foundation"
use framework "AppKit"
property wController : missing value -- outlet equivalent in AsObjC
property notificationTitle : "Restarting...                                                  "
property aWidth : 360
property aHeight : 30


my performSelectorOnMainThread:"displayNotification:" withObject:({aWidth, aHeight, notificationTitle}) waitUntilDone:true
tell application "System Events" to restart with state saving preference


------------------------------------ HANDLERS ------------------------------------------------
on displayNotification:paramObj
	copy paramObj to {aWidth, aHeight, aTitle}
	set aColor to current application's NSColor's colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.9
	set aView to current application's NSTextView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, aWidth, aHeight))
	aView's setRichText:true
	aView's useAllLigatures:true
	aView's setTextColor:(current application's NSColor's cyanColor()) --
	aView's setBackgroundColor:aColor
	aView's setEditable:false
	aView's setFont:(current application's NSFont's fontWithName:"Menlo" |size|:20)
	repeat with i from 15 to 1 by -1
		set my wController to current application's NSWindowController's alloc()
		(aView's setString:("            " & i & " sec"))
		set aWin to makeWinWithView(aView, aWidth, aHeight, aTitle, 0.9)
		my (wController's initWithWindow:aWin)
		my (wController's showWindow:me)
		delay 1
		my wController's |close|()
	end repeat
end displayNotification:


on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
	set aScreen to current application's NSScreen's mainScreen()
	set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
	set aBacking to current application's NSTitledWindowMask
	set aDefer to current application's NSBackingStoreBuffered
	set aWin to current application's NSWindow's alloc()
	(aWin's initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
	aWin's setTitle:notificationTitle
	aWin's setDelegate:me
	aWin's setDisplaysWhenScreenProfileChanges:true
	aWin's setHasShadow:true
	aWin's setIgnoresMouseEvents:false
	aWin's setLevel:(current application's NSNormalWindowLevel)
	aWin's setOpaque:false
	aWin's setAlphaValue:alphaV --append
	aWin's setReleasedWhenClosed:true
	aWin's |center|()
	aWin's setContentView:aView
	return aWin
end makeWinWithView```

Is it possible to add either a “Cancel” or “Stop” button to this script?