diff --git a/resources/images/notify.png b/resources/images/notify.png new file mode 100644 index 0000000000..1ced8ea8c2 Binary files /dev/null and b/resources/images/notify.png differ diff --git a/setup/installer/linux/freeze.py b/setup/installer/linux/freeze.py index 632009a300..2c691e47de 100644 --- a/setup/installer/linux/freeze.py +++ b/setup/installer/linux/freeze.py @@ -108,7 +108,7 @@ class LinuxFreeze(Command): 'glib', 'gobject'] packages = ['calibre', 'encodings', 'cherrypy', 'cssutils', 'xdg', - 'dateutil', 'dns', 'email'] + 'dateutil', 'dns', 'email', 'dbus'] includes += ['calibre.gui2.convert.'+x.split('/')[-1].rpartition('.')[0] for x in \ glob.glob('src/calibre/gui2/convert/*.py')] diff --git a/src/calibre/gui2/notify.py b/src/calibre/gui2/notify.py new file mode 100644 index 0000000000..fe7b3c78a7 --- /dev/null +++ b/src/calibre/gui2/notify.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +from calibre.constants import islinux + +class Notifier(object): + + DEFAULT_TIMEOUT = 5000 + + def get_msg_parms(self, timeout, body, summary): + if summary is None: + summary = 'calibre' + if timeout == 0: + timeout = self.DEFAULT_TIMEOUT + return timeout, body, summary + + def __call__(self, body, summary=None, replaces_id=None, timeout=0): + raise NotImplementedError + + +class DBUSNotifier(Notifier): + + ICON = I('notify.png') + + def __init__(self, server, path): + self.ok, self.err = True, None + try: + import dbus + self.dbus = dbus + self._notify = dbus.SessionBus().get_object(server, path) + except Exception, err: + self.ok = False + self.err = str(err) + + +class KDENotifier(DBUSNotifier): + + def __init__(self): + DBUSNotifier.__init__(self, 'org.kde.VisualNotifications', + '/VisualNotifications') + + def __call__(self, body, summary=None, replaces_id=None, timeout=0): + if replaces_id is None: + replaces_id = self.dbus.UInt32() + event_id = '' + timeout, body, summary = self.get_msg_parms(timeout, body, summary) + self._notify.Notify('calibre', replaces_id, event_id, self.ICON, summary, body, + self.dbus.Array(signature='s'), self.dbus.Dictionary(signature='sv'), + timeout) + +class FDONotifier(DBUSNotifier): + + def __init__(self): + DBUSNotifier.__init__(self, 'org.freedesktop.Notifications', + '/org/freedesktop/Notifications') + + def __call__(self, body, summary=None, replaces_id=None, timeout=0): + if replaces_id is None: + replaces_id = self.dbus.UInt32() + timeout, body, summary = self.get_msg_parms(timeout, body, summary) + self._notify.Notify('calibre', replaces_id, self.ICON, summary, body, + self.dbus.Array(signature='s'), self.dbus.Dictionary(signature='sv'), + timeout) + +class QtNotifier(Notifier): + + def __init__(self, systray=None): + self.systray = systray + self.ok = self.systray is not None and self.systray.supportsMessages() + + def __call__(self, body, summary=None, replaces_id=None, timeout=0): + timeout, body, summary = self.get_msg_parms(timeout, body, summary) + if self.systray is not None: + self.systray.showMessage(summary, body, self.systray.Information, + timeout) + +def get_notifier(systray=None): + ans = None + if islinux: + ans = KDENotifier() + if not ans.ok: + ans = FDONotifier() + if not ans.ok: + ans = None + if ans is None: + ans = QtNotifier(systray) + if not ans.ok: + ans = None + return ans + + +if __name__ == '__main__': + n = KDENotifier() + n('hello') + n = FDONotifier() + n('hello') + ''' + from PyQt4.Qt import QApplication, QSystemTrayIcon, QIcon + app = QApplication([]) + ic = QIcon(I('notify.png')) + tray = QSystemTrayIcon(ic) + tray.setVisible(True) + n = QtNotifier(tray) + n('hello') + ''' diff --git a/src/calibre/gui2/status.py b/src/calibre/gui2/status.py index 3b421d1afd..af161db818 100644 --- a/src/calibre/gui2/status.py +++ b/src/calibre/gui2/status.py @@ -9,6 +9,7 @@ from calibre import fit_image, preferred_encoding, isosx from calibre.gui2 import qstring_to_unicode, config from calibre.gui2.widgets import IMAGE_EXTENSIONS from calibre.gui2.progress_indicator import ProgressIndicator +from calibre.gui2.notify import get_notifier from calibre.ebooks import BOOK_EXTENSIONS class BookInfoDisplay(QWidget): @@ -218,6 +219,7 @@ class StatusBar(QStatusBar): def __init__(self, jobs_dialog, systray=None): QStatusBar.__init__(self) self.systray = systray + self.notifier = get_notifier(systray) self.movie_button = MovieButton(jobs_dialog) self.cover_flow_button = CoverFlowButton() self.tag_view_button = TagViewButton() @@ -247,13 +249,13 @@ class StatusBar(QStatusBar): def showMessage(self, msg, timeout=0): ret = QStatusBar.showMessage(self, msg, timeout) - if self.systray is not None and not config['disable_tray_notification']: + if self.notifier is not None and not config['disable_tray_notification']: if isosx and isinstance(msg, unicode): try: msg = msg.encode(preferred_encoding) except UnicodeEncodeError: msg = msg.encode('utf-8') - self.systray.showMessage('calibre', msg, self.systray.Information, 10000) + self.notifier(msg) return ret def jobs(self):