Skip to content

Linux Touch Input - #62

Merged
GaodaGG merged 36 commits into
mainfrom
feature/linux-touch-input
Oct 23, 2026
Merged

GaodaGG merged 36 commits into
mainfrom
feature/linux-touch-input

Conversation

@GaodaGG

@GaodaGG GaodaGG commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Cancel the shared gesture owner during window input cancellation so mouse
moves and queued resize updates cannot survive canvas detachment. Keep
native device resets scoped to touch input.

Validated the before/after behavior in an isolated KWin/XWayland window
with native mouse input and debugger-controlled canvas hiding. Confirmed
that the device-reset callback preserves mouse resizing. Desktop compilation,
UI text validation, and diff checks passed.
Extract touch tap recognition and resize execution from LinuxWindowGestures
while retaining a single gesture owner and shared mouse/touch window operations.
Keep resize coalescing, release flushing, cancellation, and tap thresholds
within the objects that own their state.

Group Linux implementation files into input, window, decoration, and x11
packages. Keep the two window frame entry points in the root package and update
callers, existing test imports, and documentation references without changing
behavior. The resulting package dependency graph is acyclic.

Validation: desktop library, existing test sources, and example classes compiled
with JBR 25.0.4.1 b583.48. The extracted implementation passed 86 resize checks
at UI scales 1 and 2 and 10 caption checks in isolated KWin/XWayland with Voxzen.
After package relocation, 43 resize checks and 4 caption checks passed again.
Diff and UI text checks passed. Physical touchscreen acceptance was not run;
previously recorded runtime limitations remain outside this refactor.
Extract contact ownership, capture, tap recognition, click suppression and
cancellation into a deterministic state machine without AWT or Compose.
Keep input conversion and explicit caption-hit replies in the dispatcher,
and inject window move, resize and focus effects while preserving their
native resource lifecycles and shared mouse/touch behavior.

Expand parameter declarations throughout the Linux package. Synchronize the
existing SheetWindowTest with close-button removal and restoration on the
native window frame clock, retaining its original assertions.

Validation: compiled desktop library and existing test sources with JBR
25.0.4.1 b583.48. Fifteen pure-state scenarios passed without java.desktop;
101 native interaction checks passed in isolated KWin/XWayland Voxzen windows,
including resize at 100% and 200% scale, caption gestures and focus.
All 177 parameterized declarations across 24 Linux files passed syntax/style
checks. Physical touchscreen acceptance remains unverified.
XI2 hover bypassed AWT modal filtering, allowing blocked owner windows to
receive synthetic mouse events and display hover feedback despite blocked clicks.

Gate native touch and hover together in LinuxWindowInput using AWT's actual
modal-blocked state. Cancel rejected input and remove the touch adapter's
separate modality rules. Resolve AWT access before selecting XI2, retaining
the complete AWT input path when the required module access is unavailable.

Validation: desktop compilation, UI text checks, and whitespace checks passed.
Verified real SaltWindow input in isolated KWin/XWayland with AWT application-
and document-modal dialogs: owner events were blocked, hover resumed after
close, modal exclusion worked, and the AWT fallback retained modal blocking.
Allow an active mouse gesture to keep receiving movement and release while
blocking new mouse gestures during a touch hold. The owning release now
finishes caption moves and commits pending resize bounds. Clear click
suppression when the corresponding click is consumed by held contacts.

Add standard desktopTest coverage for mixed mouse/touch ownership, modal
owner hover blocking, caption double-tap maximize/restore, resize
cancellation, and AWT delivery after native capabilities become unavailable.
Tests use existing input adapters and real windows without external native
input tools or Wayland-specific tests.

Validation: all 9 targeted desktopTest cases passed with no skips using
JBR 25.0.4.1 b583.48. UI text and whitespace checks passed. Adapter-injected
input tests do not verify physical touchscreen or compositor delivery.
Clear recorded mouse events in the same EDT turn as the input under test.
This prevents window setup crossings from failing the AWT fallback check
or satisfying the initial native hover assertions with stale events.

