I’ve been working on a clone of oneko for KWin, which involves creating an always-on-top QML window. Though, when the window “runs” under the cursor, it steals the mouse input: for example, if I’m scrolling and the cat runs by, scrolling abruptly stops.
I assumed WindowTransparentForInput or WindowDoesNotAcceptFocuswould do the trick, but neither seem to affect how mouse inputs are treated.
Is there something else I need to do, or is this a limitation of KWin (or Qt)? I was wondering if this was a security concern in the vein of clickjacking, but I didn’t find anything in the KWin sources.
Aha, I think I figured something out. Unfortunately in working this out, I’ve found this isn’t quite what I need. But curiosity got the better of me, so I hope it helps someone!
In the KWin sources, InternalWindow::hitTest() (of which a KWin declarative script is an instance of) checks for one of the following, on top of the standard window hit test:
If the QWindow mask is set, whether the cursor is outside the given mask[1]
Whether the flag Qt::WindowTransparentForInput is set
Whether the QWindow property outputOnly is truthy
If any of those cases are true, the input is ignored and passed to the lower window. And while technically the last one is deprecated and meant for use with org.kde.plasma.core.Dialog, you can use it on any old window:
That said, I imagine setting Qt.WindowTransparentForInput is the more correct way of tackling this. So why doesn’t it seem to work here?
Edit: My theory was wrong, it was just an issue of looking at code for the wrong version.
I’m not clear on how a QQuickWindow becomes an InternalWindow, so this is a bit of a wild guess. I’m wondering if the window flags are somehow populated in InternalWindow::m_handle after it’s constructed, and since there’s nothing listening for QWindow::setFlags(), that state never gets updated. If that’s the case, I’d assume this less feature and more bug. But I haven’t tested that hypothesis yet.
This is actually what I want, but I don’t think it can be set via QML. If there’s a workaround, please let me know! ↩︎
Oh yep, and there it is (diff between v6.6.5 and v6.6.90). Thank you!
diff --git a/src/internalwindow.cpp b/src/internalwindow.cpp
index c03d03696b..0b1322aa1b 100644
--- a/src/internalwindow.cpp
+++ b/src/internalwindow.cpp
@@ -76,7 +76,9 @@ bool InternalWindow::hitTest(const QPointF &point) const
const QRegion mask = m_handle->mask();
if (!mask.isEmpty() && !mask.contains(mapToLocal(point).toPoint())) {
return false;
- } else if (m_handle->property("outputOnly").toBool()) {
+ } else if (m_internalWindowFlags.testFlag(Qt::WindowTransparentForInput)) {
+ return false;
+ } else if (m_handle->property("outputOnly").toBool()) { // from Dialog, this is being deprecated in Plasma but still used by lots of kwin scripts
return false;
}
For why I was avoiding outputOnly, this comment from the InternalWindow definition was what made me hesitant:
// from Dialog, this is being deprecated in Plasma but still used by lots of kwin scripts
I guess the deprecation is new, but I’d rather avoid relying on it if there’s a preferred way to handle it.