Notify.NET/native/MacNotifyWrapper/MacNotifyWrapper.h
2026-06-14 15:00:42 -05:00

186 lines
8.5 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* MacNotifyWrapper.h
*
* Flat C API for macOS User Notifications (UNUserNotificationCenter).
* Consumed by the Notify.NET managed library via P/Invoke.
*
* All strings are UTF-8, null-terminated.
* Callbacks fire on a background GCD thread managed by UNUserNotificationCenter.
* The caller must not free any memory passed to MNW_ShowNotification before it returns;
* the implementation copies all fields before returning.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MACNOTIFYWRAPPER_EXPORTS
# define MACNOTIFYAPI __attribute__((visibility("default")))
#else
# define MACNOTIFYAPI
#endif
/* -------------------------------------------------------------------------
* Callback types — fired on a background thread from UNUserNotificationCenter.
* None of the callbacks should call back into MNW_* synchronously.
* ------------------------------------------------------------------------- */
typedef void (*MNW_ActivatedCallback) (int64_t notifId);
typedef void (*MNW_ButtonActivatedCallback)(int64_t notifId, int buttonIndex);
typedef void (*MNW_DismissedCallback) (int64_t notifId, int reason);
typedef void (*MNW_FailedCallback) (int64_t notifId);
/* -------------------------------------------------------------------------
* Dismiss reasons (passed to MNW_DismissedCallback)
* ------------------------------------------------------------------------- */
#define MNW_DISMISS_EXPIRED 0 /* Notification auto-expired (note: macOS does not fire this) */
#define MNW_DISMISS_USER 1 /* User swiped or clicked "Close" */
#define MNW_DISMISS_APP_REMOVED 2 /* Removed programmatically via MNW_HideNotification */
/* -------------------------------------------------------------------------
* Audio options
* ------------------------------------------------------------------------- */
#define MNW_AUDIO_DEFAULT 0
#define MNW_AUDIO_SILENT 1
/* -------------------------------------------------------------------------
* Interruption level (macOS 12+; silently ignored on earlier versions)
* ------------------------------------------------------------------------- */
#define MNW_INTERRUPTION_ACTIVE 0
#define MNW_INTERRUPTION_PASSIVE 1
#define MNW_INTERRUPTION_TIME_SENSITIVE 2
#define MNW_INTERRUPTION_CRITICAL 3
/* -------------------------------------------------------------------------
* Dock-tile progress states (passed to MNW_SetTaskbarProgress)
* ------------------------------------------------------------------------- */
#define MNW_PROGRESS_NONE 0 /* Clear the progress bar */
#define MNW_PROGRESS_INDETERMINATE 1 /* Animated bar with no specific value */
#define MNW_PROGRESS_NORMAL 2 /* Determinate bar at `fraction` */
#define MNW_PROGRESS_PAUSED 3 /* Same visual as NORMAL (Dock cannot tint) */
#define MNW_PROGRESS_ERROR 4 /* Same visual as NORMAL (Dock cannot tint) */
/* -------------------------------------------------------------------------
* Handler — bundle of four callback function pointers, copied by value.
* Any pointer may be NULL to opt out of that event.
* ------------------------------------------------------------------------- */
typedef struct {
MNW_ActivatedCallback onActivated;
MNW_ButtonActivatedCallback onButtonActivated;
MNW_DismissedCallback onDismissed;
MNW_FailedCallback onFailed;
} MNW_Handler;
/* -------------------------------------------------------------------------
* Notification descriptor.
* All pointer fields may be NULL / empty string where documented.
* The caller must keep all pointed-to memory valid until MNW_ShowNotification returns;
* the implementation deep-copies every string before returning.
* ------------------------------------------------------------------------- */
typedef struct {
const char* title; /* Required, non-empty UTF-8 string */
const char* body; /* Optional body text; NULL or "" → omitted */
const char* imagePath; /* Optional absolute path to an image file */
const char** buttonLabels; /* Optional array of buttonCount UTF-8 strings */
int buttonCount; /* 05 */
int64_t expirationMs; /* Reserved — UNUserNotificationCenter has no per-notification timeout API */
int audioOption; /* MNW_AUDIO_* */
int interruptionLevel; /* MNW_INTERRUPTION_* */
} MNW_NotificationDescriptor;
/* -------------------------------------------------------------------------
* API
* ------------------------------------------------------------------------- */
/**
* Returns true if UNUserNotificationCenter is available (macOS 10.14+).
* Safe to call before MNW_Initialize.
*/
MACNOTIFYAPI bool MNW_IsSupported(void);
/**
* Initialises the notification centre and requests authorisation (alert + sound + badge).
* Blocks until the user grants or denies the authorisation prompt (up to 30 s).
* Returns true if authorisation was granted; false if denied or unavailable.
* Safe to call multiple times; subsequent calls only re-check authorisation status.
*/
MACNOTIFYAPI bool MNW_Initialize(const char* appName);
/**
* Removes all pending and delivered notifications posted by this process and frees
* all internal state. Call once before the process exits.
*/
MACNOTIFYAPI void MNW_Uninitialize(void);
/**
* Posts a notification. Returns a positive opaque int64 identifier on success,
* or a negative value if the descriptor is invalid or the library is not initialised.
* The MNW_Handler callbacks will fire asynchronously from a background thread.
*/
MACNOTIFYAPI int64_t MNW_ShowNotification(
const MNW_NotificationDescriptor* descriptor,
const MNW_Handler* handler);
/**
* Removes a pending or delivered notification by its ID.
* Fires onDismissed(MNW_DISMISS_APP_REMOVED) synchronously before returning.
* Returns true if the notification was found and removed.
*/
MACNOTIFYAPI bool MNW_HideNotification(int64_t notifId);
/**
* Sets the Dock-tile progress indicator.
*
* @param state One of MNW_PROGRESS_*.
* @param fraction Progress in the range 0.01.0 (used only when state is
* MNW_PROGRESS_NORMAL / PAUSED / ERROR; ignored otherwise).
*
* The work is dispatched asynchronously onto the main thread because AppKit/Dock
* APIs are main-thread-only. It is therefore only effective for a regular GUI
* application whose main run loop is running and which owns a Dock tile; a bare
* console process has no Dock tile and the call is a harmless no-op.
* Safe to call before MNW_Initialize (it does not depend on notification state).
*/
MACNOTIFYAPI void MNW_SetTaskbarProgress(int state, double fraction);
/* -------------------------------------------------------------------------
* Dock menu (jump-list equivalent)
*
* Adds custom items to the application's Dock menu (shown on right-click / click-and-hold of
* the Dock icon). Unlike Windows jump lists / Linux .desktop actions, Dock-menu items fire a
* live in-process callback — there is no relaunch.
*
* Like the Dock-tile progress API these are only effective for a regular (bundled) GUI
* application with a running main loop; a bare console process has no Dock menu and the calls
* are harmless no-ops. The wrapper provides the menu via the application delegate's
* -applicationDockMenu:, installing its own delegate if the app has none, or adding the method
* to the existing delegate's class if it does not already implement it.
* ------------------------------------------------------------------------- */
/** Fired on the main thread when the user clicks a Dock-menu item. taskId is UTF-8. */
typedef void (*MNW_DockMenuCallback)(const char* taskId);
/** Registers the callback invoked when a Dock-menu item is clicked. Pass NULL to clear it. */
MACNOTIFYAPI void MNW_SetDockMenuHandler(MNW_DockMenuCallback callback);
/**
* Replaces the custom Dock-menu items.
*
* @param ids Array of `count` UTF-8 task ids (passed back to the callback when clicked).
* @param titles Array of `count` UTF-8 item labels, parallel to `ids`.
* @param count Number of items (0 clears the menu).
*
* The arrays are copied before this function returns; the caller may free them afterwards.
* Work is dispatched onto the main thread because AppKit menus are main-thread-only.
*/
MACNOTIFYAPI void MNW_SetDockMenu(const char** ids, const char** titles, int count);
/** Removes all custom Dock-menu items. Equivalent to MNW_SetDockMenu(NULL, NULL, 0). */
MACNOTIFYAPI void MNW_ClearDockMenu(void);
#ifdef __cplusplus
}
#endif