diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 44368d77a7..c7efbd5ab3 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -172,6 +172,10 @@ class ITrayModule: if self._tray_manager: self._tray_manager.show_tray_message(title, message, icon, msecs) + def add_doubleclick_callback(self, callback): + if hasattr(self.manager, "add_doubleclick_callback"): + self.manager.add_doubleclick_callback(self, callback) + class ITrayAction(ITrayModule): """Implementation of Tray action. @@ -701,7 +705,7 @@ class TrayModulesManager(ModulesManager): ) def __init__(self): - self.log = PypeLogger().get_logger(self.__class__.__name__) + self.log = PypeLogger.get_logger(self.__class__.__name__) self.modules = [] self.modules_by_id = {} @@ -709,6 +713,28 @@ class TrayModulesManager(ModulesManager): self._report = {} self.tray_manager = None + self.doubleclick_callbacks = {} + self.doubleclick_callback = None + + def add_doubleclick_callback(self, module, callback): + """Register doubleclick callbacks on tray icon. + + Currently there is no way how to determine which is launched. Name of + callback can be defined with `doubleclick_callback` attribute. + + Missing feature how to define default callback. + """ + callback_name = "_".join([module.name, callback.__name__]) + if callback_name not in self.doubleclick_callbacks: + self.doubleclick_callbacks[callback_name] = callback + if self.doubleclick_callback is None: + self.doubleclick_callback = callback_name + return + + self.log.warning(( + "Callback with name \"{}\" is already registered." + ).format(callback_name)) + def initialize(self, tray_manager, tray_menu): self.tray_manager = tray_manager self.initialize_modules() diff --git a/openpype/modules/launcher_action.py b/openpype/modules/launcher_action.py index 5ed8585b6a..0059ff021b 100644 --- a/openpype/modules/launcher_action.py +++ b/openpype/modules/launcher_action.py @@ -15,6 +15,8 @@ class LauncherAction(PypeModule, ITrayAction): def tray_init(self): self.create_window() + self.add_doubleclick_callback(self.show_launcher) + def tray_start(self): return diff --git a/openpype/tools/tray/pype_tray.py b/openpype/tools/tray/pype_tray.py index 0272ba869b..794312f389 100644 --- a/openpype/tools/tray/pype_tray.py +++ b/openpype/tools/tray/pype_tray.py @@ -48,6 +48,18 @@ class TrayManager: self._main_thread_callbacks = collections.deque() self._execution_in_progress = None + @property + def doubleclick_callback(self): + """Doubleclick callback for Tray icon.""" + callback_name = self.modules_manager.doubleclick_callback + return self.modules_manager.doubleclick_callbacks.get(callback_name) + + def execute_doubleclick(self): + """Execute double click callback in main thread.""" + callback = self.doubleclick_callback + if callback: + self.execute_in_main_thread(callback) + def execute_in_main_thread(self, callback): self._main_thread_callbacks.append(callback) @@ -185,6 +197,8 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): :type parent: QtWidgets.QMainWindow """ + doubleclick_time_ms = 100 + def __init__(self, parent): icon = QtGui.QIcon(resources.pype_icon_filepath()) @@ -203,20 +217,50 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): self.tray_man = TrayManager(self, self.parent) self.tray_man.initialize_modules() - # Catch activate event for left click if not on MacOS - # - MacOS has this ability by design so menu would be doubled - if platform.system().lower() != "darwin": - self.activated.connect(self.on_systray_activated) # Add menu to Context of SystemTrayIcon self.setContextMenu(self.menu) atexit.register(self.exit) + # Catch activate event for left click if not on MacOS + # - MacOS has this ability by design and is harder to modify this + # behavior + if platform.system().lower() == "darwin": + return + + self.activated.connect(self.on_systray_activated) + + click_timer = QtCore.QTimer() + click_timer.setInterval(self.doubleclick_time_ms) + click_timer.timeout.connect(self._click_timer_timeout) + + self._click_timer = click_timer + self._doubleclick = False + + def _click_timer_timeout(self): + self._click_timer.stop() + doubleclick = self._doubleclick + # Reset bool value + self._doubleclick = False + if doubleclick: + self.tray_man.execute_doubleclick() + else: + self._show_context_menu() + + def _show_context_menu(self): + pos = QtGui.QCursor().pos() + self.contextMenu().popup(pos) + def on_systray_activated(self, reason): # show contextMenu if left click if reason == QtWidgets.QSystemTrayIcon.Trigger: - position = QtGui.QCursor().pos() - self.contextMenu().popup(position) + if self.tray_man.doubleclick_callback: + self._click_timer.start() + else: + self._show_context_menu() + + elif reason == QtWidgets.QSystemTrayIcon.DoubleClick: + self._doubleclick = True def exit(self): """ Exit whole application.