Cross-platform desktop notifier in Python

你。 提交于 2019-11-28 15:43:21

Here's a desktop notifier I wrote a few years ago using wxPython - it behaves identically across Windows and Linux and should also run on OSX. It contains a threaded event loop that can be used to animate a notification window containing an icon and message that can be clicked on. It probably needs a couple of tweaks to customize it for your own purpose but the ground work is done.

At Pycon 2010 there was a presentation on cross-platform Python development. There was a html page about it as well, containing some advice for cross-platform notification. However, I don't find it online anymore, but I saved a local copy, and this is the part on notifications:

There are occasions in which your application wants to notify the user about something: software updates are available, a new instant message have been received, the 300 page print job has finally finished, etc.

  • To keep notifications easy to port cross-platform, don't make them interactive. For example Ubuntu does not support notifications that require user interaction.
  • These are the most important libraries:

    o Linux: pynotify.

    o Mac OS X: Growl, which is not standard, is usually installed.

    o Windows: a good wxPython solution is ToasterBox of Andrea Gavana, which mimics the look of Firefox or Thunderbird notifications.

  • For Phatch we developed a library that unifies these three systems in one API: phatch/lib/notify.py.

The linked python file is very interesting, and I think you should be able to use the linked python file almost as is. The code is also very clear, so you'll quickly see what it does.

The basic approach is it detects what notification systems are available, almost regardless of the platform, and tries to use them in a certain order but falls back to more simple systems if necessary. This way, if the user has e.g. Growl installed it'll use it, regardless of the platform.

You could adapt it to provide support for other notification systems than the three mentioned above.

masklinn
  • How to go about writing it

    Check how keyring handles the cross-platform issues (it's a python library which plugs into various autodetected keychain backends for storage)

  • Growl isn't bundled with OSX you have to install it separately, OSX doesn't come with any built-in notification system.

  • For unixes, you might want to hook into DBus as already mentioned (as a fallback, note that dbus might also be available in OSX), but both KDE and Gnome have Growl-like libraries. Respectively, KNotification for KDE and libnotify for Gnome.

  • For windows, check out Snarl, fall back to notification bubbles if not available (using something along the lines of ToasterBox)

Do not ever even think of making notifications sticky. It's stupid, it's insensitive and it's freaking annoying. Also, due to people like you it's been made not available in most notification systems.

Finally, even if there is no Python lib for any of these, you can probably use ctypes to access them.

try PyQt4, if you don't care about the size.

here is the class for this job: http://doc.trolltech.com/4.5/qsystemtrayicon.html

Sounds like you need Growl for Windows

Here is something simple that works for me. The Toast stays up for 2 secs and disappears. Yes, OP didn't want 'gigantic' PyQt4, but this may be useful to others.

import sys, time
from PyQt4 import QtCore, QtGui
import uiToast

window = None   # global

# Usage: Toast('Message')
class Toast(QtGui.QMainWindow):
    def __init__(self, msg):
        global window               # some space outside the local stack
        window = self               # save pointer till killed to avoid GC
        QtGui.QWidget.__init__(self)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.ui = uiToast.Ui_MainWindow()
        self.ui.setupUi(self)

        self.ui.display.setText(msg)

        self.toastThread = ToastThread()    # start thread to remove display
        self.connect(self.toastThread, QtCore.SIGNAL("finished()"), self.toastDone)
        self.toastThread.start()
        self.show()

    def toastDone(self):
        global window
        window = None               # kill pointer to window object to close it and GC

class ToastThread(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)

    def run(self):
        time.sleep(2.0)             # wait and die

The trimmed down file 'uiToast.py' created by pyuic4 is:

from PyQt4 import QtCore, QtGui
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.resize(547, 96)
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(255, 170, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
        MainWindow.setPalette(palette)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.display = QtGui.QTextBrowser(self.centralwidget)
        self.display.setGeometry(QtCore.QRect(0, 0, 551, 101))
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(255, 170, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
        self.display.setPalette(palette)
        font = QtGui.QFont()
        font.setPointSize(12)
        self.display.setFont(font)
        MainWindow.setCentralWidget(self.centralwidget)

For good cross-platform support, I would look at PyQt. It will add some heft to your library, but they've done a good job working out most of the kinks.

Dim
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!