mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-29 14:10:17 +00:00
desktop: shorten comments in hover cursor fix
This commit is contained in:
+3
-6
@@ -29,12 +29,9 @@ expect fun Modifier.desktopPointerHoverIconHand(): Modifier
|
||||
|
||||
/**
|
||||
* Directly sets the mouse cursor on desktop ([PointerIcon.Hand], [PointerIcon.Text], anything else
|
||||
* means default). Compose's pointerHoverIcon displays icons only on Enter/Exit edges or on icon
|
||||
* change while marked in-bounds — edges that are silently lost when chat items shift/recompose
|
||||
* under the cursor, leaving a stale cursor. Calling this on every hover move (and resetting on
|
||||
* exit) keeps it self-correcting. No-op on Android.
|
||||
* Verified against Compose 1.8.2, re-verify on upgrade (JetBrains/compose-multiplatform #2091,
|
||||
* #1314, #3750). Details: plans/2026-07-13-fix-command-hover-cursor.md
|
||||
* means default); no-op on Android. Compose's pointerHoverIcon is edge-triggered and silently loses
|
||||
* updates when chat items shift/recompose under the cursor; calling this on every hover move (and
|
||||
* resetting on exit) keeps the cursor correct. Details: plans/2026-07-13-fix-command-hover-cursor.md
|
||||
*/
|
||||
expect fun desktopSetHoverCursor(icon: PointerIcon)
|
||||
|
||||
|
||||
+3
-4
@@ -359,13 +359,12 @@ fun MarkdownText (
|
||||
val hand = hasAnnotation("WEB_URL") || hasAnnotation("SIMPLEX_URL") || hasAnnotation("OTHER_URL") || hasAnnotation("SIMPLEX_NAME") || hasAnnotation("SECRET") || hasAnnotation("COMMAND")
|
||||
val newIcon = if (hand) PointerIcon.Hand else PointerIcon.Text
|
||||
icon.value = newIcon
|
||||
// pointerHoverIcon alone loses updates when items shift/recompose under the cursor, see desktopSetHoverCursor
|
||||
// pointerHoverIcon alone loses updates, see desktopSetHoverCursor
|
||||
desktopSetHoverCursor(newIcon)
|
||||
},
|
||||
onHoverExit = {
|
||||
// also reset icon.value, or the pointerHoverIcon node re-displays a stale Hand on its next Enter;
|
||||
// values differ on purpose: Text is this node's neutral icon, Default is what the cursor
|
||||
// should be outside the text
|
||||
// reset icon.value too, or its node re-displays a stale Hand on next Enter;
|
||||
// Text = this node's neutral icon, Default = cursor outside the text
|
||||
icon.value = PointerIcon.Text
|
||||
desktopSetHoverCursor(PointerIcon.Default)
|
||||
},
|
||||
|
||||
+2
-3
@@ -93,14 +93,13 @@ suspend fun PointerInputScope.detectGesture(
|
||||
}
|
||||
|
||||
suspend fun PointerInputScope.detectCursorMove(onExit: () -> Unit = {}, onMove: (Offset) -> Unit = {},) {
|
||||
// Single scope: re-entering awaitPointerEventScope per event (as forEachGesture did) drops events.
|
||||
// Enter/Release matter too: a stationary cursor gets no Move when content shifts or after a click.
|
||||
// Single scope: per-event scope re-entry (old forEachGesture) drops events; Enter/Release cover stationary cursors.
|
||||
awaitPointerEventScope {
|
||||
while (true) {
|
||||
val event = awaitPointerEvent()
|
||||
if (event.type == PointerEventType.Move || event.type == PointerEventType.Enter || event.type == PointerEventType.Release) {
|
||||
val pos = event.changes[0].position
|
||||
// pressed nodes keep receiving events outside their bounds, both while held and at release
|
||||
// pressed nodes receive events outside their bounds (during drag and at release)
|
||||
if (event.changes.none { it.pressed } && pos.x >= 0 && pos.y >= 0 && pos.x < size.width && pos.y < size.height) {
|
||||
onMove(pos)
|
||||
}
|
||||
|
||||
+2
-4
@@ -88,8 +88,7 @@ actual fun Modifier.onRightClick(action: () -> Unit): Modifier = contextMenuOpen
|
||||
|
||||
actual fun Modifier.desktopPointerHoverIconHand(): Modifier = Modifier.pointerHoverIcon(PointerIcon.Hand)
|
||||
|
||||
// Runs on every mouse move, so the canvas lookup (and its failure) is cached per window;
|
||||
// weak refs avoid retaining a recreated window's scene graph.
|
||||
// hot path: canvas lookup (and its failure) cached per window, weakly to not retain a recreated window
|
||||
private var cachedSkiaCanvas: WeakReference<Component>? = null
|
||||
private var skiaCanvasMissingIn: WeakReference<Window>? = null
|
||||
|
||||
@@ -115,8 +114,7 @@ actual fun desktopSetHoverCursor(icon: PointerIcon) {
|
||||
if (canvas.cursor.type != type) canvas.cursor = Cursor.getPredefinedCursor(type)
|
||||
}
|
||||
|
||||
// Compose writes pointer icons to its skia canvas component (ComposeSceneMediator.setPointerIcon);
|
||||
// writing to the same component keeps last-write-wins consistent with the framework's own updates.
|
||||
// the same component Compose writes pointer icons to (ComposeSceneMediator.setPointerIcon)
|
||||
private fun findSkiaCanvas(c: Component): Component? = when {
|
||||
c.javaClass.name.contains("Skia") -> c
|
||||
c is Container -> c.components.firstNotNullOfOrNull { findSkiaCanvas(it) }
|
||||
|
||||
Reference in New Issue
Block a user