Seed a mouse-enter event before attaching the fallback source to reproduce
the CI timing case deterministically, and include received event IDs in
failed negotiation assertions.

Validation: the seeded setup event reproduced the original assertion failure
before the fix. All 9 targeted desktopTest cases then passed with no skips
on JBR 25.0.4.1 b583.48. UI text and whitespace checks passed. Remote CI has
not been rerun with this change.
Extract the bounded poll wait and connection error handling from readEvents
into pollEvents to reduce the event loop complexity flagged by CodeFactor.
Preserve EINTR retries, the 100 ms wait limit, and event-cookie cleanup.

Validation: the existing 9 targeted desktopTest cases passed without skips
on JBR 25.0.4.1 b583.48. Local Lizard analysis reports a maximum complexity
of 14 in LinuxXInputSession. UI text and whitespace checks passed.
Split captured-touch updates and first-touch gesture selection from contact
lifecycle handling. Keep mouse/touch arbitration separate from mouse phase
dispatch, gesture initiation, and click suppression to reduce the method
complexity reported by CodeFactor.

Preserve gesture ownership, release cleanup, pending resize application,
and caption double-tap behavior through the existing state interface.

Validation: all 9 targeted desktopTest cases passed without skips on JBR
25.0.4.1 b583.48. Local complexity, UI text, and whitespace checks passed.
On supported X11 window managers, defer caption touch ownership until the
drag threshold is crossed, then follow Qt's handoff order to reject the
XI2 contact and start the native window move. Prevent the window from
following the mouse after touch release while retaining the existing
fallback when native handoff is unavailable.

Let Mover own native move preparation, startup and cleanup across release,
cancellation, configuration changes and startup failures. Use raw release
events to end handed-off moves, suppress AWT touch-to-mouse replay, and
centralize AWT connection access and touch selection restoration.
Remove the compatibility overload, clarify method names by responsibility,
and update existing test callers.

Validation: production and test sources compile on JBR 25; all 9 targeted
tests passed. All 30 native input checks passed in isolated KWin X11 at
100% and 200% scaling. The later API cleanup was recompiled, and all 3
existing window tests passed after migrating the caller.
Physical touchscreens and the native Wayland toolkit remain unverified.
Keep XI2 touch and hover enabled when Window.isModalBlocked cannot be
accessed. Centralize modality checks and retain AWT's exact result when
reflection is available; otherwise use visible dialogs, owner hierarchies,
modality types and inherited modal exclusions through public AWT methods.

The fallback covers the current AppContext and conservatively blocks extra
native input for overlapping modal dialogs whose blocker order is private.

Validation: production and existing test sources compile on JBR 25.
All 9 existing Linux input tests passed both with and without java.awt
reflective access. All 13 native input checks passed in isolated KWin X11,
covering modal scopes, inherited exclusions, nested ownership and recovery
after dialogs close. Physical touchscreens and native Wayland were not tested.
- Keep the resize-edge indicator as gesture state and emit at most one
  ShowEdge per decision, so starting or finishing a resize no longer reports
  edge -> None -> edge through onResizeEdgeChange.
- Cancel native input once on the eligible-to-blocked transition instead of
  for every rejected XI2 sample while a modal dialog is open.
- Ignore XI2 slave-switch DeviceChanged events. They fire on every
  mouse/touch handoff without changing source device classes, and used to
  cost an EDT round trip and cancel an active touch drag.
Skip ComposeDialog's own semantics owner when looking for modal overlays.
This prevents native dialog content from excluding the entire caption,
while retaining hit testing for modal scenes layered above the window.

Validation: :ui2:compileKotlinDesktop; native touch dragging and modal
interior, boundary, exterior, and click checks in isolated KWin/XWayland
with Steam Runtime 4.
@GaodaGG
GaodaGG marked this pull request as ready for review October 19, 2026 07:32
@GaodaGG
GaodaGG requested a review from Moriafly October 19, 2026 07:32
Let the window manager own native restore and movement throughout a drag.
Keep AWT restore handling and pointer anchors inside LinuxFallbackWindowMover
so a resize callback cannot hand a partially restored window to the native mover.

