#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Defines one useful function :func:`notify()` to (try to) send a desktop notification.
- Only tested on Ubuntu and Debian desktops.
- Should work on any FreeDesktop compatible desktop, see https://wiki.ubuntu.com/NotifyOSD.
.. warning:: Experimental support of Mac OS X has been added since #143 (https://github.com/SMPyBandits/SMPyBandits/issues/143).
"""
from __future__ import division, print_function # Python 2 compatibility
__author__ = "Lilian Besson"
__version__ = "0.9"
from os import getcwd
from os.path import exists, join
from subprocess import Popen
VERBOUS = False
# Constants for the program
PROGRAM_NAME = "SMPyBandits" #: Program name
# ICON_PATH = join("..", "logo.png") #: Icon to use
ICON_PATH = "logo.png" #: Icon to use
# Define the icon loaded function
try:
from gi import require_version
require_version('GdkPixbuf', '2.0')
from gi.repository import GdkPixbuf
def load_icon():
""" Load and open the icon. """
# Loading the icon...
if exists(ICON_PATH):
# Use GdkPixbuf to create the proper image type
iconpng = GdkPixbuf.Pixbuf.new_from_file(ICON_PATH)
else:
iconpng = None
# print("iconpng =", iconpng) # DEBUG
return iconpng
except (ImportError, ValueError):
if VERBOUS:
print("\nError, gi.repository.GdkPixbuf seems to not be available, so notification icons will not be available ...")
print("On Ubuntu, if you want notification icons to work, install the 'python-gobject' and 'libnotify-bin' packages.")
print("(For more details, cf. 'http://www.devdungeon.com/content/desktop-notifications-python-libnotify')")
[docs] def load_icon():
""" Load and open the icon. """
return None
#: Trying to import gi.repository.Notify
has_Notify = False
try:
from gi import require_version
require_version('Notify', '0.7')
from gi.repository import Notify
# One time initialization of libnotify
Notify.init(PROGRAM_NAME)
has_Notify = True
except (ImportError, ValueError):
if VERBOUS:
print("\nError, gi.repository.Notify seems to not be available, so notification will not be available ...")
print("On Ubuntu, if you want notifications to work, install the 'python-gobject' and 'libnotify-bin' packages.")
print("(For more details, cf. 'http://www.devdungeon.com/content/desktop-notifications-python-libnotify')")
# Define the first notify function, with gi.repository.Notify
[docs]def notify_gi(body,
summary=PROGRAM_NAME,
icon="terminal",
timeout=5 # In seconds
):
""" Send a notification, with gi.repository.Notify.
- icon can be "dialog-information", "dialog-warn", "dialog-error".
"""
try:
# Trying to fix a bug:
# g-dbus-error-quark: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name :1.5124 was not provided by any .service files (2)
Notify.init(PROGRAM_NAME)
# XXX maybe the PROGRAM_NAME should be random?
# Cf. http://www.devdungeon.com/content/desktop-notifications-python-libnotify
# Create the notification object
notification = Notify.Notification.new(
summary, # Title of the notification
body, # Optional content of the notification
icon # XXX Should not indicate it here
)
# Lowest urgency (LOW, NORMAL or CRITICAL)
notification.set_urgency(Notify.Urgency.LOW)
# add duration, lower than 10 seconds (5 second is enough).
notification.set_timeout(timeout * 1000)
# Actually show the notification on screen
notification.show()
return 0
# Ugly! XXX Catches too general exception
except Exception as e:
print("\nnotify.notify(): Error, notify.notify() failed, with this exception")
print(e)
return -1
# Define the second notify function, with a subprocess call to 'notify-send'
[docs]def notify_cli(body,
summary=PROGRAM_NAME,
icon="terminal",
timeout=5, # In seconds,
gnulinux=True
):
""" Send a notification, with a subprocess call to 'notify-send'."""
try:
print("notify.notify(): Trying to use the command line program 'notify-send' ...")
icon = join(getcwd(), icon)
if gnulinux:
Popen(["notify-send", "--expire-time=%s" % (timeout * 1000), "--icon=%s" % icon, summary, body])
print("notify.notify(): A notification have been sent, with summary = '%s', body = '%s', expire-time='%s' and icon='%s'." % (summary, body, timeout * 1000, icon))
else:
# Cf. https://superuser.com/a/345455
Popen(["osascript", "-e", "'tell Application \"Finder\" to display dialog \"%s\"'" % body])
print("notify.notify(): A notification have been sent, with body = '%s'." % body)
return 0
# Ugly! XXX Catches too general exception
except Exception as e:
print("\nnotify.notify(): %s : not-found ! Returned exception is %s." % ("notify-send" if gnulinux else "osascript", e))
try:
if gnulinux:
return notify_cli(body, summary=summary, icon=icon, timeout=timeout, gnulinux=False)
else:
return -1
except Exception as e:
return -1
# Define the unified notify.notify() function
[docs]def notify(body,
summary=PROGRAM_NAME,
icon="terminal",
timeout=5 # In seconds
):
""" Send a notification, using one of the previously defined method, until it works. Usually it works."""
# print("Notification: '{}', from '{}' with icon '{}'.".format(body, summary, icon)) # DEBUG
if not has_Notify:
print("notify.notify(): Warning, desktop notification from Python seems to not be available ...")
return notify_cli(body, summary=summary, icon=icon, timeout=timeout)
else:
try:
return_code = notify_gi(body, summary=summary, icon=icon, timeout=timeout)
if return_code < 0:
return_code = notify_cli(body, summary=summary, icon=icon, timeout=timeout)
except Exception:
return_code = notify_cli(body, summary=summary, icon=icon, timeout=timeout)
return return_code
if __name__ == "__main__":
notify("Test body Test body Test body ! From 'notify(...)' with icon=terminal ...", icon="terminal")