It looks like `Modifier.onClick` triggers not only...
# compose-desktop
m
It looks like
Modifier.onClick
triggers not only for left clicks, but also for right clicks, even though
PointerMatcher.Primary
is used. Am I missing something about how the PointerMatcher works or is this a bug?
a
Works fine for me
Copy code
@OptIn(ExperimentalFoundationApi::class)
fun main() = singleWindowApplication {
    var clickCount by remember { mutableStateOf(0) }
    Box(
        Modifier
            .fillMaxSize()
            .background(if (clickCount.mod(2) == 1) Color.Red else Color.Green)
            .onClick {
                clickCount += 1
            }
    )
}
m
Your example indeed works correctly for me, but I see different behavior in my actual app. I'll try to isolate what makes it different.
This is very weird, every time I see this happening (onClick triggers for right clicks), I try to isolate the issue, eventually I simplify the code enough it stops happening, but then going back it doesn't happen anymore in the full app, with no changes. Until another day when it starts again.
I would think this is something on my computer, but I get the same reports from users. It just randomly starts happening until it doesn't anymore.
a
Any chance they’re ctrl-clicking on macOS?
err, no, never mind
that would be the other way around
m
Users on Windows are reporting it, and I'm testing on Linux and see the same thing. Really annoying to debug because it just fixes itself by itself with no code changes until something triggers that behavior again.
@Alexander Maryanovsky I managed to reproduce it. It's triggered by the presence, somewhere else, of the
onDrag
Modifier that matches both mouse buttons. Here is your example with the bug:
Copy code
@OptIn(ExperimentalFoundationApi::class)
fun main() = singleWindowApplication {
    var clickCount by remember { mutableStateOf(0) }
    Column(
        modifier = Modifier.fillMaxSize()
    ) {
        Box(
            Modifier
                .fillMaxWidth()
                .weight(1f)
                .background(if (clickCount.mod(2) == 1) Color.Red else Color.Green)
                .onClick {
                    clickCount += 1
                }
        )
        Spacer(Modifier.height(100.dp))
        Box(
            modifier = Modifier.onDrag(matcher = PointerMatcher.Primary + PointerMatcher.mouse(PointerButton.Secondary)) {}
        ) {
            Text("Drag")
        }
    }
}
The
onDrag
is on an unrelated element. In my actual application it was in a different
Window
which is why it felt so random: it was only happening when the other, unrelated application window was open at the same time. It also seems to happen only if the
onDrag
matches both mouse buttons. If I change the matcher to only Primary or only Secondary, it's fine.
a
Looking into it
Ok, I’ll fix it
In the meantime, don’t use
PointerMatcher.Primary + …
Use, for example
Copy code
fun PointerMatcher.Companion.Primary() = mouse(PointerButton.Primary) + touch + stylus + eraser
and then
Copy code
PointerMatcher.Primary() + ...
m
Great, thank you.
Hmm, I actually can't get dragging working that way. Works:
Copy code
onDrag(matcher = PointerMatcher.Primary)
Doesn't work:
Copy code
onDrag(matcher = PointerMatcher.mouse(PointerButton.Primary) + PointerMatcher.touch + PointerMatcher.stylus + PointerMatcher.eraser)
Even though the second version is exactly what
PointerMatcher.Primary
is.
a
Weird. Try `remember`ing it maybe?
m
That's it, works after remembering, thanks.
a
Can you give me a reproducer where it doesn’t work? It worked for me…
Copy code
@OptIn(ExperimentalFoundationApi::class)
fun main() = singleWindowApplication {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .onDrag(
                matcher = PointerMatcher.mouse(PointerButton.Primary) +
                    PointerMatcher.touch +
                    PointerMatcher.stylus +
                    PointerMatcher.eraser +
                    PointerMatcher.mouse(PointerButton.Secondary),
                onDrag = {
                    println("Dragged $it")
                }
            )
    ) {
        Text("Drag")
    }
}
Because there’s no reason you’d have to remember the matcher (other than to avoid recreating on every recomposition, of course).
m
This is as far as I could go:
Copy code
@OptIn(ExperimentalFoundationApi::class)
fun main() = singleWindowApplication {
    var center by remember { mutableStateOf(Offset.Zero) }
    val springSpec = remember { spring<Offset>() }
    val snapSpec = remember { snap<Offset>() }
    var spec by remember { mutableStateOf<AnimationSpec<Offset>>(springSpec) }
    val animatedCenter by animateOffsetAsState(Offset(center.x, center.y), spec)
    Box(
        modifier = Modifier
            .fillMaxSize()
            .onDrag(matcher = PointerMatcher.mouse(PointerButton.Primary)) {
                println("Dragged: $it")
                spec = snapSpec
                center = center.copy()
            }
    ) {}
}
Only prints "Dragged" once or a few times before stopping. If you use
matcher = PointerMatcher.Primary
, or
remember
the
PointerMatcher.mouse(PointerButton.Primary)
, it works fine. Removing any of the two setters in the
onDrag
makes it work again as well. Removing the unused
animatedCenter
makes it work again too, but with all of it together it has the issue.
a
Yeah, looks like there’s a bug there too. We’re restarting
detectDragGestures
whenever the matcher changes.
m
Glad to help. 😄 I'm not too familiar with the release process, with your PR merged, when would the change normally be expected to be available in a new Compose Desktop version? And same for my skiko PR: https://github.com/JetBrains/skiko/pull/799 Not in a hurry at all, just wanted to know.
a
We publish dev builds every few days. A stable version is expected in about a month, if I’m not mistaken.