Pass both press and current positions to native preparation. Preserve the
original caption press for maximized restore while retaining the current-contact
handoff for ordinary touch dragging. Reuse finish() for failed native mouse moves.

Validation: desktop compilation with JBR 25, 10 existing gesture/input tests,
and real SaltWindow checks with native input in isolated KWin/XWayland under
Steam Runtime 4. Covered mouse and touch, system 200% and app 150% scaling,
ordinary dragging, release, and fallback when native AWT access is unavailable.
Touch pointer emulation in dix happens at delivery time
(TouchConvertToPointerEvent), so touches only produce RawTouch* events
and never RawButtonRelease. Filtering by direct-touch devices would be a
no-op for touch and could only drop a real button release.
Add native mouse coverage for caption dragging, maximize/restore, resize
boundaries, and layered Dialog hit testing on real SaltWindow and
SaltDialogWindow instances. Verify that the topmost dialog blocks its
content, exposed captions remain draggable, and closing each overlay
restores the remaining layer's behavior.

Cover exact touch slop, reset and configuration changes, contact release
order, and stale caption replies. Give the fixture an explicit 4dp resize
region, wait for native focus and expected resize layouts, and share its
content between frame and dialog windows. Keep synthetic taps in one EDT
turn to prevent unrelated native events from splitting their samples. Add
an optional KWayland pointer helper while retaining Robot for X11 test runs.

Validation: all 27 targeted tests passed with JBR 25 under isolated
KWin/XWayland at 100% and 200% AWT scaling, with no skipped tests.
Temporary mutations of slop, caption request identity, native dialog owner
exclusion, and overlay priority were detected by the regression tests.
Physical touchscreen input and remote CI were not exercised.
A failed XI2 reader can no longer report the raw button release that ends a
native mouse move, leaving a stale mouse gesture that held an X connection
and swallowed the next non-primary press.

On spontaneous close, drop ownership of the move without sending
_NET_WM_MOVERESIZE_CANCEL: the WM still ends the drag on release, while a
cancel would restore the window's start position mid-drag. Requested stops
already cancel input, and AWT or Compose input is left running.
…nput

# Conflicts:
#	ui2/src/desktopTest/kotlin/com/moriafly/salt/ui/sheet/SheetWindowTest.kt
…ting

Openbox sends the client its new position only when an interactive move
ends, so AWT bounds stay stale while the button is held. Check the dragged
position after release instead; the later no-follow check still proves the
WM move ended.

Restoring a maximized window on move is WM policy, and Openbox keeps the
window maximized. Run the restore-anchor test only under KWin, where that
behavior was verified.
TouchDriver recomputed each event's root position from the canvas's native
screen origin, which lags AWT bounds until the WM applies an earlier move.
When Openbox caught up between touch-down and the next move, the synthetic
finger shifted by the window's offset and the drag moved too far.

Capture the screen origin at touch-down and reuse it for that contact, as a
real finger keeps its screen position while the window moves under it.
Revert the fixed per-contact screen origin from b1a0fb0. It did not change
the synthetic coordinates for multi-touch resize, yet that test failed on
both CI attempts with it and passed on both runs without it.

AWT applies the WM's position reports from the toolkit thread, so a late
report of the first move can overwrite the second move, and the native
origin that synthetic contacts use can shift between press and move. Wait
until the WM has applied the first move before the fresh press, and await
the final position instead of reading it once.
@Moriafly
Moriafly marked this pull request as draft October 22, 2026 01:11
Return the existing Modifier early when caption hit testing is unavailable.
Move region registration and cleanup out of the conditional modifier
assignment so lifecycle handling and modifier construction read in order.

This relies on the current window and dialog providers supplying caption
hit testing and gesture handling together.

Validation: desktop Kotlin compilation, UI text check, and git diff --check
passed.
@GaodaGG
GaodaGG marked this pull request as ready for review October 23, 2026 11:32
@GaodaGG
GaodaGG merged commit 47588e6 into main Oct 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants