Global application quick picture

Hello Xojo community,

I would like to write a global application, that depending on what program I am in it will change its pictures.

Example, If I’m in Photoshop I want the app to display FIGURE 1 Picture and if I switch to Final Cut Pro I want the image to switch to FIGURE 2. Is this possible?

Figure 1

Figure 2

Thanks

What OS? On mac I’ve used NSWorkspace/NSNotificationCenter for this kinda thing.

Hello Will Shank, how do I implement NSWorkspace to return the application name I am working in?

This single method will return the name of the front app. If the user renames an app this method still returns the original name. For example, I’ve renamed “Xojo” to “Xojo 14r1” but this will still return “Xojo”. I don’t know if the name will change in different languages though.

If the name changes by language a better way to identify an app may be the bundleIdentifier. That’s the thing that looks like “com.xojo.xojo” or “com.apple.finder”. Switch the commented declare and return lines to get the bundleID.

[code]Private Function frontMostApp() As String

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 frontmostApp lib CocoaLib selector “frontmostApplication” (inst_id As Ptr) As Ptr
declare function getLocName lib CocoaLib selector “localizedName” (inst_id As Ptr) As CFStringRef
//declare function bundleID lib CocoaLib selector “bundleIdentifier” (inst_id As Ptr) As CFStringRef

dim workspaceCls, workspace, frontRunningApp As Ptr
workspaceCls = NSClassFromString(“NSWorkspace”)
workspace = sharedWorkspace(workspaceCls)
frontRunningApp = frontmostApp(workspace)
return getLocName(frontRunningApp)
//return bundleID(frontRunningApp)

End Function[/code]

With just this method you can setup a Timer getting the name every second or so and watch for changes. A lighter weight (and more involved) way is to install a notification center observer for ‘did activate’ events. This module does that for a single event type and callback. First you call install with the method you want to be triggered when a new app is brought front. You should call unregister when done with.

How it works. install() first dynamically creates an NSObject subclass and adds a method that’s implemented by the Xojo method HandleActivateNotify. Then an instance of this class is made and added to notification center as an observer of the did activate event. When the OS sends those events handleActivateNotify gets triggered which simply calls the delegate. removeObserver() simply tells notification center as much and then nils its values.

[code]Module ActivateNotifier

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

Private Delegate delNotifyHandler(notifyEvent As Ptr)

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("HandleActivateNotify:")
  
  //dynamically create class with Xojo implementing a method
  dim classRef As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), "MyActivateNotifierxyz", 0)
  objc_registerClassPair(classRef)
  if not class_addMethod(classRef, callbackSelector, AddressOf handleActivateNotify, "v@:@") then break
  
  //instantiate one
  refInstanceid = init(alloc(classRef))
  
  //link this instance to be notified of activated apps
  refCenter = notificationCenter(sharedWorkspace(NSClassFromString("NSWorkspace")))
  
  addObserver(refCenter, refInstanceid, callbackSelector, _
     "NSWorkspaceDidActivateApplicationNotification", nil)

End Sub

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

Protected Sub unregister()

  if refCenter = nil then return 
  
  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)
  refInstanceid = nil
  refCenter = nil

End Sub

End Module[/code]

Here’s a demo. Add this code to a window along with the frontMostApp method and a TextArea. And add the ActivateNotifier Module. Run and switch apps.

[code]Sub Open()
ActivateNotifier.install(AddressOf anAppActivated)
End Sub

Private Sub anAppActivated(notifyEvent As Ptr)
#pragma unused notifyEvent
TextArea1.AppendText "just activated: " + frontMostApp + EndOfLine
End Sub

Sub Close()
ActivateNotifier.unregister
End Sub[/code]

notes: I think this is 10.7+ only. Very little error checking. Hard coded constants. When anAppActivated is triggered it gets an event object ptr containing the app in question. This code is ignoring that object and just getting the name through frontMostApp().