mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add system tray to demo app
This commit is contained in:
parent
fce224af80
commit
1b1f1b0cc8
@ -8,7 +8,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from PyQt5.Qt import (
|
||||
QApplication, QMainWindow, QVBoxLayout, Qt, QKeySequence, QAction,
|
||||
QActionGroup, QMenu)
|
||||
QActionGroup, QMenu, QIcon)
|
||||
|
||||
from calibre.gui2.dbus_export.utils import setup_for_cli_run
|
||||
from calibre.gui2.dbus_export.widgets import factory
|
||||
@ -22,6 +22,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def __init__(self):
|
||||
QMainWindow.__init__(self)
|
||||
f = factory()
|
||||
self.setMinimumWidth(400)
|
||||
self.setWindowTitle('Demo of DBUS menu exporter and systray integration')
|
||||
self.statusBar().showMessage(self.windowTitle())
|
||||
@ -32,6 +33,11 @@ class MainWindow(QMainWindow):
|
||||
m = self.menu_one = mb.addMenu('&One')
|
||||
m.aboutToShow.connect(self.about_to_show_one)
|
||||
s = self.style()
|
||||
self.q = q = QAction('&Quit', self)
|
||||
q.setShortcut(QKeySequence.Quit)
|
||||
q.triggered.connect(QApplication.quit)
|
||||
self.addAction(q)
|
||||
QApplication.instance().setWindowIcon(QIcon(I('debug.png')))
|
||||
for i, icon in zip(xrange(3), map(s.standardIcon, (s.SP_DialogOkButton, s.SP_DialogCancelButton, s.SP_ArrowUp))):
|
||||
ac = m.addAction('One - &%d' % (i + 1))
|
||||
ac.setShortcut(QKeySequence(Qt.CTRL | (Qt.Key_1 + i), Qt.SHIFT | (Qt.Key_1 + i)))
|
||||
@ -57,6 +63,32 @@ class MainWindow(QMainWindow):
|
||||
ac.triggered.connect(self.action_triggered)
|
||||
for m in mb.findChildren(QMenu):
|
||||
m.aboutToShow.connect(self.about_to_show)
|
||||
self.systray = f.create_system_tray_icon(parent=self, title=self.windowTitle())
|
||||
if self.systray is not None:
|
||||
self.systray.activated.connect(self.tray_activated)
|
||||
self.sm = m = QMenu()
|
||||
m.addAction('Show/hide main window').triggered.connect(self.tray_activated)
|
||||
m.addAction(q)
|
||||
self.systray.setContextMenu(m)
|
||||
self.update_tray_toggle_action()
|
||||
print ('DBUS connection unique name:', f.bus.get_unique_name())
|
||||
|
||||
def update_tray_toggle_action(self):
|
||||
if hasattr(self, 'sm'):
|
||||
self.sm.actions()[0].setText('Hide main window' if self.isVisible() else 'Show main window')
|
||||
|
||||
def hideEvent(self, ev):
|
||||
if not ev.spontaneous():
|
||||
self.update_tray_toggle_action()
|
||||
return QMainWindow.hideEvent(self, ev)
|
||||
|
||||
def showEvent(self, ev):
|
||||
if not ev.spontaneous():
|
||||
self.update_tray_toggle_action()
|
||||
return QMainWindow.showEvent(self, ev)
|
||||
|
||||
def tray_activated(self):
|
||||
self.setVisible(not self.isVisible())
|
||||
|
||||
def action_triggered(self, checked=False):
|
||||
ac = self.sender()
|
||||
@ -74,8 +106,7 @@ class MainWindow(QMainWindow):
|
||||
self.menu_two.addAction('Action added by about to show')
|
||||
|
||||
app = QApplication([])
|
||||
f = factory()
|
||||
app.setApplicationName('com.calibre-ebook.DBusExportDemo')
|
||||
mw = MainWindow()
|
||||
mw.show()
|
||||
print ('DBUS connection unique name:', f.bus.get_unique_name())
|
||||
app.exec_()
|
||||
|
@ -68,12 +68,12 @@ class DBusMenu(QObject):
|
||||
|
||||
handle_event_signal = pyqtSignal(object, object, object, object)
|
||||
|
||||
def __init__(self, object_path, **kw):
|
||||
QObject.__init__(self, kw.get('parent'))
|
||||
def __init__(self, object_path, parent=None, bus=None):
|
||||
QObject.__init__(self, parent)
|
||||
# Unity barfs is the Event DBUS method does not return immediately, so
|
||||
# handle it asynchronously
|
||||
self.handle_event_signal.connect(self.handle_event, type=Qt.QueuedConnection)
|
||||
self.dbus_api = DBusMenuAPI(self, object_path, **kw)
|
||||
self.dbus_api = DBusMenuAPI(self, object_path, bus=bus)
|
||||
self.set_status = self.dbus_api.set_status
|
||||
self._next_id = 0
|
||||
self.action_changed_timer = t = QTimer(self)
|
||||
@ -82,6 +82,10 @@ class DBusMenu(QObject):
|
||||
t.setInterval(0), t.setSingleShot(True), t.timeout.connect(self.layouts_changed)
|
||||
self.init_maps()
|
||||
|
||||
@property
|
||||
def object_path(self):
|
||||
return self.dbus_api._object_path
|
||||
|
||||
def init_maps(self, qmenu=None):
|
||||
self.action_changes = set()
|
||||
self.layout_changes = set()
|
||||
@ -241,10 +245,9 @@ class DBusMenuAPI(Object):
|
||||
|
||||
IFACE = 'com.canonical.dbusmenu'
|
||||
|
||||
def __init__(self, menu, object_path, **kw):
|
||||
bus = kw.get('bus')
|
||||
def __init__(self, menu, object_path, bus=None):
|
||||
if bus is None:
|
||||
bus = kw['bus'] = dbus.SessionBus()
|
||||
bus = dbus.SessionBus()
|
||||
Object.__init__(self, bus, object_path)
|
||||
self.status = 'normal'
|
||||
self.menu = menu
|
||||
|
@ -16,7 +16,7 @@ import os
|
||||
|
||||
import dbus
|
||||
from PyQt5.Qt import (
|
||||
QApplication, QObject, pyqtSignal, Qt, QPoint, QRect, QMenu, QIcon)
|
||||
QApplication, QObject, pyqtSignal, Qt, QPoint, QRect, QMenu)
|
||||
|
||||
from calibre.gui2.dbus_export.menu import DBusMenu
|
||||
from calibre.gui2.dbus_export.utils import qicon_to_sni_image_list
|
||||
@ -36,7 +36,7 @@ class StatusNotifierItem(QObject):
|
||||
self.context_menu = None
|
||||
self.is_visible = True
|
||||
self.tool_tip = ''
|
||||
self._icon = QIcon()
|
||||
self._icon = QApplication.instance().windowIcon()
|
||||
self.show_menu.connect(self._show_menu, type=Qt.QueuedConnection)
|
||||
_sni_count += 1
|
||||
kw['num'] = _sni_count
|
||||
@ -85,6 +85,8 @@ class StatusNotifierItem(QObject):
|
||||
def icon(self):
|
||||
return self._icon
|
||||
|
||||
_status_item_menu_count = 0
|
||||
|
||||
class StatusNotifierItemAPI(Object):
|
||||
|
||||
'See http://www.notmart.org/misc/statusnotifieritem/statusnotifieritem.html'
|
||||
@ -92,6 +94,7 @@ class StatusNotifierItemAPI(Object):
|
||||
IFACE = 'org.kde.StatusNotifierItem'
|
||||
|
||||
def __init__(self, notifier, **kw):
|
||||
global _status_item_menu_count
|
||||
self.notifier = notifier
|
||||
bus = kw.get('bus')
|
||||
if bus is None:
|
||||
@ -103,7 +106,8 @@ class StatusNotifierItemAPI(Object):
|
||||
self.title = kw.get('title') or self.app_id
|
||||
self.icon_serialization = qicon_to_sni_image_list(notifier.icon())
|
||||
Object.__init__(self, bus, '/' + self.IFACE.split('.')[-1])
|
||||
self.dbus_menu = DBusMenu('/StatusItemMenu', **kw)
|
||||
_status_item_menu_count += 1
|
||||
self.dbus_menu = DBusMenu('/StatusItemMenu/%d' % _status_item_menu_count, bus=bus, parent=kw.get('parent'))
|
||||
|
||||
def publish_new_menu(self):
|
||||
menu = self.notifier.contextMenu()
|
||||
@ -166,7 +170,7 @@ class StatusNotifierItemAPI(Object):
|
||||
|
||||
@dbus_property(IFACE, signature='o')
|
||||
def Menu(self):
|
||||
return dbus.ObjectPath(self.dbus_menu._object_path)
|
||||
return dbus.ObjectPath(self.dbus_menu.object_path)
|
||||
|
||||
@dbus_property(IFACE, signature='i')
|
||||
def WindowId(self):
|
||||
|
@ -8,7 +8,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import time, sys
|
||||
|
||||
from PyQt5.Qt import QObject, QMenuBar, QAction, QEvent, QSystemTrayIcon
|
||||
from PyQt5.Qt import QObject, QMenuBar, QAction, QEvent, QSystemTrayIcon, QApplication
|
||||
|
||||
from calibre.constants import iswindows, isosx
|
||||
|
||||
@ -82,8 +82,9 @@ class ExportedMenuBar(QMenuBar):
|
||||
|
||||
class Factory(QObject):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, app_id=None):
|
||||
QObject.__init__(self)
|
||||
self.app_id = app_id or QApplication.instance().applicationName() or 'unknown_application'
|
||||
if iswindows or isosx:
|
||||
self.dbus = None
|
||||
else:
|
||||
@ -144,7 +145,7 @@ class Factory(QObject):
|
||||
'See http://www.notmart.org/misc/statusnotifieritem/statusnotifierwatcher.html'
|
||||
self.status_notifier = False
|
||||
if self.bus.name_has_owner(STATUS_NOTIFIER[0]):
|
||||
args = STATUS_NOTIFIER + ('Get', 'ss', (STATUS_NOTIFIER[-1], 'IsStatusNotifierHostRegistered'))
|
||||
args = STATUS_NOTIFIER[:2] + (self.dbus.PROPERTIES_IFACE, 'Get', 'ss', (STATUS_NOTIFIER[-1], 'IsStatusNotifierHostRegistered'))
|
||||
self.status_notifier = bool(self.bus.call_blocking(*args, timeout=0.1))
|
||||
|
||||
def create_window_menubar(self, parent):
|
||||
@ -152,12 +153,12 @@ class Factory(QObject):
|
||||
return ExportedMenuBar(parent, self.menu_registrar, self.bus)
|
||||
return QMenuBar(parent)
|
||||
|
||||
def create_system_tray_icon(self, parent=None, title=None, app_id=None, category=None):
|
||||
def create_system_tray_icon(self, parent=None, title=None, category=None):
|
||||
if self.has_status_notifier:
|
||||
from calibre.gui2.dbus_export.tray import StatusNotifierItem
|
||||
ans = StatusNotifierItem(parent=parent, title=title, app_id=app_id, category=category)
|
||||
self.bus.call_blocking(
|
||||
self.SERVICE, self.PATH, self.IFACE, 'RegisterStatusNotifierItem', 's', (ans.dbus_api.name,), timeout=1)
|
||||
ans = StatusNotifierItem(parent=parent, title=title, app_id=self.app_id, category=category)
|
||||
args = STATUS_NOTIFIER + ('RegisterStatusNotifierItem', 's', (ans.dbus_api.name,))
|
||||
self.bus.call_blocking(*args, timeout=1)
|
||||
return ans
|
||||
if iswindows or isosx:
|
||||
return QSystemTrayIcon(parent)
|
||||
|
Loading…
x
Reference in New Issue
Block a user