mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Notes on GmenuModel based DBus menus
This commit is contained in:
parent
4c82321f66
commit
065017ba25
@ -9,7 +9,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
# Demo program to explore the GTK DBus interface, which is only partially documented
|
||||
# at https://wiki.gnome.org/Projects/GLib/GApplication/DBusAPI
|
||||
|
||||
import sys, dbus, struct
|
||||
import sys, dbus, struct, time, signal
|
||||
from threading import Thread
|
||||
from pprint import pformat
|
||||
|
||||
@ -37,6 +37,11 @@ UI_INFO = """
|
||||
<menuitem action='ChoiceTwo'/>
|
||||
<separator />
|
||||
<menuitem action='ChoiceThree'/>
|
||||
<separator />
|
||||
<menuitem action='DisabledAction'/>
|
||||
<menuitem action='InvisibleAction'/>
|
||||
<menuitem action='TooltipAction'/>
|
||||
<menuitem action='IconAction'/>
|
||||
</menu>
|
||||
</menubar>
|
||||
<toolbar name='ToolBar'>
|
||||
@ -93,6 +98,12 @@ class MenuExampleWindow(Gtk.ApplicationWindow):
|
||||
self.popup = uimanager.get_widget("/PopupMenu")
|
||||
|
||||
self.add(box)
|
||||
i = Gtk.Image.new_from_stock(Gtk.STOCK_OK, Gtk.IconSize.MENU)
|
||||
# Currently the menu items image is not exported over DBus, so probably
|
||||
# best to stick with using dbusmenu
|
||||
uimanager.get_widget('/MenuBar/ChoicesMenu/IconAction')
|
||||
uimanager.get_widget('/MenuBar/ChoicesMenu/IconAction').set_image(i)
|
||||
uimanager.get_widget('/MenuBar/ChoicesMenu/IconAction').set_always_show_image(True)
|
||||
|
||||
def add_file_menu_actions(self, action_group):
|
||||
action_filemenu = Gtk.Action("FileMenu", "File", None, None)
|
||||
@ -140,6 +151,15 @@ class MenuExampleWindow(Gtk.ApplicationWindow):
|
||||
three = Gtk.ToggleAction("ChoiceThree", "Three", None, None)
|
||||
three.connect("toggled", self.on_menu_choices_toggled)
|
||||
action_group.add_action(three)
|
||||
ad = Gtk.Action('DisabledAction', 'Disabled Action', None, None)
|
||||
ad.set_sensitive(False)
|
||||
action_group.add_action(ad)
|
||||
ia = Gtk.Action('InvisibleAction', 'Invisible Action', None, None)
|
||||
ia.set_visible(False)
|
||||
action_group.add_action(ia)
|
||||
ta = Gtk.Action('TooltipAction', 'Tooltip Action', 'A tooltip', None)
|
||||
action_group.add_action(ta)
|
||||
action_group.add_action(Gtk.Action('IconAction', 'Icon Action', None, None))
|
||||
|
||||
def create_ui_manager(self):
|
||||
uimanager = Gtk.UIManager()
|
||||
@ -263,6 +283,7 @@ class MyApplication(Gtk.Application):
|
||||
|
||||
def print_dbus_data(self):
|
||||
bus = dbus.SessionBus()
|
||||
time.sleep(0.5)
|
||||
self.data = []
|
||||
self.get_actions_description(bus)
|
||||
self.print_menu_start(bus)
|
||||
@ -273,7 +294,9 @@ class MyApplication(Gtk.Application):
|
||||
print = self.print
|
||||
print('\nActions description')
|
||||
self.actions_desc = d = {}
|
||||
for name, data in bus.call_blocking(self.bus_name, self.object_path, 'org.gtk.Actions', 'DescribeAll', '', ()).iteritems():
|
||||
adata = bus.call_blocking(self.bus_name, self.object_path, 'org.gtk.Actions', 'DescribeAll', '', ())
|
||||
for name in sorted(adata):
|
||||
data = adata[name]
|
||||
d[name] = {'enabled':convert(data[0]), 'param type': convert(data[1]), 'state':convert(data[2])}
|
||||
print ('Name:', name)
|
||||
print (pformat(d[name]))
|
||||
@ -282,4 +305,5 @@ class MyApplication(Gtk.Application):
|
||||
Gtk.Application.do_startup(self)
|
||||
|
||||
app = MyApplication(application_id='com.calibre-ebook.test-gtk')
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
sys.exit(app.run(sys.argv))
|
||||
|
64
src/calibre/gui2/dbus_export/menu2.py
Normal file
64
src/calibre/gui2/dbus_export/menu2.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!/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 <kovid at kovidgoyal.net>'
|
||||
|
||||
# A implementation of the GMenuModel export of menus/actions on DBus.
|
||||
# GMenuModel is pretty bad, does not support icons, for instance, so I have not
|
||||
# bothered to complete it. See gtk.py for an exmaple app that creates a
|
||||
# GMenuModel menu.
|
||||
#
|
||||
# Partial spec: https://wiki.gnome.org/Projects/GLib/GApplication/DBusAPI
|
||||
|
||||
import dbus
|
||||
from PyQt5.Qt import QObject, pyqtSignal, QTimer, Qt
|
||||
|
||||
from calibre.utils.dbus_service import Object, method as dbus_method, signal as dbus_signal
|
||||
from calibre.gui2.dbus_export.utils import set_X_window_properties
|
||||
|
||||
def add_window_properties_for_menu(widget, object_path, bus):
|
||||
op = unicode(object_path)
|
||||
set_X_window_properties(widget.effectiveWinId(), _UNITY_OBJECT_PATH=op, _GTK_UNIQUE_BUS_NAME=unicode(bus.get_unique_name()), _GTK_MENUBAR_OBJECT_PATH=op)
|
||||
|
||||
|
||||
class DBusMenu(QObject):
|
||||
|
||||
handle_event_signal = pyqtSignal(object, object, object, object)
|
||||
|
||||
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, bus=bus)
|
||||
self.set_status = self.dbus_api.set_status
|
||||
self._next_id = 0
|
||||
self.action_changed_timer = t = QTimer(self)
|
||||
t.setInterval(0), t.setSingleShot(True), t.timeout.connect(self.actions_changed)
|
||||
self.layout_changed_timer = t = QTimer(self)
|
||||
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
|
||||
|
||||
|
||||
class DBusMenuAPI(Object):
|
||||
|
||||
ACTIONS_IFACE = 'org.gtk.Actions'
|
||||
|
||||
def __init__(self, menu, object_path, bus=None):
|
||||
if bus is None:
|
||||
bus = dbus.SessionBus()
|
||||
Object.__init__(self, bus, object_path)
|
||||
self.status = 'normal'
|
||||
self.menu = menu
|
||||
self.revision = 0
|
||||
|
||||
dbus_method, dbus_signal
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user