Notification
-
- Enthusiast
- Posts: 347
- Joined: Thu Jul 02, 2009 5:42 am
Notification
Is there anyway in PureBasic to send notifications in El Capitain?
Thanks
Thanks
Re: Notification
It should be possible but I'm having trouble to get it working
You need the NSUserNotificationCenter and NSUserNotification classes and the plist must contain a CFBundleIdentifier .
You need the NSUserNotificationCenter and NSUserNotification classes and the plist must contain a CFBundleIdentifier .
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
-
- Enthusiast
- Posts: 347
- Joined: Thu Jul 02, 2009 5:42 am
Re: Notification
Okay thanks Wilbert, looks like this will be a hard one to figure out
Re: Notification
You can add a notification like that:
I tested it and it works fine on OS X 10.11.
However i'm not sure if you need to sign your app. It didn't work for the first time, then i signed an app with the same bundle id and it started to work everywhere.
UPD: yes, you need to sign your app first or use a bundle id of any other already signed app (it seems that there are no checks for valid id)
Still, to display a popup you need to use delegate.
I have no idea how to port it. Wilbert, can you please help?
Code: Select all
notification = CocoaMessage(0,CocoaMessage(0,0,"NSUserNotification alloc"),"init")
CocoaMessage(0,notification,"setTitle:$",@"test")
CocoaMessage(0,notification,"setSubtitle:$",@"test2")
CocoaMessage(0,notification,"setInformativeText:$",@"test3")
notificationCenter = CocoaMessage(0,0,"NSUserNotificationCenter defaultUserNotificationCenter")
CocoaMessage(0,notificationCenter,"deliverNotification:",notification)
However i'm not sure if you need to sign your app. It didn't work for the first time, then i signed an app with the same bundle id and it started to work everywhere.
UPD: yes, you need to sign your app first or use a bundle id of any other already signed app (it seems that there are no checks for valid id)
Still, to display a popup you need to use delegate.
Code: Select all
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification
{
return YES;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSUserNotificationCenter *userNotificationCenter = [NSUserNotificationCenter defaultUserNotificationCenter];
userNotificationCenter.delegate = self;
}
Re: Notification
Another thing i found is that you don't need to do anything else if your app is hidden or at least not frontmost.
This code adds a notification and displays a popup:
But it would be nice to know how to do it in all cases.
This code adds a notification and displays a popup:
Code: Select all
app = CocoaMessage(0,0,"NSApplication sharedApplication")
OpenWindow(0,0,0,0,0,"")
CocoaMessage(0,app,"hide:")
notificationCenter = CocoaMessage(0,0,"NSUserNotificationCenter defaultUserNotificationCenter")
notification = CocoaMessage(0,CocoaMessage(0,0,"NSUserNotification alloc"),"init")
CocoaMessage(0,notification,"setTitle:$",@"test")
CocoaMessage(0,notification,"setSubtitle:$",@"test2")
CocoaMessage(0,notification,"setInformativeText:$",@"test3")
CocoaMessage(0,notificationCenter,"deliverNotification:",notification)
Repeat
ev = WaitWindowEvent()
Until ev = #PB_Event_CloseWindow
Re: Notification
What else i'm trying to achieve is to control a behaviour when user clicks on notification. By default it just activates your application, which can be not exactly what you need. As far as i know, there is no way to define desired action.
I looked into sources of TerminalNotifier (very nice app by the way) and it seems that there is a callback called userActivatedNotification which is being called by NotificationCenter itself (?).
How to implement it in PB?
I looked into sources of TerminalNotifier (very nice app by the way) and it seems that there is a callback called userActivatedNotification which is being called by NotificationCenter itself (?).
How to implement it in PB?
Re: Notification
From what I understand you need to implement applicationDidFinishLaunching: .
When the application is launched, it sends a NSNotification object to this method from which you need the userInfo to get the NSUserNotification object.
NSUserNotification * userNotification = [[aNotification userInfo] objectForKey:NSApplicationLaunchUserNotificationKey];
I think PB also uses applicationDidFinishLaunching so you might need to hook into this and still call the implementation PureBasic provides to prevent problems.
When the application is launched, it sends a NSNotification object to this method from which you need the userInfo to get the NSUserNotification object.
NSUserNotification * userNotification = [[aNotification userInfo] objectForKey:NSApplicationLaunchUserNotificationKey];
I think PB also uses applicationDidFinishLaunching so you might need to hook into this and still call the implementation PureBasic provides to prevent problems.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Notification
Thanks wilbert.
How can i do that? Where to start?wilbert wrote:I think PB also uses applicationDidFinishLaunching so you might need to hook into this and still call the implementation PureBasic provides to prevent problems.
Re: Notification
You need method swizzling but I'm no expert on thatdeseven wrote:How can i do that? Where to start?
What also might work is add an observer for NSApplicationDidFinishLaunchingNotification but I'm not sure if that sends the right object.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Notification
For now i don't need to know what notification it is, it will be enough to know that user clicked on any notification. So probably i don't need an object with notification.
How to add an observer for NSApplicationDidFinishLaunchingNotification then?
How to add an observer for NSApplicationDidFinishLaunchingNotification then?
Re: Notification
Can you try if this does anything at all ?deseven wrote:How to add an observer for NSApplicationDidFinishLaunchingNotification then?
Code: Select all
Global notificationCenter = CocoaMessage(0, 0, "NSNotificationCenter defaultCenter")
Global appDelegate = CocoaMessage(0, CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
Global delegateClass = object_getClass_(appDelegate)
ProcedureC DidFinishLaunching(obj, sel, notification)
Protected userInfo.i = CocoaMessage(0, notification, "userInfo")
Protected userNotification.i = CocoaMessage(0, userInfo, "objectForKey:$", @"NSApplicationLaunchUserNotificationKey")
If userNotification
MessageRequester("UserNotification", "UserNotification was clicked")
EndIf
EndProcedure
selector = sel_registerName_("MyAppDidFinishLaunching:")
class_addMethod_(delegateClass, selector, @DidFinishLaunching(), "v@:@")
CocoaMessage(0, notificationCenter, "addObserver:", appDelegate, "selector:", selector, "name:$", @"NSApplicationDidFinishLaunchingNotification", "object:", #nil)
If OpenWindow(0, 0, 0, 320, 170, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
EditorGadget(0, 10, 10, 300, 150)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
CocoaMessage(0, notificationCenter, "removeObserver:", appDelegate, "name:$", @"NSApplicationDidFinishLaunchingNotification", "object:", #nil)
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Notification
Nope.
DidFinishLaunching() is called only once when application starts (which is actually strange), click on a notification doesn't do anything.
The only difference with your code is that if your app is closed completely then click on a notification opens an empty window without title. Don't know how that happens.
But thanks for showing me how to add observers, i'll try to figure something out.
DidFinishLaunching() is called only once when application starts (which is actually strange), click on a notification doesn't do anything.
The only difference with your code is that if your app is closed completely then click on a notification opens an empty window without title. Don't know how that happens.
But thanks for showing me how to add observers, i'll try to figure something out.
Re: Notification
It seems that NSApplicationDidFinishLaunchingNotification doesn't have anything to do with notifications from NotificationCenter at all.
UPD: here is what i need to catch:
UPD: here is what i need to catch:
Code: Select all
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
Re: Notification
According to the NSUserNotificationCenterDelegate Protocol Reference ...
It might be impossible to catch this because of the message already been delivered before the PB code can do something about it.
But it seems this behavior is not what you are looking for.
Try this
By the way, new is a combination of alloc and init so you can also create your notification
notification = CocoaMessage(0,0,"NSUserNotification new")
I didn't read the last line carefully.NSUserNotificationCenterDelegate Protocol Reference wrote:To take an action when your application is launched as a result of a user clicking on a notification, be sure to implement the applicationDidFinishLaunching: method in the application class that implements the NSApplicationDelegate Protocol protocol. The notification parameter to that method has a userInfo dictionary, and if that dictionary has the NSApplicationLaunchUserNotificationKey key. The value of that key is the NSUserNotification object that caused the application to launch. The NSUserNotification object is delivered to the NSApplication delegate because that message will be sent before your application has a chance to set a delegate for the NSUserNotificationCenter.
It might be impossible to catch this because of the message already been delivered before the PB code can do something about it.
But it seems this behavior is not what you are looking for.
Try this
Code: Select all
ProcedureC DidActivateNotification(obj, sel, center, notification)
MessageRequester("","didActivateNotification")
EndProcedure
ProcedureC ShouldPresentNotification(obj, sel, center, notification)
ProcedureReturn #YES
EndProcedure
; >>> Create delegate class <<<
delegateClass = objc_allocateClassPair_(objc_getClass_("NSObject"), "myDelegateClass", 0)
; >>> Add delegate methods <<<
class_addMethod_(delegateClass,
sel_registerName_("userNotificationCenter:didActivateNotification:"),
@DidActivateNotification(), "v@:@@")
class_addMethod_(delegateClass,
sel_registerName_("userNotificationCenter:shouldPresentNotification:"),
@ShouldPresentNotification(), "c@:@@")
; >>> Register class <<<
objc_registerClassPair_(delegateClass)
; >>> Create delegate instance <<<
delegate = class_createInstance_(delegateClass, 0)
Global userNotificationCenter = CocoaMessage(0, 0, "NSUserNotificationCenter defaultUserNotificationCenter")
CocoaMessage(0, userNotificationCenter, "setDelegate:", delegate)
notification = CocoaMessage(0,0,"NSUserNotification new")
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Notification
Works like a charm! Thank you very much!wilbert wrote:Try this
Didn't know, thanks again.wilbert wrote:By the way, new is a combination of alloc and init so you can also create your notification
notification = CocoaMessage(0,0,"NSUserNotification new")
Next thing is to populate and parse userInfo dictionary to be able to define specific actions, but that's easy enough, i can do it.
I think i'm going to write a module so everyone can use native OS X notifications easily.