Skip to content

docs: Desktop Integration developer-guide chapter#5138

Merged
shai-almog merged 5 commits into
masterfrom
docs/desktop-integration-guide
Jun 1, 2026
Merged

docs: Desktop Integration developer-guide chapter#5138
shai-almog merged 5 commits into
masterfrom
docs/desktop-integration-guide

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Follow-up to #5136 (Deeper desktop integration), which merged without developer-guide coverage.

Adds a Desktop Integration chapter to docs/developer-guide covering:

  • The three title-bar modes (desktop.titleBar = native / custom / toolbar).
  • The native menu bar populated from Command objects, and the placement-hint API (Command.setDesktopMenu(...) + the DESKTOP_MENU_* constants) that maps commands into App/File/Edit/View/Window/Help.
  • Interactive scrollbars (desktop.interactiveScrollbars).
  • How to enable on the Java SE desktop build (build hints, default-on for generated apps) vs the macOS / Mac Catalyst build (Display.setProperty(...), opt-in).
  • The Desktop* / Window* theme UIIDs, with a cross-reference to the Native Themes chapter.

Wired into developer-guide.asciidoc; adds a [[native-modern-themes]] anchor so the cross-reference resolves. The full guide renders with asciidoctor cleanly (zero warnings).

🤖 Generated with Claude Code

Document the desktop integration features: title-bar modes (native/custom/toolbar
via the desktop.titleBar setting), the native menu bar with Command.setDesktopMenu
placement hints (DESKTOP_MENU_*), interactive scrollbars, how to enable on the
Java SE desktop build (build hints) and the macOS/Catalyst build (Display
properties), and the Desktop*/Window* theme UIIDs. Wired into developer-guide.asciidoc
and adds a [[native-modern-themes]] cross-reference anchor.

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

github-actions Bot commented May 31, 2026

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

