Send both computer shut down command and Quit my application

Hi Folks,
I made a desktop application (Win and Mac) which at times may get asked by the user to do media processing that can even lasts for three hours or more, I gave the user an option to shut down computer when done.
I’m well familiar with Windows CMD but less with Mac Terminal and I want to both send shut down command and Quit my application. On Windows it’s easy for me because I know how to send a delayed Shutdown request with no user interaction or approval what after it’s submitted the application still have 15 seconds to quit properly.
I do not want to save a script file just to achieve that on macOS and I believe “sudo shutdown -h +2” is not an option because it requires user feedback (password)

[code]#If TargetMacOS Then
SDSC = “osascript -e 'tell application ““System Events””” + " to shut down’"
#else // if it’s not Mac then it must be Windows
SDSC = “shutdown -s -t 15 -c ““Scheduled Shutdown starts in 15 seconds By By”””
#Endif

Dim sd As New Shell
sd.Execute(SDSC)
Quit[/code]
Of course my code works, only on Mac when I boot the system back on, my application is still open because the execution never got to the Quit part of the code.
I did try:
osascript -e ‘tell app “System Events” to shut down in 15’
But it looks like “in 15” is getting ignored because I get the same result as I get without it.
Any idea would be a blessing:)

@Sagi Gal — I personally would rather put the Mac to sleep. It seems friendlier to me (debatable) but more importantly easier and foolproof, which shutting down is not (any application can cancel it, macOS may require an administrator password…)

osascript -e ‘tell application"“System Events”" to sleep’

Hi @StphaneThank you very much for the feedback!
Professional media content creators, the only clients for this app, work almost exclusively with robust workstations and never ever put the machine to sleep, most media creators leave the machine on 24/7 some shut down at nights and some only shut down during weekends.
In fact as part of ‘Media work optimisation’ many of them even go step further and remove hibernation completely from their systems to make the machine more efficient and light.
In light of this I don’t expect this feature to be much in use, if ever, but still I give the option even if for rare cases.
It works and I can leave it as is, but it bothers me I don’t know how to delay the shut down event under OS X to make it ‘slicker’

@Sagi Gal — Oh, I see! What I don’t understand, however, is why you want a delay. Is it just to allow your app to properly quit?

You got it @StphaneMons
If the Shell command is executed immediately the app ever get to quit properly , and if I quit the app first I can’t send the shutdown command. of course timer will not work either so the only proper solution is to do as I do under Windows: ‘shutdown -s -t 15’ which gives me 15 seconds to operate, I was hoping someone have an idea how to achieve such command-line under Mac as well.

@Sagi Gal — Well I don’t think it should be an issue on macOS, especially if you execute the command in the App.Close event (which is executed only if you haven’t cancelled quitting). This is your last chance of executing anything and your app effectively quits as soon as it encounters a Return.

Shutting down is not a synchronous process because it will let up to 30 seconds for each process to quit before it tries more radical methods. Your app should have plenty of time to actually quit before the system shuts down. Or are you experiencing something different?

If you look at the Kaju project, you’ll see the technique I use to run a shell script after the app has quit. In short, I write the shell script, then call it through a Shell using nohup. In your case, you’d do that in App.Close and the script would pause for a couple of seconds, then call shut down.

https://github.com/ktekinay/Kaju

But I think this is all too complicated. Your entire point is that you don’t want your app reopening on restart, yes? I think there is a key you can write to or include in a plist somewhere that will tell the OS to skip your app, in which case you can just call shut down directly.

Hmmm… I think I get it now that you mention App.close
My code was sitting on a timer because it’s part of a larger event I created that clean things up and needs time, but you’re definitely right, I can (and should) move this part of the code to App.close
Stupid of me not to do that as I already have there some other closing arrangements.
I’ll make the switch and report back with the results once tested on all OS environments.
Thanks @StphaneMons !

@StphaneMons unfortunately moving the code to the app close event handler did not help, the immediate execution still override the app close event, I guess it makes sense because the app waits for the shell result property but the system is already shutting down (without waiting for applications Quit confirmation).

@KemTekinay Thanks for chiming in, you are right, I do want to keep it simple without external scripts or plist alteration, plus, my Mac skills are limited as is so I’m looking for a more straight up solution.

So odd there is no match to Windows: shutdown -s -t 15 on Mac without using something like: sudo shutdown -h +2 which of course require admin password authorization.

You should avoid that anyway as it’s a sudden stop rather than an orderly shutdown.

Okay, so you say Mac can not do what Windows can in that regard and that method should be avoided, got it Thanks.

I don’t actually know what that command does on Windows. If it’s a sudden stop too, I’d recommend against it as well.

Windows shutdown -s -t 15 is a legit scheduled shutdown command which activates Windows Shutdown/Reboot/Log Off mechanism and it has all the necessary Syntax switches.
https://www.lifewire.com/shutdown-command-2618100

The reason this works on Windows is because of the difference in Shell on the platforms. On the Mac, the executed commands are tied to Shell that started them. If that Shell is terminated, the underlying commands are too. On Windows, though, they are detached and will survive the destruction of the Shell and even your app quitting.

The way to do this on the Mac is to use nohup, but I have another solution for you. Include an AppleScript applet with your app that is launched during App.Close. That applet will wait a couple of seconds, then tell System Events to shut down.

The only thing I don’t know is if the applet will be relaunched on restarted causing an annoying loop. Frankly, I’d include the shell script and call it using nohup.

@Kem Tekinay Hahaha, Thanks for the offer but I think I’ll pass for now as I mentioned my Mac skills are still a bit limited.
Just now getting to know this OS, My Application started as Windows only and lots of Mac users saw it and implore me to make it available for Mac as well but I’m far from being able to include a shell script and call it using nohup.
I’m just happy right now it all finally work in Mac as it works in Windows, took me a lot of time adjusting the code to get to this point, not as easy as I thought it would be using cross-platform development tool :slight_smile:
If shutdown become that complicated in Mac my Mac users can easily live without that single feature.

Hi Kem,

I would like to take that offer the applet.

Thanks again.

Lennox

Er, I wasn’t really offering to write it, but here’s a shot:

delay 5
tell app "System Events" to shut down

Save that as an app using Script Editor, copy it to the app’s Resources (or similar) folder using a compile script, then call it in App.Close with something like this:

dim f as FolderItem = SpecialFolder.Resources.Child( "My Shutdown.app" )
f.Launch
//
// Give it two seconds
//
dim targetTicks as integer = Ticks + 120
while Ticks < targetTicks
  App.YieldToNextThread
wend

If you want to go the script route, save this script as something like “My Shutdown.applescript” to the Resources folder (mind the permissions):

#!/usr/bin/osascript

delay 5
tell app "System Events" to shut down

Call it this way:

dim f as FolderItem = SpecialFolder.Resources _
    .Child( "My Shutdown.applescript" )
dim cmd as string = "/usr/bin/nohup " + f.ShellPath

dim sh as new Shell
sh.Mode = 1
sh.Execute cmd

// Same delay code as above

sh.Poll

I haven’t tested this, but conceptually it should work.

Brilliant @Kem Tekinay !
I’ve just finished making the script and I’m struggling with the execution method and I see your post right on time :slight_smile:

Thanks Kem,

Shuts dow the Mac, but on reboot all open windows and documents are relaunched.

Thanks again.

Lennox

That’s the default behavior of the Mac OS. Are you saying that your app is among those that are relaunched?