desktop-notifier

repository·main·Indexed 41 days ago

https://github.com/samschott/desktop-notifier

A Python library for sending cross-platform desktop notifications on Linux, macOS, iOS, and Windows. Version 6.2.0 supports asynchronous notifications via the DesktopNotifier class, featuring advanced capabilities such as clickable buttons, reply fields, callbacks for notification lifecycle events, and file attachments.

Tokens
7.7K
Snippets
26
Records
36
Agent score
91%

What's inside desktop-notifier

  1. Handle notification callbacks with an event loop

    main

    MacOS, Windows, and most Linux notification servers support executing Python callbacks when a notification is clicked (on_clicked) or dismissed (on_dismissed).

    Requirement: To ensure these callbacks are actually executed, you must have a running event loop in your Python application to handle the incoming interactions.

  2. Configure notification attachments per platform

    main

    Attachments allow you to include media in notifications. Supported types and limitations vary:

    macOS and iOS

    Supports local files with the following limits:

    • Audio: Up to 5 MB (AIFF, WAV, MP3, or MPEG4).
    • Images: Up to 10 MB (JPEG, GIF, or PNG). macOS only shows previews; iOS shows previews and allows full viewing via long-press.
    • Video: Up to 50 MB (MPEG, MPEG2, MPEG4, or AVI).

    Windows

    • Supports images only.
    • The image URI must be a web URL or a resource bundled with the application.

    Linux

    • Supports attaching a secondary image.
    • If the notification server does not support a secondary image, the app icon is typically replaced by a thumbnail of the attached image (e.g., in Gnome).
  3. Configure notification buttons per platform

    main

    You can add buttons to notifications to allow user interaction via callbacks. However, the number of supported buttons is limited by the platform:

    • macOS: Supports an unlimited number of buttons.
    • Windows: Supports up to 5 buttons.
    • Linux: Support varies by desktop environment. For example, Gnome typically supports up to 3 buttons.

    Note: If you specify more buttons than the platform supports, any additional buttons will be silently ignored.

  4. Integrate with macOS CFRunLoop using rubicon-objc

    main

    On macOS, executing callbacks requires a running CFRunLoop. To integrate asyncio with the required Core Foundation loop, use rubicon-objc and set the EventLoopPolicy.

    import asyncio
    from rubicon.objc.eventloop import EventLoopPolicy
    
    # Install the event loop policy
    asyncio.set_event_loop_policy(EventLoopPolicy())
  5. Integrate the event loop on macOS

    main

    To use the asynchronous API effectively and ensure callbacks execute correctly on macOS, you must have a running CFRunLoop. You can integrate asyncio with CFRunLoop using the EventLoopPolicy from the rubicon-objc library. Since desktop-notifier already uses rubicon-objc to interface with Cocoa APIs, installing this policy does not add new external dependencies to your project.

    On Linux, a standard asyncio event loop is sufficient, but macOS requires this specific policy to prevent blocking IO from Cocoa APIs.

    import asyncio
    from rubicon.objc.eventloop import EventLoopPolicy
    
    # Install the event loop policy
    asyncio.set_event_loop_policy(EventLoopPolicy())
  6. Install and use Desktop Notifier

    main

    Desktop Notifier is a Python library for sending desktop notifications.

    Installation

    Install the package using pip:

    pip install desktop-notifier

    Basic Usage

    To send a notification, import the library and use the notification functions. (Note: Refer to the specific API documentation for detailed method signatures).

  7. Integrate asyncio with a Gtk main loop

    main

    If you are developing a Gtk application on Gnome, you can integrate the asyncio event loop with the Gtk main loop using the gbulb library. While this is not required for the full functionality of desktop-notifier, it can be a convenient way to manage concurrency within a Gtk environment.

    # Use gbulb to integrate asyncio with Gtk
    # (Requires installing gbulb)
  8. Handle notification interaction events in a backend

    main

    The DesktopNotifierBackend provides hooks for responding to user interactions with notifications. You can define these at two levels:

    1. Global Backend Callbacks: Set these on the backend instance itself (e.g., backend.on_clicked = my_callback). These are triggered if the specific Notification object does not have its own individual callback defined.
    2. Per-Notification Callbacks: Define callbacks directly on the Notification object (e.g., notification.on_clicked = my_callback). These take precedence over global backend callbacks.

    Available Event Handlers:

    • on_dispatched: Triggered when a notification is successfully sent.
    • on_clicked: Triggered when a user clicks the notification.
    • on_dismissed: Triggered when a user dismisses the notification.
    • on_button_pressed(identifier: str, button_identifier: str): Triggered when a specific button on a notification is pressed.
    • on_replied(identifier: str, reply_text: str): Triggered when a user submits a text reply to a notification.
  9. Configure Notification components

    main

    A Notification can be customized using several supporting classes and types to control its appearance and interactivity:

    • Button: Add interactive buttons to a notification.
    • ReplyField: Add a text input field for user replies.
    • Urgency: Set the importance level of the notification.
    • Icon: Specify a custom icon for the notification.
    • Sound: Specify a custom sound to play.
    • Attachment: Attach files to the notification.
    • Capability: Check for supported features on the current platform.
  10. Use FileResource for Icons, Sounds, and Attachments

    main

    The project uses FileResource (and its subclasses Icon, Sound, and Attachment) to handle media. A resource must be initialized with either a local path (as a pathlib.Path) or a uri (as a str). Providing both or neither will raise a RuntimeError.

    from pathlib import Path
    from desktop_notifier import Icon, Sound, Attachment
    
    # Using a local path
    my_icon = Icon(path=Path("/path/to/icon.png"))
    
    # Using a URI
    my_sound = Sound(uri="file:///path/to/sound.wav")
    
    # Using a system name (for Sound/Icon)
    my_system_sound = Sound(name="default")
  11. Handle notification interaction callbacks

    main

    You can handle user interactions in two ways:

    1. Class-level handlers: Set these on the DesktopNotifier instance. They act as defaults for all notifications sent by that instance. They receive the notification identifier as an argument.
    2. Notification-level handlers: Set these directly on a Notification object (or via the send() method). These take precedence over class-level handlers and are tied to the specific Python instance of that notification.

    Available Callbacks:

    • on_dispatched(notification_id: str): Called when the notification is sent to the system.
    • on_clicked(notification_id: str): Called when the user clicks the notification.
    • on_dismissed(notification_id: str): Called when the user dismisses the notification.
    • on_button_pressed(notification_id: str, button_id: str): Called when a specific button is clicked.
    • on_replied(notification_id: str, text: str): Called when a user submits text via a ReplyField.
    # Class-level handler
    notifier.on_clicked = lambda nid: print(f"Clicked: {nid}")
    
    # Notification-level handler (takes precedence)
    await notifier.send(
        title="Specific Task",
        message="Click me",
        on_clicked=lambda nid: print("Clicked specific notification")
    )