Detect FolderItem Launch Complete

f.launch <somefile>

Which as we all know if done properly will launch the default application for “” and load it into that app

The question is… Is there a way for the XOJO app that is initaiting the launch to know when the external app has completed loading and becomes active?

For my particular situation, it takes 5 to 10 seconds (expected), but I’d like my app to say “Hang on while I set up your request” (or words to that effect), and have that msg vanish when the external app is ready.

Gravy would be if the launching app (XOJO) could also detect if the user quit the external app (but that would be a “nice to have”)

This is for OSX ONLY

Is it an arbitrary app or one known to you? If known, is it AppleScript aware?

It is an app “known to me”… (XCODE to be specific)… so I’m sure it is AS aware

It is indeed so some AppleScript like this should do it:

on run {docPath}
  if not running of app "Xcode" then
    return "false"
  end if
  tell app "Xcode"
    set fList to file of every file document
  end tell
  repeat with f in fList
    if (contents of f) is docPath then
      return "true"
    end if
  end repeat
  return "false"
end run

I haven’t tested but something like that. You’d call it from your app much the same as boolean test with the HFS path of the file you’re testing for.

I know it can be done with NSNotifications but I couldn’t tell you how :confused:

Here’s a module I made to detect when Xojo quits (via notification center) (sorry 'bout the wrapping)

[code]Module QuitNotifier

Private Property notifyHandler As delNotifyHandler
Private Property refCenter As Ptr
Private Property refInstanceid As Ptr

Private Delegate Sub delNotifyHandler(notifyEvent As Ptr)

Private Sub HandleQuitNotify(id as Ptr, sel as Ptr, notification as Ptr)
#pragma unused id
#pragma unused sel
notifyHandler.Invoke(notification)
End Sub

Protected Sub install(handler As delNotifyHandler)
const CocoaLib = “Cocoa.framework”
declare function NSClassFromString lib CocoaLib (aClassName as CFStringRef) as Ptr
declare function NSSelectorFromString lib CocoaLib (aSelectorName as CFStringRef) as Ptr
declare function objc_allocateClassPair lib CocoaLib (superclass as Ptr, name as CString, extraBytes as Integer) as Ptr
declare sub objc_registerClassPair lib CocoaLib (cls as Ptr)
declare function class_addMethod lib CocoaLib (cls as Ptr, name as Ptr, imp as Ptr, types as CString) as Boolean
declare function alloc lib CocoaLib selector “alloc” (classRef as Ptr) as Ptr
declare function init lib CocoaLIb selector “init” (id as Ptr) as Ptr
declare function sharedWorkspace lib CocoaLib selector “sharedWorkspace” (class_id as Ptr) as Ptr
declare function notificationCenter lib CocoaLib selector “notificationCenter” (inst_id as Ptr) as Ptr
declare sub addObserver lib CocoaLib selector “addObserver:selector:name:object:” (obj_id as Ptr, notificationObserver as Ptr, notificationSelector as Ptr, notificationName as CFStringRef, notificationSender as Ptr)

  notifyHandler = handler //store
  
  dim callbackSelector As Ptr = NSSelectorFromString("HandleQuitNotify:")
  
  //dynamically create class with Xojo implementing a method
  dim classRef As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), "MyQuitNotifierBleepBlorp", 0)
  objc_registerClassPair(classRef)
  if not class_addMethod(classRef, callbackSelector, AddressOf HandleQuitNotify, "v@:@") then break
  
  //instantiate one
  refInstanceid = init(alloc(classRef))
  
  //link this instance to be notified of terminating apps
  refCenter = notificationCenter(sharedWorkspace(NSClassFromString("NSWorkspace")))
  
  addObserver(refCenter, refInstanceid, callbackSelector, "NSWorkspaceDidTerminateApplicationNotification", nil)

End Sub

Protected Sub unregister()
if refCenter = nil then return //may be called multiple times (but install should only be called once)

  const CocoaLib = "Cocoa.framework"
  declare sub removeObserver lib CocoaLib selector "removeObserver:" (obj_id as Ptr, notificationObserver as Ptr)
  declare sub release lib CocoaLib selector "release" (id as Ptr)
  
  removeObserver(refCenter, refInstanceid)
  
  release(refInstanceid)
  
  refCenter = nil
  refInstanceid = nil 

End Sub

End Module[/code]

To start it call…

QuitNotifier.install(AddressOf methodToHandleQuitNotifications)

That method then gets triggered with a Ptr to an NSNotification object when any app quits. You can unpack the Ptr to discover the apps name like this

[code]const CocoaLib = “Cocoa.framework”
declare function userInfo lib CocoaLib selector “userInfo” (obj_id as Ptr) as Ptr
declare function valueForKey lib CocoaLib selector “valueForKey:” (obj_id as Ptr, key as CFStringRef) as Ptr
declare function getLocName lib CocoaLib selector “localizedName” (inst_id As Ptr) As CFStringRef

dim uidict As Ptr = userInfo(notifyEvent)
dim theApp As Ptr = valueForKey(uidict, “NSWorkspaceApplicationKey”)
dim quittingAppName As String = getLocName(theApp)

if quittingAppName = “Xojo” then Quit[/code]

but in my app I ignore the Ptr for some reason and call this method to tell if Xojo is running. I think because I have multiple Xojos with different names and this gives me that name, or maybe not, I don’t remember why I do it this way :slight_smile: Anyways this can be used to tell what apps are running without a notification being triggered.

[code]Private Function xojoIsRunning() As boolean

const CocoaLib = “Cocoa.framework”
declare function NSClassFromString lib CocoaLib (aClassName as CFStringRef) as Ptr
declare function sharedWorkspace lib CocoaLib selector “sharedWorkspace” (class_id as Ptr) as Ptr
declare function runningApps lib CocoaLib selector “runningApplications” (inst_id As Ptr) As Ptr
declare function getLocName lib CocoaLib selector “localizedName” (inst_id As Ptr) As CFStringRef
declare function count lib CocoaLib selector “count” (inst_id as Ptr) as UInt32
declare function objectAtIndex lib CocoaLib selector “objectAtIndex:” (theArray as Ptr, idx as Integer) as Ptr

dim workspaceCls, workspace, appsArray, curApp As Ptr, i, last As integer

workspaceCls = NSClassFromString(“NSWorkspace”)
workspace = sharedWorkspace(workspaceCls)
appsArray = runningApps(workspace)

last = count(appsArray) - 1

for i = 0 to last
curApp = objectAtIndex(appsArray, i)
if getLocName(curApp) = “Xojo” then return true
next

return false

End Function[/code]

To tell when an app has launched you can modify the module to also handle NSWorkspaceDidActivateApplicationNotification, or maybe NSWorkspaceDidLaunchApplicationNotification. Not sure how that compares to Kems AS, at least it won’t tell you when the document has loaded.

declare references NSWorkspace NSNotificationCenter NSNotification

In that case, it’s probably better to implement it completely with AppleScript.
Ideally, you launch the script and wait for it returning.
The script must contain code to launch the app and looping while checking if the process is running, then returning.

That way your app will wait until the script is done (and Xcode is running).

Or just use the command line compilers etc from Xcode and do it in a shell ?

Have not been able to figure out what the shell command would be

load an XCODE project
Compile it
if not errors, then launch iOS Simulator with a specified device

https://developer.apple.com/library/ios/technotes/tn2339/_index.html