From 10c2dcb8aa15435806e3770fdc4fbe8f8979e0c0 Mon Sep 17 00:00:00 2001 From: pax Date: Fri, 10 Apr 2026 22:10:27 -0500 Subject: [PATCH] fix popout menu flash on wrong monitor and preview unsave button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - preview_pane: unsave button now checks self._is_saved instead of self._save_btn.text() == "Unsave", which stopped matching after the button text became a Unicode icon (✕ / ⤓) - popout: new _exec_menu_at_button helper uses menu.popup() + QEventLoop blocked on aboutToHide instead of menu.exec(globalPos). On Hyprland the popout gets moved via hyprctl after Qt maps it and Qt's window-position tracking stays stale, so exec(btn.mapToGlobal) resolved to a global point on the wrong monitor, flashing the menu there before the compositor corrected it. popup() routes through a different positioning path that anchors correctly. --- booru_viewer/gui/popout/window.py | 27 +++++++++++++++++++++++---- booru_viewer/gui/preview_pane.py | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/booru_viewer/gui/popout/window.py b/booru_viewer/gui/popout/window.py index 48d84df..ca4d62d 100644 --- a/booru_viewer/gui/popout/window.py +++ b/booru_viewer/gui/popout/window.py @@ -5,7 +5,7 @@ from __future__ import annotations import logging from pathlib import Path -from PySide6.QtCore import Qt, QRect, QTimer, Signal +from PySide6.QtCore import Qt, QEventLoop, QRect, QTimer, Signal from PySide6.QtGui import QPixmap from PySide6.QtWidgets import ( QHBoxLayout, QInputDialog, QLabel, QMainWindow, QMenu, QPushButton, @@ -622,6 +622,25 @@ class FullscreenPreview(QMainWindow): self._current_tags = tag_categories self._current_tag_list = tag_list + def _exec_menu_at_button(self, menu: QMenu, btn: QPushButton): + """Open a menu anchored below a button, blocking until dismissed. + + Uses popup() + QEventLoop instead of exec(pos) because on + Hyprland/Wayland the popout window gets moved via hyprctl after + Qt maps it, and Qt's window-position tracking stays stale. Using + exec(btn.mapToGlobal(...)) resolves to a global point on the + wrong monitor, causing the menu to flash there before the + compositor corrects it. popup() routes through the same path + but with triggered/aboutToHide signals we can block manually. + """ + result = [None] + menu.triggered.connect(lambda a: result.__setitem__(0, a)) + loop = QEventLoop() + menu.aboutToHide.connect(loop.quit) + menu.popup(btn.mapToGlobal(btn.rect().bottomLeft())) + loop.exec() + return result[0] + def _show_bl_tag_menu(self) -> None: menu = QMenu(self) if self._current_tags: @@ -632,7 +651,7 @@ class FullscreenPreview(QMainWindow): else: for tag in self._current_tag_list[:30]: menu.addAction(tag) - action = menu.exec(self._bl_tag_btn.mapToGlobal(self._bl_tag_btn.rect().bottomLeft())) + action = self._exec_menu_at_button(menu, self._bl_tag_btn) if action: self.blacklist_tag_requested.emit(action.text()) @@ -837,7 +856,7 @@ class FullscreenPreview(QMainWindow): folder_actions[id(a)] = folder menu.addSeparator() new_action = menu.addAction("+ New Folder...") - action = menu.exec(self._save_btn.mapToGlobal(self._save_btn.rect().bottomLeft())) + action = self._exec_menu_at_button(menu, self._save_btn) if not action: return if action == unfiled: @@ -869,7 +888,7 @@ class FullscreenPreview(QMainWindow): folder_actions[id(a)] = folder menu.addSeparator() new_action = menu.addAction("+ New Folder...") - action = menu.exec(self._bookmark_btn.mapToGlobal(self._bookmark_btn.rect().bottomLeft())) + action = self._exec_menu_at_button(menu, self._bookmark_btn) if not action: return if action == unfiled: diff --git a/booru_viewer/gui/preview_pane.py b/booru_viewer/gui/preview_pane.py index 7cf7806..bd07081 100644 --- a/booru_viewer/gui/preview_pane.py +++ b/booru_viewer/gui/preview_pane.py @@ -196,7 +196,7 @@ class ImagePreview(QWidget): self.bookmark_to_folder.emit(folder_actions[id(action)]) def _on_save_clicked(self) -> None: - if self._save_btn.text() == "Unsave": + if self._is_saved: self.unsave_requested.emit() return menu = QMenu(self)