shai-almog and others added 3 commits May 31, 2026 20:27
Resolve the Vale/LanguageTool findings in the new chapter: use contractions
(they're / it's) per Microsoft.Contractions and drop "all of the" -> "all the"
(Microsoft.Wordiness / LanguageTool ALL_OF_THE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reworks the "custom" desktop title-bar mode so the CN1 Toolbar itself acts
as the window's title bar instead of a separate CN1-drawn slim title bar:

- The OS window is undecorated (no native title area); the visible Toolbar
  shows the Form title + side menu and is the window's title bar.
- Dragging the Toolbar moves the (undecorated) window; the window is resized
  by dragging its edges (glass-pane edge-resize in the JavaSE port).
- Commands are bridged to the native menu bar AND remain in the side menu.

Core: split the chrome gating - isDesktopHideToolbar() (native only) vs
isDesktopToolbarTitle() (custom); remove the slim-bar chrome
(installCustomWindowChrome/WindowChromeAction/customWindowTitleLabel). The
Toolbar wires a form-level window-drag listener gated to its title band.

JavaSE port: undecorate the desktop window on first custom-mode form; the
glass-pane dispatcher implements edge-resize (cursor + drag) so the
undecorated window stays resizable on retina and non-retina.

Drops the now-unused Window*/WindowTitleBar/WindowDragArea theme UIIDs from
the modern themes and updates the developer guide and the desktop-chrome
unit/UI tests to the new semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…creenshots

Catalyst parity for the redefined "custom" desktop title-bar mode: hide the
AppKit title bar on the host NSWindow (transparent + hidden title + full-size
content view) so the CN1 Toolbar acts as the window's title bar, keep the
window resizable, and make it movable by its background so the toolbar drags
it. Reached through the existing UIWindow->NSWindow KVC bridge + objc_msgSend
(no AppKit link), re-applied on scene activation like the title/menu work.

- IOSNative.setMacWindowUndecorated(boolean) -> CN1SetMacWindowUndecorated in
  CodenameOne_GLAppDelegate.m (cn1ApplyMacWindowChrome).
- IOSImplementation: isNativeTitle() is now native-only (custom shows the
  title via the visible Toolbar, not the OS title bar); syncMacDesktopChrome()
  pushes the undecorated chrome for custom mode; the OS title is only pushed
  in native mode.

Docs: add macOS screenshots of the native / custom / toolbar title-bar modes
to the Desktop Integration developer-guide chapter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 31, 2026

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 31, 2026

✅ 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
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 31, 2026

Compared 122 screenshots: 122 matched.

Native Android coverage

  • 📊 Line coverage: 12.82% (7510/58599 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.41% (37524/360456), branch 4.37% (1479/33876), complexity 5.46% (1781/32605), method 9.54% (1461/15309), class 15.58% (333/2138)
    • 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: 12.82% (7510/58599 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.41% (37524/360456), branch 4.37% (1479/33876), complexity 5.46% (1781/32605), method 9.54% (1461/15309), class 15.58% (333/2138)
    • 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 790.000 ms
Base64 CN1 encode 195.000 ms
Base64 encode ratio (CN1/native) 0.247x (75.3% faster)
Base64 native decode 960.000 ms
Base64 CN1 decode 328.000 ms
Base64 decode ratio (CN1/native) 0.342x (65.8% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 31, 2026

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

Benchmark Results

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

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 656.000 ms
Base64 CN1 encode 1118.000 ms
Base64 encode ratio (CN1/native) 1.704x (70.4% slower)
Base64 native decode 306.000 ms
Base64 CN1 decode 841.000 ms
Base64 decode ratio (CN1/native) 2.748x (174.8% slower)
Base64 SIMD encode 354.000 ms
Base64 encode ratio (SIMD/native) 0.540x (46.0% faster)
Base64 encode ratio (SIMD/CN1) 0.317x (68.3% faster)
Base64 SIMD decode 362.000 ms
Base64 decode ratio (SIMD/native) 1.183x (18.3% slower)
Base64 decode ratio (SIMD/CN1) 0.430x (57.0% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 53.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.189x (81.1% faster)
Image applyMask (SIMD off) 115.000 ms
Image applyMask (SIMD on) 59.000 ms
Image applyMask ratio (SIMD on/off) 0.513x (48.7% faster)
Image modifyAlpha (SIMD off) 116.000 ms
Image modifyAlpha (SIMD on) 64.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.552x (44.8% faster)
Image modifyAlpha removeColor (SIMD off) 142.000 ms
Image modifyAlpha removeColor (SIMD on) 68.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.479x (52.1% faster)
Image PNG encode (SIMD off) 893.000 ms
Image PNG encode (SIMD on) 741.000 ms
Image PNG encode ratio (SIMD on/off) 0.830x (17.0% faster)
Image JPEG encode 390.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 31, 2026

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 66000 ms
Simulator Boot (Run) 1000 ms
App Install 17000 ms
App Launch 7000 ms
Test Execution 370000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1382.000 ms
Base64 CN1 encode 4305.000 ms
Base64 encode ratio (CN1/native) 3.115x (211.5% slower)
Base64 native decode 964.000 ms
Base64 CN1 decode 2088.000 ms
Base64 decode ratio (CN1/native) 2.166x (116.6% slower)
Base64 SIMD encode 982.000 ms
Base64 encode ratio (SIMD/native) 0.711x (28.9% faster)
Base64 encode ratio (SIMD/CN1) 0.228x (77.2% faster)
Base64 SIMD decode 1220.000 ms
Base64 decode ratio (SIMD/native) 1.266x (26.6% slower)
Base64 decode ratio (SIMD/CN1) 0.584x (41.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 292.000 ms
Image createMask (SIMD on) 25.000 ms
Image createMask ratio (SIMD on/off) 0.086x (91.4% faster)
Image applyMask (SIMD off) 2154.000 ms
Image applyMask (SIMD on) 447.000 ms
Image applyMask ratio (SIMD on/off) 0.208x (79.2% faster)
Image modifyAlpha (SIMD off) 1076.000 ms
Image modifyAlpha (SIMD on) 656.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.610x (39.0% faster)
Image modifyAlpha removeColor (SIMD off) 1982.000 ms
Image modifyAlpha removeColor (SIMD on) 1016.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.513x (48.7% faster)
Image PNG encode (SIMD off) 2325.000 ms
Image PNG encode (SIMD on) 1364.000 ms
Image PNG encode ratio (SIMD on/off) 0.587x (41.3% faster)
Image JPEG encode 867.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 31, 2026

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 77000 ms
Simulator Boot (Run) 0 ms
App Install 15000 ms
App Launch 16000 ms
Test Execution 303000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 578.000 ms
Base64 CN1 encode 1348.000 ms
Base64 encode ratio (CN1/native) 2.332x (133.2% slower)
Base64 native decode 269.000 ms
Base64 CN1 decode 907.000 ms
Base64 decode ratio (CN1/native) 3.372x (237.2% slower)
Base64 SIMD encode 474.000 ms
Base64 encode ratio (SIMD/native) 0.820x (18.0% faster)
Base64 encode ratio (SIMD/CN1) 0.352x (64.8% faster)
Base64 SIMD decode 413.000 ms
Base64 decode ratio (SIMD/native) 1.535x (53.5% slower)
Base64 decode ratio (SIMD/CN1) 0.455x (54.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 60.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.150x (85.0% faster)
Image applyMask (SIMD off) 120.000 ms
Image applyMask (SIMD on) 55.000 ms
Image applyMask ratio (SIMD on/off) 0.458x (54.2% faster)
Image modifyAlpha (SIMD off) 124.000 ms
Image modifyAlpha (SIMD on) 54.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.435x (56.5% faster)
Image modifyAlpha removeColor (SIMD off) 137.000 ms
Image modifyAlpha removeColor (SIMD on) 62.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.453x (54.7% faster)
Image PNG encode (SIMD off) 1047.000 ms
Image PNG encode (SIMD on) 1001.000 ms
Image PNG encode ratio (SIMD on/off) 0.956x (4.4% faster)
Image JPEG encode 473.000 ms

- docs: fix two Vale alerts in the Desktop Integration chapter (avoid the
  first-person "My" in the screenshot caption; use the "it's" contraction).
- iOS port: the Mac Catalyst native window chrome is now touched ONLY in the
  "custom" title-bar mode. The "native"/"toolbar" modes keep the original
  setCurrentForm/refreshNativeTitle title-push behavior and never call the new
  native chrome hook, so existing Catalyst apps (and the mac-native screenshot
  baseline) are byte-for-byte unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 31, 2026

JavaScript port screenshot updates

Compared 73 screenshots: 64 matched, 9 updated.

  • DialogTheme_dark — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • DialogTheme_light — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • FloatingActionButtonTheme_dark — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • FloatingActionButtonTheme_light — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • ListTheme_light — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • MultiButtonTheme_dark — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • MultiButtonTheme_light — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • SpanLabelTheme_light — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

  • ToolbarTheme_dark — updated screenshot. Screenshot differs (375x667 px, bit depth 8).

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

@shai-almog shai-almog merged commit 5015c71 into master Jun 1, 2026
35 of 38 checks passed
@shai-almog shai-almog deleted the docs/desktop-integration-guide branch June 1, 2026 00:59
shai-almog added a commit that referenced this pull request Jun 5, 2026
…, desktop notifications

Follow-up to #5136/#5138, completing the desktop integration pieces that didn't
go deep enough.

Interactive scrollbars (core):
- The thumb now highlights on hover (selected style) and while dragged (pressed
  style). Wires pointerHover through Form to the nearest scrollable ancestor;
  LookAndFeel pushes the visual state into a new InteractiveScrollThumb before
  painting. New Desktop*Thumb .selected/.pressed styles in both modern themes.
- A minimum thumb length (scrollThumbMinSizeInt theme constant, ~4mm default)
  keeps the thumb grabbable on very long content; the offset is remapped into
  the reduced travel so the enlarged thumb never overshoots the track and stays
  the inverse of dragScrollThumb. All gated on isInteractiveScroll() so mobile
  is untouched.
- (Gutter reservation already worked via getSideGap()/getBottomGap() + the
  DesktopScroll padding; covered by a new regression test.)

Menu keyboard accelerators:
- Command.setDesktopShortcut(char[, modifiers]) with PRIMARY/SHIFT/ALT flags
  (primary = Command on macOS, Control elsewhere).
- JavaSE: JMenuItem.setAccelerator from the hint (menu-shortcut mask).
- Mac Catalyst: the menu row now carries the key + modifiers and the native
  builder emits a UIKeyCommand so the accelerator shows and fires.

Desktop notifications:
- JavaSEPort now honors LocalNotification on a real desktop build (not just the
  simulator): scheduled notifications surface through a persistent SystemTray
  icon and clicking dispatches to LocalNotificationCallback. Mac Catalyst keeps
  using the iOS UNUserNotificationCenter path.

Tests: InteractiveScrollbarTest (hover, min-size+clamp, gutter), DesktopChromeTest
(shortcut round-trip), DesktopChromeUITest (real JMenuItem accelerator). Developer
guide updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request Jun 5, 2026
…, desktop notifications

Follow-up to #5136/#5138, completing the desktop integration pieces that didn't
go deep enough.

Interactive scrollbars (core):
- The thumb now highlights on hover (selected style) and while dragged (pressed
  style). Wires pointerHover through Form to the nearest scrollable ancestor;
  LookAndFeel pushes the visual state into a new InteractiveScrollThumb before
  painting. New Desktop*Thumb .selected/.pressed styles in both modern themes.
- A minimum thumb length (scrollThumbMinSizeInt theme constant, ~4mm default)
  keeps the thumb grabbable on very long content; the offset is remapped into
  the reduced travel so the enlarged thumb never overshoots the track and stays
  the inverse of dragScrollThumb. All gated on isInteractiveScroll() so mobile
  is untouched.
- (Gutter reservation already worked via getSideGap()/getBottomGap() + the
  DesktopScroll padding; covered by a new regression test.)

Menu keyboard accelerators:
- Command.setDesktopShortcut(char[, modifiers]) with PRIMARY/SHIFT/ALT flags
  (primary = Command on macOS, Control elsewhere).
- JavaSE: JMenuItem.setAccelerator from the hint (menu-shortcut mask).
- Mac Catalyst: the menu row now carries the key + modifiers and the native
  builder emits a UIKeyCommand so the accelerator shows and fires.

Desktop notifications:
- JavaSEPort now honors LocalNotification on a real desktop build (not just the
  simulator): scheduled notifications surface through a persistent SystemTray
  icon and clicking dispatches to LocalNotificationCallback. Mac Catalyst keeps
  using the iOS UNUserNotificationCenter path.

Tests: InteractiveScrollbarTest (hover, min-size+clamp, gutter), DesktopChromeTest
(shortcut round-trip), DesktopChromeUITest (real JMenuItem accelerator). Developer
guide updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request Jun 5, 2026
…, desktop notifications

Follow-up to #5136/#5138, completing the desktop integration pieces that didn't
go deep enough.

Interactive scrollbars (core):
- The thumb now highlights on hover (selected style) and while dragged (pressed
  style). Wires pointerHover through Form to the nearest scrollable ancestor;
  LookAndFeel pushes the visual state into a new InteractiveScrollThumb before
  painting. New Desktop*Thumb .selected/.pressed styles in both modern themes.
- A minimum thumb length (scrollThumbMinSizeInt theme constant, ~4mm default)
  keeps the thumb grabbable on very long content; the offset is remapped into
  the reduced travel so the enlarged thumb never overshoots the track and stays
  the inverse of dragScrollThumb. All gated on isInteractiveScroll() so mobile
  is untouched.
- (Gutter reservation already worked via getSideGap()/getBottomGap() + the
  DesktopScroll padding; covered by a new regression test.)

Menu keyboard accelerators:
- Command.setDesktopShortcut(char[, modifiers]) with PRIMARY/SHIFT/ALT flags
  (primary = Command on macOS, Control elsewhere).
- JavaSE: JMenuItem.setAccelerator from the hint (menu-shortcut mask).
- Mac Catalyst: the menu row now carries the key + modifiers and the native
  builder emits a UIKeyCommand so the accelerator shows and fires.

Desktop notifications:
- JavaSEPort now honors LocalNotification on a real desktop build (not just the
  simulator): scheduled notifications surface through a persistent SystemTray
  icon and clicking dispatches to LocalNotificationCallback. Mac Catalyst keeps
  using the iOS UNUserNotificationCenter path.

Tests: InteractiveScrollbarTest (hover, min-size+clamp, gutter), DesktopChromeTest
(shortcut round-trip), DesktopChromeUITest (real JMenuItem accelerator). Developer
guide updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request Jun 5, 2026
…, desktop notifications (#5170)

* Deepen desktop integration: scrollbar thumb polish, menu accelerators, desktop notifications

Follow-up to #5136/#5138, completing the desktop integration pieces that didn't
go deep enough.

Interactive scrollbars (core):
- The thumb now highlights on hover (selected style) and while dragged (pressed
  style). Wires pointerHover through Form to the nearest scrollable ancestor;
  LookAndFeel pushes the visual state into a new InteractiveScrollThumb before
  painting. New Desktop*Thumb .selected/.pressed styles in both modern themes.
- A minimum thumb length (scrollThumbMinSizeInt theme constant, ~4mm default)
  keeps the thumb grabbable on very long content; the offset is remapped into
  the reduced travel so the enlarged thumb never overshoots the track and stays
  the inverse of dragScrollThumb. All gated on isInteractiveScroll() so mobile
  is untouched.
- (Gutter reservation already worked via getSideGap()/getBottomGap() + the
  DesktopScroll padding; covered by a new regression test.)

Menu keyboard accelerators:
- Command.setDesktopShortcut(char[, modifiers]) with PRIMARY/SHIFT/ALT flags
  (primary = Command on macOS, Control elsewhere).
- JavaSE: JMenuItem.setAccelerator from the hint (menu-shortcut mask).
- Mac Catalyst: the menu row now carries the key + modifiers and the native
  builder emits a UIKeyCommand so the accelerator shows and fires.

Desktop notifications:
- JavaSEPort now honors LocalNotification on a real desktop build (not just the
  simulator): scheduled notifications surface through a persistent SystemTray
  icon and clicking dispatches to LocalNotificationCallback. Mac Catalyst keeps
  using the iOS UNUserNotificationCenter path.

Tests: InteractiveScrollbarTest (hover, min-size+clamp, gutter), DesktopChromeTest
(shortcut round-trip), DesktopChromeUITest (real JMenuItem accelerator). Developer
guide updated.

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

* Fix CSS derive cycle in Desktop*Thumb hover/pressed styles

The .selected/.pressed variants used `cn1-derive: DesktopScrollThumb` (deriving a
state from its own base UIID), which made the CSS theme compiler recurse forever
in CSSTheme$Element.getFlattenedStyle and blew the stack while building the
JavaScript and JavaSE-simulator theme bundles. Re-declare the thumb properties
directly instead (matching the dark-theme overrides), removing the self-reference.

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

* docs: reword 'grabbable' to satisfy LanguageTool NON_STANDARD_WORD gate

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

* docs: drop literal key combos from intro bullet for LanguageTool

LanguageTool's NON_STANDARD_WORD rule flags the bare 'Ctrl+S' token in prose
(it reads it as a misspelled word). The concrete Cmd+S/Ctrl+S mapping still lives
in the code-block comment, which the grammar check excludes.

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

* docs: replace 'and so on' (Vale Microsoft.Avoid) in accelerator bullet

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

* Add DesktopMode screenshot test demonstrating desktop integration per-port

Adds DesktopModeScreenshotTest to scripts/hellocodenameone, registered in
Cn1ssDeviceRunner. The same code runs on every port and gates on CN.isDesktop():

- Mobile (Android / iOS / JavaScript): renders an ordinary screen - a CN1 Toolbar
  with a hamburger side menu and the usual fading touch scrollbar (settled to
  invisible by capture time). Desktop integration has no visible impact.
- Mac native (Catalyst, isDesktop()): opts into desktop mode (desktop.titleBar=native
  + interactive scrollbars). The Toolbar/hamburger disappears (commands move to the
  native macOS menu bar, outside the form raster) and the scrollbar shows an
  always-visible draggable thumb the mobile ports never display. Command keyboard
  shortcuts are exercised too (UIKeyCommand) though a still shot can't show them.

The desktop toggles are global, so the test reverts them in done() (after the
screenshot is captured), keeping every other test's baseline on every port unchanged.
The test has no golden yet, so it reports as a "new" screenshot (missing_expected) on
each pipeline without failing CI; baselines get seeded from the first run's artifacts.

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

* Make iOS-modern desktop scroll thumb opaque so it renders visibly

The always-visible interactive desktop scrollbar thumb in ios-modern was
rgba(0,0,0,0.35); composited over content on the iOS/Metal (Mac native) pipeline
it read as effectively invisible, so the Mac native DesktopMode screenshot showed
the reserved gutter but no thumb. Switch the thumb to opaque macOS-style greys
(hover/drag still darken), matching android-material's already-opaque thumb. This
is the correct treatment for an always-visible (non-fading) desktop scrollbar.

Also adds a one-line diagnostic log to DesktopModeScreenshotTest's desktop branch
(interactiveScroll + gutter width) to confirm engagement in the device-runner log.

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

* Render interactive scrollbar track/thumb via direct Graphics fill

The always-visible interactive (desktop) scrollbar was painted by calling
paintComponent() on the orphan track/thumb Label components. A component that was
never attached to a form does not reliably render its background on every port -
on the iOS/Metal Mac-native pipeline the thumb produced no pixels, so the Mac
screenshot showed a reserved gutter with no visible scrollbar.

Paint the track and thumb directly with g.fillRect using the resolved style's
bgColor/transparency (the InteractiveScrollThumb visual state still selects
unselected/hover/pressed). fillRect renders identically on every port's Graphics.
Only the interactive path is touched (no pre-existing baselines), and the new
InteractiveScrollbarTest.interactiveThumbRendersOpaquePixels asserts the thumb
actually paints pixels. Also drops the temporary diagnostic from the demo test.

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

* Fix JDK 8/11 javadoc-jar build: drop newer-only javadoc flags from the plugin

The maven-javadoc-plugin config passed --add-stylesheet / --add-script, which only
exist in newer javadoc tools (JDK 8 rejects --add-stylesheet, JDK 11 rejects
--add-script). Any JDK 8/11 `mvn install` that builds the per-module javadoc jar
therefore failed with "invalid flag: --add-stylesheet" - breaking, among others,
the iOS-port framework install used by the iOS and Mac-native screenshot pipelines.

The published website javadocs are produced separately by
.github/scripts/build_javadocs.sh, which invokes javadoc directly on JDK 25 with its
own copy of those flags, so the maven plugin doesn't need them. Keep only
--allow-script-in-comments (valid on JDK 8+) in the plugin; the per-module javadoc
jars no longer carry the website's syntax-highlight CSS, which they never needed.

Also skip javadoc/source jars in build-ios-port.sh's framework install (matching
setup-workspace.sh) so the iOS port builds faster and never depends on this.

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

* Seed DesktopMode screenshot baselines for all five ports

Adds the golden images for the new DesktopModeScreenshotTest, captured from CI:

- android / javascript / ios / ios-metal: the mobile rendering - a CN1 Toolbar with
  a hamburger side menu and full-width rows; desktop mode is inert (CN.isDesktop()
  is false), so it has no visible effect.
- mac-native: the desktop rendering - no in-app Toolbar/hamburger (the commands move
  to the native macOS menu bar) and content inset by the reserved interactive-
  scrollbar gutter; the desktop window proportions differ from the phone ports.

This turns the test into a real per-port pixel regression. (The always-visible
scrollbar thumb itself is not yet visible in the mac-native capture - the interactive
scrollbar paint is dropped on the iOS/Metal pipeline despite rendering correctly in
JavaSE; tracked separately.)

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

* Move DesktopModeScreenshotTest to the end of the suite; re-seed goldens next

Root cause of the Android (and any port's) screenshot breakage: running
DesktopModeScreenshotTest early (position 2) shifted suite timing / warmed the font
cache, which flipped the baselines of the later graphics font tests (DrawString,
DrawStringDecorated, inscribed-triangle-grid). Those tests paint text directly during
a frame that races the async native-font load, so the amount of work done before them
determines whether the fonts are loaded at capture time. master captures the
not-yet-loaded state deterministically; inserting a test before them changed it.

Fix: run DesktopModeScreenshotTest LAST, so every pre-existing test executes in the
exact same sequence as master and matches its stored baseline. Temporarily drop the
DesktopMode goldens so the test reports as a tolerated "new" screenshot (it can't
fail on mismatch) while it's at its new position - the baselines will be re-seeded
from this position's CI output in a follow-up, since theme tests that run before it
can leave global theme state that affects its rendering.

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

---------

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