diff --git a/src/calibre/gui2/dbus_export/menu.py b/src/calibre/gui2/dbus_export/menu.py new file mode 100644 index 0000000000..3b5d1acf43 --- /dev/null +++ b/src/calibre/gui2/dbus_export/menu.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2014, Kovid Goyal ' + +import dbus + +from calibre.utils.dbus_service import Object + +class DBusMenu(Object): + + IFACE = 'com.canonical.dbusmenu' + + def __init__(self, notifier, object_path, **kw): + self.notifier = notifier + bus = kw.get('bus') + if bus is None: + bus = kw['bus'] = dbus.SessionBus() + Object.__init__(self, bus, object_path) + + def publish_new_menu(self): + pass + + diff --git a/src/calibre/gui2/dbus_export/tray.py b/src/calibre/gui2/dbus_export/tray.py index c8a3db91dc..f3d9a697f8 100644 --- a/src/calibre/gui2/dbus_export/tray.py +++ b/src/calibre/gui2/dbus_export/tray.py @@ -6,39 +6,22 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal ' -import os, sys, array, socket +# Implement the StatusNotifierItem spec for creating a system tray icon in +# modern linux desktop environments. See +# http://www.notmart.org/misc/statusnotifieritem/index.html#introduction +# This is not an actual standard, but is apparently used by GNOME, KDE and +# Unity, which makes it necessary enough to implement. + +import os import dbus from PyQt5.Qt import ( - QApplication, QObject, pyqtSignal, Qt, QPoint, QRect, QMenu, QImage, QSize, QIcon) + QApplication, QObject, pyqtSignal, Qt, QPoint, QRect, QMenu, QIcon) +from calibre.gui2.dbus_export.menu import DBusMenu +from calibre.gui2.dbus_export.utils import log, qicon_to_sni_image_list from calibre.utils.dbus_service import Object, method as dbus_method, BusName, dbus_property, signal as dbus_signal -def log(*args, **kw): - kw['file'] = sys.stderr - print('StatusNotifier:', *args, **kw) - kw['file'].flush() - -def qicon_to_sni_image_list(qicon): - 'See http://www.notmart.org/misc/statusnotifieritem/icons.html' - ans = dbus.Array(signature='(iiay)') - if not qicon.isNull(): - sizes = qicon.availableSizes() or (QSize(x, x) for x in (32, 64, 128, 256)) - tc = b'L' if array.array(b'I').itemsize < 4 else b'I' - for size in sizes: - # Convert to DBUS struct of width, height, and image data in ARGB32 - # in network endianness - i = qicon.pixmap(size).toImage().convertToFormat(QImage.Format_ARGB32) - w, h = i.width(), i.height() - data = i.constBits().asstring(4 * w * h) - if socket.htonl(1) != 1: - # Host endianness != Network Endiannes - data = array.array(tc, i.constBits().asstring(4 * i.width() * i.height())) - data.byteswap() - data = data.tostring() - ans.append((w, h, dbus.ByteArray(data))) - return ans - class Factory(QObject): 'See http://www.notmart.org/misc/statusnotifieritem/statusnotifierwatcher.html' @@ -186,20 +169,6 @@ class StatusNotifierItem(QObject): def icon(self): return self._icon -class DBusMenu(Object): - - IFACE = 'com.canonical.dbusmenu' - - def __init__(self, notifier, object_path, **kw): - self.notifier = notifier - bus = kw.get('bus') - if bus is None: - bus = kw['bus'] = dbus.SessionBus() - Object.__init__(self, bus, object_path) - - def publish_new_menu(self): - pass - class StatusNotifierItemAPI(Object): 'See http://www.notmart.org/misc/statusnotifieritem/statusnotifieritem.html' diff --git a/src/calibre/gui2/dbus_export/utils.py b/src/calibre/gui2/dbus_export/utils.py new file mode 100644 index 0000000000..dd3a3cd746 --- /dev/null +++ b/src/calibre/gui2/dbus_export/utils.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2014, Kovid Goyal ' + +import sys, array, socket + +import dbus + +from PyQt5.Qt import QSize, QImage + +def log(*args, **kw): + kw['file'] = sys.stderr + print('StatusNotifier:', *args, **kw) + kw['file'].flush() + + +def qicon_to_sni_image_list(qicon): + 'See http://www.notmart.org/misc/statusnotifieritem/icons.html' + ans = dbus.Array(signature='(iiay)') + if not qicon.isNull(): + sizes = qicon.availableSizes() or (QSize(x, x) for x in (32, 64, 128, 256)) + tc = b'L' if array.array(b'I').itemsize < 4 else b'I' + for size in sizes: + # Convert to DBUS struct of width, height, and image data in ARGB32 + # in network endianness + i = qicon.pixmap(size).toImage().convertToFormat(QImage.Format_ARGB32) + w, h = i.width(), i.height() + data = i.constBits().asstring(4 * w * h) + if socket.htonl(1) != 1: + # Host endianness != Network Endiannes + data = array.array(tc, i.constBits().asstring(4 * i.width() * i.height())) + data.byteswap() + data = data.tostring() + ans.append((w, h, dbus.ByteArray(data))) + return ans +