I have an AppleScriptObjC application written entirely “by hand” - in other words, not using XCode. I have specified the application delegate with
NSApplication’s sharedApplication’s setDelegate:me
This is placed at near the beginning of the script. In the resulting application, the menu bar’s Application Menu contains an item for Quit, but nothing happens when used. Other menu items work, such as Hide.
Many application delegate handlers are called as expected, such as applicationDidBecomeActive:, among others. However, applicationShouldTerminate: is never called and, as mentioned, the application does not quit.
The structure of the code is:
use framework "Foundation"
use framework "AppKit"
use scripting additions
NSApplication's sharedApplication's setDelegate:me
-- Application's code is here. FWIW there is no explicit run handler, although using one does not change the result.
on applicationDidBecomeActive:sender
-- Code in here is executed.
end applicationDidBecomeActive:
on applicationShouldTerminate:sender
-- Code in here is not executed, as evidenced by the fact that a NSLog() statement does not generate output.
end applicationShouldTerminate:
Perhaps I have not properly specified the application delegate. However, as I said, most delegate handlers execute normally.
If those other standard delegate protocol functions are being called then “me” is the delegate.
Are you sure the protocol handler
Is not being called? You may want to inject some code in there to test it like Beeping or Posting a notification.
And make sure your providing a reply to that call.
The applicationShouldTerminate:
Gets called to allow you to do any final clean up or other operations before the real quit happens. And you need to return a reply value for it of enumType NSApplicationTerminateReply
statement in the main body of the script, the handler applicationDidBecomeActive: is not called. I put an NSLog() statement inside the handler, but it did not generate any output.
Script Editor, Cocoa app (made with Xcode) and Cocoa-AppleScript applet.
I guess you are talking about Script Editor and exported applets.
This AppleScript runtime have less Cocoa function and Cocoa app (made with Xcode) has all Cocoa functions such as application related events.
The middle of them is Cocoa-AppleScript applet.
You can use it via Script Editor’s File>Create new from template> Cocoa-AppleScript Applet
It has application related event capability as you like.
--
-- CocoaAppletAppDelegate.applescript
-- Cocoa-AppleScript Applet
--
-- Copyright 2011 {Your Company}. All rights reserved.
--
-- This application delegate emulates the OSA script applet by loading "main.scpt" from the
-- "Scripts" folder in the application resources and invoking the traditional run/open/reopen/quit
-- handlers in response to Cocoa application delegate methods being called.
--
-- This is provided in source form so that you may customize or replace it if your needs go
-- beyond the basic applet handlers.
--
-- Some of these methods must guard against re-entrancy, because invoking the main.scpt
-- handler may end up invoking the event handler inherited from the current application,
-- which calls the application delegate's method again.
script CocoaAppletAppDelegate
property parent : class "NSObject"
property mainScript : missing value -- the applet's main.scpt
property didOpenFiles : false -- true = the application opened documents during startup
property isOpeningFiles : false -- re-entrancy guard: true = in the process of opening files
property isReopening : false -- re-entrancy guard: true = in the process of re-opening
property isQuitting : false -- re-entrancy guard: true = in the process of quitting
on applicationWillFinishLaunching:aNotification
-- Insert code here to initialize your application before any files are opened
-- Emulate an OSA Applet: Load the main script from the Scripts resource folder.
try
set my mainScript to load script (path to resource "main.scpt" in directory "Scripts")
on error errMsg number errNum
-- Perhaps this should silently fail if it can't load the script; that way, a Cocoa applet
-- can just have Cocoa classes and no main.scpt.
display alert "Could not load main.scpt" message errMsg & " (" & errNum & ")" as critical
end try
end applicationWillFinishLaunching:
on applicationDidFinishLaunching:aNotification
-- Insert code here to do startup actions after your application has initialized
if mainScript is missing value then return
-- Emulate an OSA Applet: Invoke the "run" handler.
-- If we have already opened files during startup, don't invoke the run handler.
if didOpenFiles then return
try
tell mainScript to run
on error errMsg number errNum
if errNum is not -128 then
display alert "An error occurred while running" message errMsg & " (" & errNum & ")" as critical
end if
end try
-- TODO: Read the applet's "stay open" flag and quit if it's false or unspecified.
-- For now, all Cocoa Applets stay open and require the run handler to explicitly quit,
-- which is arguably more correct for a Cocoa application, anyway.
(* if not shouldStayOpen then
quit
end if *)
end applicationDidFinishLaunching:
on applicationShouldHandleReopen:sender hasVisibleWindows:flag
-- Insert code here to perform actions in response to a "reopen" event
if mainScript is missing value then return true
-- Guard against re-entrancy.
if not isReopening then
set isReopening to true
-- Emulate an OSA Applet: Invoke the "reopen" handler. If there isn't one, let the application object
-- handle reopen (this is different from an OSA applet, which would do nothing if there is no handler;
-- this way, the application will perform the usual "create untitled document" behavior by default).
try
tell mainScript to reopen
set isReopening to false
return false
on error errMsg number errNum
if errNum is not -128 then
display alert "An error occurred while reopening" message errMsg & " (" & errNum & ")" as critical
end if
end try
set isReopening to false
end if
return true
end applicationShouldHandleReopen:hasVisibleWindows:
on |application|:sender openFiles:filenames
-- Insert code here to perform actions in response to an "open documents" event
-- Remember that we opened files, to avoid invoking the "run" handler later.
set didOpenFiles to true
-- Guard against re-entrancy.
if not isOpeningFiles and mainScript is not missing value then
set isOpeningFiles to true
try
-- Convert all the filenames from NSStrings to script strings
set theFilenameStrings to {}
repeat with eachFile in filenames
set theFilenameStrings to theFilenameStrings & (eachFile as text)
end repeat
tell mainScript to open theFilenameStrings
set isOpeningFiles to false
tell sender to replyToOpenOrPrint:(current application's NSApplicationDelegateReplySuccess)
on error errMsg number errNum
if errNum = -128 then
tell sender to replyToOpenOrPrint:(current application's NSApplicationDelegateReplyCancel)
else
display alert "An error occurred while opening file(s)" message errMsg & " (" & errNum & ")" as critical
tell sender to replyToOpenOrPrint:(current application's NSApplicationDelegateReplyFailure)
end if
end try
set isOpeningFiles to false
else
tell sender to replyToOpenOrPrint:(current application's NSApplicationDelegateReplyFailure)
end if
end |application|:openFiles:
on applicationShouldTerminate:sender
-- Insert code here to do any housekeeping before your application quits
-- Guard against re-entrancy.
if not isQuitting and mainScript is not missing value then
set isQuitting to true
-- Emulate an OSA Applet: Invoke the "quit" handler; if the handler returns, it has fully
-- handled the quit message and we should not quit, otherwise, it calls "continue quit",
-- which returns error -10000.
try
tell mainScript to quit
set isQuitting to false
return current application's NSTerminateCancel
on error errMsg number errNum
-- -128 means there is no quit handler
-- -10000 means the handler did "continue quit"
if errNum is not -128 and errNum is not -10000 then
display alert "An error occurred while quitting" message errMsg & " (" & errNum & ")" as critical
end if
end try
set isQuitting to false
end if
return current application's NSTerminateNow
end applicationShouldTerminate:
end script
Piyomaru - Thank you for your response. I had not been aware of the Cocoa-AppleScript Applet template in Script Editor. Your explanation was very helpful.
Unfortunately, I have not been successful. Any application I created from the template will not run. macOS displays a message stating “The application X can not be run.” I have attempted numerous times to identify the source of the problem. The code I have used in main.scpt is very simple and I do not believe it to be the problem.
I have located an older version of CocoaAppletAppDelegate. Replacing the executable in the current version with that of the older version allows the template to function normally (as far as I have noticed.) I have attached the older executable for anyone interested.
I’m guessing that the template isn’t used that much since there aren’t many topics about it, but my recent experience (Apple M1 running 14.7 Sonoma) is that although the Cocoa-AppleScript Applet template works, the issue seems to be when using the arm64e executable. Although an earlier version (that doesn’t have the arm64e executable) works, you can also just run it in Rosetta.