I also found out how to get the gadget id in a notification callback.
Update v1.02.0
- Fix automated PlaceHolderList
- Add SetWindowNotification
OSX_GadgetCallback.pb
Code: Select all
;-TOP
; Comment : MacOS SetGadgetCallback and SetGadgetNotification (Base by Shardik)
; Author  : mk-soft
; Version : v1.02.0
; Create  : 28.02.2021
; Update  : 06.03.2021
; Link Base of Shardik: https://www.purebasic.fr/english/viewtopic.php?f=19&t=65891&p=492568#p492568s
EnableExplicit
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  
  ImportC ""
    sel_registerName(str.p-utf8)
    class_addMethod(class, selector, imp, types.p-utf8)
    class_getInstanceMethod(class, selector)
  EndImport
  
  ; *** Required variables ***
  
  Global notificationCenter = CocoaMessage(0, 0, "NSNotificationCenter defaultCenter")
  Global appDelegate = CocoaMessage(0, CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
  Global delegateClass = CocoaMessage(0, appDelegate, "class")
  
  Structure udtGadgetCallback
    Window.i
    Gadget.i
    refCount.i
  EndStructure  
  
  Structure udtWindowNotification
    Window.i
    refCount.i
  EndStructure  
  
  Structure udtGadgetNotification
    Window.i
    Gadget.i
    refCount.i
  EndStructure  
  
  Global NewMap mapGadgetCallback.udtGadgetCallback()
  Global NewMap mapWindowNotification.udtWindowNotification()
  Global NewMap mapGadgetNotification.udtGadgetNotification()
  
  ; *** Callback ***
  
  Procedure SetGadgetCallback(Window, Gadget, *Callback, Method.s, PlaceholderList.s = "")
    Protected key.s, selector
    ; Add gadget to map gadget callback
    key = Str(GadgetID(Gadget))
    If Not FindMapElement(mapGadgetCallback(), key) 
      AddMapElement(mapGadgetCallback(), key)
      mapGadgetCallback()\Window = Window
      mapGadgetCallback()\Gadget = Gadget
    EndIf
    mapGadgetCallback()\refCount + 1
    ; Add method to delegateClass
    If Not Bool(PlaceholderList)
      PlaceholderList = "v@:" + LSet("@", CountString(Method, ":"), "@")
    EndIf
    selector = sel_registerName_(Method)
    If Not class_getInstanceMethod(delegateClass, selector)
      class_addMethod_(delegateClass, selector, *Callback, PlaceholderList)
    EndIf
    ; Add gadget to appDelegate
    CocoaMessage(0, GadgetID(Gadget), "setDelegate:", appDelegate)
  EndProcedure
  
  ; *** Notification ***
  
  Procedure SetWindowNotification(Window, *Callback, Notification.s)
    Protected selector, key.s
    ; Add Window to map Window notification
    key = Str(WindowID(Window))
    If Not FindMapElement(mapWindowNotification(), key) 
      AddMapElement(mapWindowNotification(), key)
      mapWindowNotification()\Window = Window
      mapWindowNotification()\Window = Window
    EndIf
    mapWindowNotification()\refCount + 1
    ; Add new callback method to delegateClass
    selector = sel_registerName("windowNotificationCB_" + Str(*Callback))
    If Not class_getInstanceMethod(delegateClass, selector)
      class_addMethod(delegateClass, selector, *Callback, "v@:@")
    EndIf
    ; Add Window to notification center
    CocoaMessage(0, notificationCenter,
                 "addObserver:", appDelegate, 
                 "selector:", selector,
                 "name:$", @Notification,
                 "object:", WindowID(Window))
  
  EndProcedure
  
  ; ----
  
  Procedure RemoveWindowNotification(Window, *Callback, Notification.s)
    If FindMapElement(mapWindowNotification(), Str(WindowID(Window)))
      CocoaMessage(0, notificationCenter,
                   "removeObserver:", appDelegate,
                   "name:$", @Notification,
                   "object:", WindowID(Window))
      mapWindowNotification()\refCount - 1
      If mapWindowNotification()\refCount <= 0
        DeleteMapElement(mapWindowNotification())
      EndIf
    EndIf
    
  EndProcedure
  
  ; ----
  
  Procedure SetGadgetNotification(Window, Gadget, *Callback, Notification.s)
    Protected selector, key.s
    ; Add gadget to map gadget notification
    key = Str(GadgetID(Gadget))
    If Not FindMapElement(mapGadgetNotification(), key) 
      AddMapElement(mapGadgetNotification(), key)
      mapGadgetNotification()\Window = Window
      mapGadgetNotification()\Gadget = Gadget
    EndIf
    mapGadgetNotification()\refCount + 1
    ; Add new callback method to delegateClass
    selector = sel_registerName("gadgetNotificationCB_" + Str(*Callback))
    If Not class_getInstanceMethod(delegateClass, selector)
      class_addMethod(delegateClass, selector, *Callback, "v@:@")
    EndIf
    ; Add gadget to notification center
    CocoaMessage(0, notificationCenter,
                 "addObserver:", appDelegate, 
                 "selector:", selector,
                 "name:$", @Notification,
                 "object:", GadgetID(Gadget))
  
  EndProcedure
  
  ; ----
  
  Procedure RemoveGadgetNotification(Window, Gadget, *Callback, Notification.s)
    If FindMapElement(mapGadgetNotification(), Str(GadgetID(Gadget)))
      CocoaMessage(0, notificationCenter,
                   "removeObserver:", appDelegate,
                   "name:$", @Notification,
                   "object:", GadgetID(Gadget))
      mapGadgetNotification()\refCount - 1
      If mapGadgetNotification()\refCount <= 0
        DeleteMapElement(mapGadgetNotification())
      EndIf
    EndIf
    
  EndProcedure
  
  ; *** Cocoa String Helper ***
  
  Macro CocoaString(NSString)
    PeekS(CocoaMessage(0, NSString, "UTF8String"), -1, #PB_UTF8)
  EndMacro
CompilerEndIf
; ********
