Skip to content

Native Windows port: wheel scrolling, shell launch services, native file picker#5209

Open
shai-almog wants to merge 6 commits into
masterfrom
win32-port-gaps
Open

Native Windows port: wheel scrolling, shell launch services, native file picker#5209
shai-almog wants to merge 6 commits into
masterfrom
win32-port-gaps

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Works through the actionable gaps tracked in Ports/WindowsPort/status.md for the new native Win32/Direct2D port.

Mouse wheel scrolling — gap 1b (now a shared core API)

Rather than the per-port synthetic-event hack, the wheel→scroll mapping now lives once in core:

  • CodenameOneImplementation.pointerWheelMoved(x, y, scrollX, scrollY) replays the wheel as a press → drag → release gesture spread over four EDT cycles (so CN1's own tensile/deceleration animates it), temporarily makes the component under the cursor non-focusable so the synthetic press isn't a click, and owns the scrollWheeling / isScrollWheeling() state.
  • JavaSE (which carried the original inline implementation) is refactored onto this method, so every desktop port maps the wheel identically.
  • Windows: WndProc pushes WM_MOUSEWHEEL/WM_MOUSEHWHEEL into the input ring (new CN1_EVENT_MOUSE_WHEEL/_HWHEEL); drainInput converts the delta to a DPI-scaled distance and calls the shared method.

Shell launch services — gap 4

A native shellOpen() (ShellExecuteW) backs honest desktop implementations of execute(url), dial() (tel:), sendSMS() (sms:?body=, so getSMSSupport() reports SMS_INTERACTIVE) and sendMessage() (mailto:?subject=&body=). Nothing is fabricated — an absent handler reports failure.

Native file picker — gap 4

GetOpenFileNameW (comdlg32) run modally on the window-owning pump thread via a blocking WM_CN1_FILEDIALOG SendMessage, filtered by media type. openGallery / openImageGallery now use the real OS picker and return a file:// path FileSystemStorage opens, instead of the in-app FileTree fallback. comdlg32 + shell32 added to the Windows link set.

Honesty preserved

status.md is updated to move these gaps to "done" while keeping the remaining hardware/OS-account capabilities (camera, sensors, location, contacts, push, biometric, audio recording, SIMD) honestly unsupported — they return null/no-op/false rather than fabricating data, per the port's guiding rule.

Validation

  • core, javase and windows Maven modules compile cleanly (the shared pointerWheelMoved API links across modules).
  • Native additions are pure Win32 (ShellExecuteW, GetOpenFileNameW) / input-ring wiring; the gallery/file-dialog path is not exercised headlessly, so it cannot affect the screenshot suite, and falls back gracefully.
  • CI: windows-cross-compile (Linux PE link) + parparvm-tests-windows (clean-target build/run + screenshot suite) are the gates.

🤖 Generated with Claude Code

shai-almog and others added 2 commits June 9, 2026 22:28
Closes the most actionable gaps in Ports/WindowsPort/status.md.

Mouse wheel (gap 1b) is now a proper shared API instead of a per-port hack:
CodenameOneImplementation.pointerWheelMoved(x, y, scrollX, scrollY) owns the
synthetic press/drag/release scroll gesture (spread over four EDT cycles, with
the component under the cursor temporarily made non-focusable) and the
scrollWheeling / isScrollWheeling() state. The JavaSE port, which carried the
original inline implementation, is refactored onto it so every desktop port maps
the wheel identically. The Windows WndProc pushes WM_MOUSEWHEEL / WM_MOUSEHWHEEL
into the input ring (new CN1_EVENT_MOUSE_WHEEL/_HWHEEL) and drainInput converts
the delta to a DPI-scaled distance.

Shell launch services (gap 4): a native shellOpen() (ShellExecuteW) backs honest
desktop implementations of execute(url), dial() (tel:), sendSMS() (sms:, so
getSMSSupport() reports SMS_INTERACTIVE) and sendMessage() (mailto:). Nothing is
fabricated -- an absent handler reports failure.

Native file picker (gap 4): GetOpenFileNameW (comdlg32) run modally on the
window-owning pump thread via a blocking WM_CN1_FILEDIALOG SendMessage, filtered
by media type. openGallery / openImageGallery now use the real OS picker and
return a file:// path FileSystemStorage opens, instead of the in-app FileTree
fallback. comdlg32 + shell32 added to the Windows link set.

status.md updated: these gaps move to "done"; the remaining hardware/OS-account
capabilities (camera, sensors, location, contacts, push, biometric, audio
recording, SIMD) stay honestly unsupported.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WIN32_LEAN_AND_MEAN keeps shellapi.h out of windows.h and shlobj.h does not
pull it in under clang-cl, so ShellExecuteW was an implicit declaration and the
clean-target build failed (call to undeclared function / int->HINSTANCE). Add
the explicit include.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 387 total, 0 failed, 11 skipped

Benchmark Results

  • Execution Time: 21966 ms

  • Hotspots (Top 20 sampled methods):

    • 22.23% java.lang.String.indexOf (556 samples)
    • 17.23% java.util.ArrayList.indexOf (431 samples)
    • 16.07% com.codename1.tools.translator.Parser.isMethodUsed (402 samples)
    • 4.52% com.codename1.tools.translator.ByteCodeClass.markDependent (113 samples)
    • 3.36% com.codename1.tools.translator.BytecodeMethod.appendMethodSignatureSuffixFromDesc (84 samples)
    • 3.16% com.codename1.tools.translator.Parser.addToConstantPool (79 samples)
    • 2.08% com.codename1.tools.translator.ByteCodeClass.updateAllDependencies (52 samples)
    • 1.84% java.lang.StringBuilder.append (46 samples)
    • 1.76% com.codename1.tools.translator.ByteCodeClass.calcUsedByNative (44 samples)
    • 1.40% com.codename1.tools.translator.Parser.generateClassAndMethodIndexHeader (35 samples)
    • 1.40% org.objectweb.asm.ClassReader.readCode (35 samples)
    • 1.24% java.lang.Object.hashCode (31 samples)
    • 1.00% com.codename1.tools.translator.BytecodeMethod.optimize (25 samples)
    • 0.96% com.codename1.tools.translator.BytecodeMethod.addInstruction (24 samples)
    • 0.76% java.util.TreeMap.getEntry (19 samples)
    • 0.68% com.codename1.tools.translator.bytecodes.Invoke.addDependencies (17 samples)
    • 0.64% com.codename1.tools.translator.Parser.cullMethods (16 samples)
    • 0.64% com.codename1.tools.translator.BytecodeMethod.appendCMethodPrefix (16 samples)
    • 0.60% sun.nio.fs.UnixNativeDispatcher.open0 (15 samples)
    • 0.56% java.io.UnixFileSystem.getBooleanAttributes0 (14 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.

Native Android coverage

  • 📊 Line coverage: 14.21% (8613/60613 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.50% (42483/369369), branch 5.02% (1742/34685), complexity 6.05% (2012/33271), method 10.48% (1631/15567), class 17.19% (377/2193)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 14.21% (8613/60613 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.50% (42483/369369), branch 5.02% (1742/34685), complexity 6.05% (2012/33271), method 10.48% (1631/15567), class 17.19% (377/2193)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 997.000 ms
Base64 CN1 encode 173.000 ms
Base64 encode ratio (CN1/native) 0.174x (82.6% faster)
Base64 native decode 875.000 ms
Base64 CN1 decode 219.000 ms
Base64 decode ratio (CN1/native) 0.250x (75.0% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Native Windows port

Compared 124 screenshots: 123 matched, 1 updated.

  • StatusBarTapDiagnosticScreenshotTest — updated screenshot. Screenshot differs (784x561 px, bit depth 8).

    StatusBarTapDiagnosticScreenshotTest
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as StatusBarTapDiagnosticScreenshotTest.png in workflow artifacts.

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 11 screenshots: 11 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

PMD's MissingOverride rule is enforced on core; the four anonymous Runnable
run() methods added for the shared wheel-scroll gesture need the annotation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 112 seconds

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 857.000 ms
Base64 CN1 encode 1590.000 ms
Base64 encode ratio (CN1/native) 1.855x (85.5% slower)
Base64 native decode 478.000 ms
Base64 CN1 decode 1141.000 ms
Base64 decode ratio (CN1/native) 2.387x (138.7% slower)
Base64 SIMD encode 529.000 ms
Base64 encode ratio (SIMD/native) 0.617x (38.3% faster)
Base64 encode ratio (SIMD/CN1) 0.333x (66.7% faster)
Base64 SIMD decode 495.000 ms
Base64 decode ratio (SIMD/native) 1.036x (3.6% slower)
Base64 decode ratio (SIMD/CN1) 0.434x (56.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 71.000 ms
Image createMask (SIMD on) 12.000 ms
Image createMask ratio (SIMD on/off) 0.169x (83.1% faster)
Image applyMask (SIMD off) 233.000 ms
Image applyMask (SIMD on) 92.000 ms
Image applyMask ratio (SIMD on/off) 0.395x (60.5% faster)
Image modifyAlpha (SIMD off) 172.000 ms
Image modifyAlpha (SIMD on) 75.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.436x (56.4% faster)
Image modifyAlpha removeColor (SIMD off) 193.000 ms
Image modifyAlpha removeColor (SIMD on) 95.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.492x (50.8% faster)
Image PNG encode (SIMD off) 1348.000 ms
Image PNG encode (SIMD on) 1168.000 ms
Image PNG encode ratio (SIMD on/off) 0.866x (13.4% faster)
Image JPEG encode 634.000 ms

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 121 screenshots: 121 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 124 screenshots: 124 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 210 seconds

Build and Run Timing

Metric Duration
Simulator Boot 93000 ms
Simulator Boot (Run) 1000 ms
App Install 22000 ms
App Launch 6000 ms
Test Execution 354000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1108.000 ms
Base64 CN1 encode 1681.000 ms
Base64 encode ratio (CN1/native) 1.517x (51.7% slower)
Base64 native decode 373.000 ms
Base64 CN1 decode 1438.000 ms
Base64 decode ratio (CN1/native) 3.855x (285.5% slower)
Base64 SIMD encode 486.000 ms
Base64 encode ratio (SIMD/native) 0.439x (56.1% faster)
Base64 encode ratio (SIMD/CN1) 0.289x (71.1% faster)
Base64 SIMD decode 593.000 ms
Base64 decode ratio (SIMD/native) 1.590x (59.0% slower)
Base64 decode ratio (SIMD/CN1) 0.412x (58.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 80.000 ms
Image createMask (SIMD on) 51.000 ms
Image createMask ratio (SIMD on/off) 0.638x (36.3% faster)
Image applyMask (SIMD off) 182.000 ms
Image applyMask (SIMD on) 70.000 ms
Image applyMask ratio (SIMD on/off) 0.385x (61.5% faster)
Image modifyAlpha (SIMD off) 188.000 ms
Image modifyAlpha (SIMD on) 85.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.452x (54.8% faster)
Image modifyAlpha removeColor (SIMD off) 307.000 ms
Image modifyAlpha removeColor (SIMD on) 424.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.381x (38.1% slower)
Image PNG encode (SIMD off) 1665.000 ms
Image PNG encode (SIMD on) 1437.000 ms
Image PNG encode ratio (SIMD on/off) 0.863x (13.7% faster)
Image JPEG encode 904.000 ms

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 184 seconds

Build and Run Timing

Metric Duration
Simulator Boot 60000 ms
Simulator Boot (Run) 0 ms
App Install 12000 ms
App Launch 5000 ms
Test Execution 254000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1190.000 ms
Base64 CN1 encode 1650.000 ms
Base64 encode ratio (CN1/native) 1.387x (38.7% slower)
Base64 native decode 260.000 ms
Base64 CN1 decode 985.000 ms
Base64 decode ratio (CN1/native) 3.788x (278.8% slower)
Base64 SIMD encode 445.000 ms
Base64 encode ratio (SIMD/native) 0.374x (62.6% faster)
Base64 encode ratio (SIMD/CN1) 0.270x (73.0% faster)
Base64 SIMD decode 529.000 ms
Base64 decode ratio (SIMD/native) 2.035x (103.5% slower)
Base64 decode ratio (SIMD/CN1) 0.537x (46.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 87.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.115x (88.5% faster)
Image applyMask (SIMD off) 158.000 ms
Image applyMask (SIMD on) 77.000 ms
Image applyMask ratio (SIMD on/off) 0.487x (51.3% faster)
Image modifyAlpha (SIMD off) 207.000 ms
Image modifyAlpha (SIMD on) 236.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.140x (14.0% slower)
Image modifyAlpha removeColor (SIMD off) 231.000 ms
Image modifyAlpha removeColor (SIMD on) 105.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.455x (54.5% faster)
Image PNG encode (SIMD off) 1231.000 ms
Image PNG encode (SIMD on) 789.000 ms
Image PNG encode ratio (SIMD on/off) 0.641x (35.9% faster)
Image JPEG encode 709.000 ms

shai-almog and others added 3 commits June 10, 2026 04:22
Implements native SIMD for the Windows port (status.md gap 2), the x86/ARM analog
of IOSSimd. WindowsSimd overrides the hot-path vector ops with SSE2 (x64) / NEON
(arm64) intrinsics in cn1_windows_simd.c; Simd's @concrete gains
win=com.codename1.impl.windows.WindowsSimd and WindowsImplementation.createSimd()
returns it, so Simd.get().isSupported() is true on Windows. Each kernel vectorizes
the bulk with a scalar tail (unaligned load/store, so no aligned allocator); ops
SSE2 lacks (int32 mul/min/max/dot) stay scalar on x64 but vectorize on arm64, and
any op not overridden inherits the correct portable Simd scalar loop.

Covered: int add/sub/mul/min/max/and/or/xor/sum/dot, float add/sub/mul/min/max/
sum/dot, byte add/sub(saturating)/and/or/xor, plus fused
replaceTopByteFromUnsignedBytes / blendByMaskTestNonzero.

SimdApiTest (already in the Windows suite) gates correctness; new SimdBenchmarkTest
times native vs an inline Java scalar loop over a 64K workload, verifies the native
result matches, and logs CN1SS:SIMD:BENCH ... speedup=Nx so CI shows the benefit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements getSecureStorage() (status.md gap 4) so the networking layer can read
API keys / tokens at rest. WindowsSecureStorage encrypts each value with the
Windows Data Protection API (CryptProtectData, bound to the current user's logon)
via native dpapiProtect/dpapiUnprotect and persists the ciphertext through CN1
Storage -- the desktop analog of the iOS keychain / Android
EncryptedSharedPreferences non-prompting store. The biometric-prompting overloads
map to the same store (DPAPI is itself the user-account auth boundary). crypt32
added to the link set. SecureStorageTest round-trips set/get/remove in the suite
(self-skips where unsupported, e.g. JS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements scheduleLocalNotification/cancelLocalNotification (status.md gap 4),
mirroring the JavaSE desktop semantic: while the app runs a Timer fires the
notification at its scheduled time (with REPEAT_* support) and Shell_NotifyIcon
shows a tray balloon; clicking it routes the id (WM_CN1_TRAY -> drainInput poll)
to the app's LocalNotificationCallback. Native tray/balloon lives in
cn1_windows_notify.c, marshaled to the window-owning pump thread via WM_CN1_NOTIFY.
Background scheduling fires only while the process runs (no OS scheduler survives
app exit on desktop) -- a documented limitation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant