mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 10:56:10 +00:00
Stop the indicator from swallowing clicks in its corner
WA_TransparentForMouseEvents does nothing for a top-level window: Qt takes the click and then drops it, so it still never reaches whatever is underneath. Since the window stays mapped while idle, that turned its corner of the screen into a dead zone for good. Qt::WindowTransparentForInput is the one that leaves the window without an input region at all. The dismissable one has to keep taking clicks, and the flag is read once when the window is created, so it shrinks to a point while concealed instead. Resizing keeps the surface alive, which is the whole reason concealing does not simply hide it.
This commit is contained in:
+20
-5
@@ -65,16 +65,23 @@ class Overlay(QWidget):
|
||||
# It is the window manager that would otherwise move this out of
|
||||
# the corner. macOS has no such hint, and Qt warns about it.
|
||||
flags |= Qt.WindowType.X11BypassWindowManagerHint
|
||||
self.setWindowFlags(flags)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_ShowWithoutActivating)
|
||||
# One that can be clicked away has to receive the click, which means it
|
||||
# also swallows one aimed at whatever is underneath it. The rest stay
|
||||
# transparent to the mouse, as an indicator should be.
|
||||
# transparent to the mouse, as an indicator should be. It has to be this
|
||||
# flag and not WA_TransparentForMouseEvents: on a top-level window the
|
||||
# attribute only makes Qt drop the event it already took, so the click
|
||||
# never reaches the window below. The flag is the one that tells the
|
||||
# display server the window has no input region at all. It is read when
|
||||
# the window is created and cannot be turned off later without the
|
||||
# window being torn down and built again, which is why the dismissable
|
||||
# one has to shrink itself instead (see _conceal).
|
||||
if dismissable:
|
||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
else:
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
|
||||
flags |= Qt.WindowType.WindowTransparentForInput
|
||||
self.setWindowFlags(flags)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_ShowWithoutActivating)
|
||||
self.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
self.resize(MIN_WIDTH, HEIGHT)
|
||||
|
||||
@@ -190,11 +197,19 @@ class Overlay(QWidget):
|
||||
to be a real repaint, not just zero opacity: with the animation stopped
|
||||
nothing else damages the surface, and the stale frame would sit on the
|
||||
screen until some other event made the compositor redraw it.
|
||||
|
||||
A window that stays mapped also stays clickable, though, and the one
|
||||
that can be dismissed is the one that takes clicks. Left at full size it
|
||||
would turn its corner of the screen into a dead zone long after there
|
||||
was anything to see there, so it shrinks to a point. Resizing keeps the
|
||||
surface alive, unlike hiding it.
|
||||
"""
|
||||
self._anim.stop()
|
||||
self.state = "hidden"
|
||||
self._concealed = True
|
||||
self.repaint()
|
||||
if self.dismissable:
|
||||
self.resize(1, 1)
|
||||
|
||||
def _resize_to_content(self):
|
||||
if self.state in LIVE:
|
||||
|
||||
@@ -355,6 +355,25 @@ class Overlay(DikteTest):
|
||||
self.assertTrue(flags & Qt.WindowType.WindowDoesNotAcceptFocus)
|
||||
self.assertTrue(flags & Qt.WindowType.WindowStaysOnTopHint)
|
||||
|
||||
def test_it_lets_a_click_through_to_whatever_is_under_it(self):
|
||||
"""It stays mapped while idle, so without this its corner of the screen
|
||||
would stop taking clicks for good. The widget attribute is not enough:
|
||||
on a top-level window it only makes Qt drop the event it already took."""
|
||||
from PyQt6.QtCore import Qt
|
||||
flags = self.overlay().windowFlags()
|
||||
self.assertTrue(flags & Qt.WindowType.WindowTransparentForInput)
|
||||
|
||||
def test_the_one_that_takes_clicks_shrinks_out_of_the_way(self):
|
||||
"""It has to stay clickable, so it cannot be transparent to input; it
|
||||
gets out of the way by leaving nothing there to click instead."""
|
||||
widget = self.overlay(dismissable=True)
|
||||
widget.show_busy("Asking Claude…")
|
||||
self.assertGreater(widget.width(), 1)
|
||||
widget.dismiss()
|
||||
self.assertEqual((widget.width(), widget.height()), (1, 1))
|
||||
widget.show_busy("Asking Claude…")
|
||||
self.assertGreater(widget.width(), 1)
|
||||
|
||||
def test_recording_then_working_then_done(self):
|
||||
widget = self.overlay()
|
||||
widget.show_recording()
|
||||
|
||||
Reference in New Issue
Block a user