diff --git a/src/calibre/gui2/dbus_export/demo.py b/src/calibre/gui2/dbus_export/demo.py index 45677f8d63..5e8f18120a 100644 --- a/src/calibre/gui2/dbus_export/demo.py +++ b/src/calibre/gui2/dbus_export/demo.py @@ -10,7 +10,7 @@ import time from PyQt5.Qt import ( QApplication, QMainWindow, QVBoxLayout, Qt, QKeySequence, QAction, - QActionGroup, QMenu, QPushButton, QWidget, QTimer) + QActionGroup, QMenu, QPushButton, QWidget, QTimer, QMessageBox, pyqtSignal) from calibre.gui2.dbus_export.utils import setup_for_cli_run from calibre.gui2.dbus_export.widgets import factory @@ -22,6 +22,9 @@ def make_checkable(ac, checked=True): class MainWindow(QMainWindow): + window_blocked = pyqtSignal() + window_unblocked = pyqtSignal() + def __init__(self): QMainWindow.__init__(self) f = factory() @@ -84,6 +87,8 @@ class MainWindow(QMainWindow): b.clicked.connect(self.add_menu), l.addWidget(b) self.rb = b = QPushButton('Remove a created menu') b.clicked.connect(self.remove_menu), l.addWidget(b) + self.sd = b = QPushButton('Show modal dialog') + b.clicked.connect(self.show_dialog), l.addWidget(b) print ('DBUS connection unique name:', f.bus.get_unique_name()) def update_tooltip(self): @@ -143,6 +148,17 @@ class MainWindow(QMainWindow): def about_to_show_two(self): self.menu_two.addAction('Action added by about to show') + def show_dialog(self): + QMessageBox.information(self, 'A test dialog', 'While this dialog is shown, the global menu should be hidden') + + def event(self, ev): + if ev.type() in (ev.WindowBlocked, ev.WindowUnblocked): + if ev.type() == ev.WindowBlocked: + self.window_blocked.emit() + else: + self.window_unblocked.emit() + return QMainWindow.event(self, ev) + app=QApplication([]) app.setAttribute(Qt.AA_DontUseNativeMenuBar, False) app.setApplicationName('com.calibre-ebook.DBusExportDemo') diff --git a/src/calibre/gui2/dbus_export/menu.py b/src/calibre/gui2/dbus_export/menu.py index a2a3f3757d..1ee6054a9c 100644 --- a/src/calibre/gui2/dbus_export/menu.py +++ b/src/calibre/gui2/dbus_export/menu.py @@ -34,7 +34,7 @@ def create_properties_for_action(ac, previous=None): ans['label'] = swap_mnemonic_char(text) if not ac.isEnabled(): ans['enabled'] = False - if not ac.isVisible(): + if not ac.isVisible() or ac.property('blocked') is True: ans['visible'] = False if ac.menu() is not None: ans['children-display'] = 'submenu' @@ -124,6 +124,22 @@ class DBusMenu(QObject): self.add_action(ac) self.dbus_api.LayoutUpdated(self.dbus_api.revision, 0) + def set_visible(self, visible): + ac = self.id_to_action(0) + if ac is not None and self.qmenu is not None: + changed = False + blocked = not visible + for ac in ac.menu().actions(): + ac_id = self.action_to_id(ac) + if ac_id is not None: + old = ac.property('blocked') + if old is not blocked: + ac.setProperty('blocked', blocked) + self.action_changes.add(ac_id) + changed = True + if changed: + self.action_changed_timer.start() + def add_action(self, ac): ac_id = 0 if ac.menu() is self.qmenu else self.next_id self._id_to_action[ac_id] = ac diff --git a/src/calibre/gui2/dbus_export/widgets.py b/src/calibre/gui2/dbus_export/widgets.py index 827454e346..c474289bc7 100644 --- a/src/calibre/gui2/dbus_export/widgets.py +++ b/src/calibre/gui2/dbus_export/widgets.py @@ -37,6 +37,8 @@ class ExportedMenuBar(QMenuBar): global menu_counter if not parent.isWindow(): raise ValueError('You must supply a top level window widget as the parent for an exported menu bar') + self._blocked = False + self.is_visible = True QMenuBar.__init__(self, parent) QMenuBar.setVisible(self, False) self.menu_action = MenuBarAction(self) @@ -51,6 +53,10 @@ class ExportedMenuBar(QMenuBar): self.dbus_menu.publish_new_menu(self) self.register() parent.installEventFilter(self) + # See https://bugreports.qt-project.org/browse/QTBUG-42281 + if hasattr(parent, 'window_blocked'): + parent.window_blocked.connect(self._block) + parent.window_unblocked.connect(self._unblock) def register(self): wid = self.parent().effectiveWinId() @@ -66,16 +72,38 @@ class ExportedMenuBar(QMenuBar): self.bus.call_blocking(*args) def setVisible(self, visible): - pass # no-op + self.is_visible = visible + self.dbus_menu.set_visible(self.is_visible and not self._blocked) def isVisible(self): - return True + return self.is_visible + + def show(self): + self.setVisible(True) + + def hide(self): + self.setVisible(False) def menuAction(self): return self.menu_action + def _block(self): + self._blocked = True + self.setVisible(self.is_visible) + + def _unblock(self): + self._blocked = False + self.setVisible(self.is_visible) + def eventFilter(self, obj, ev): etype = ev.type() + # WindowBlocked and WindowUnblocked aren't delivered to event filters, + # so we have to rely on co-operation from the mainwindow class + # See https://bugreports.qt-project.org/browse/QTBUG-42281 + # if etype == QEvent.WindowBlocked: + # self._block() + # elif etype == QEvent.WindowUnblocked: + # self._unblock() if etype == QEvent.WinIdChange: self.unregister() self.register()