mirror of
https://github.com/bitsycore/compose-desktop-native.git
synced 2026-10-06 19:27:26 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb44db915e | ||
|
|
1120abc488 |
@@ -391,21 +391,21 @@ re-vendoring.** The debt is **completing native-actual stubs**.
|
||||
### P0 - blocks fidelity/correctness
|
||||
|
||||
- [~] **P0** Text context menu (right-click copy/paste/select-all) - **RECONCILED: already
|
||||
works, no reimplementation.** Static trace confirmed the menu is wired end-to-end
|
||||
through the vendored LEGACY path: text-level `ContextMenuArea` (`ContextMenu.native.kt`)
|
||||
works, no reimplementation.** Static trace confirmed the menu is wired end-to-end
|
||||
through the vendored LEGACY path: text-level `ContextMenuArea` (`ContextMenu.native.kt`)
|
||||
→ `CommonContextMenuArea` (`vendor/common/.../text/CommonContextMenuArea.kt`) → (native
|
||||
`ComposeFoundationFlags.isNewContextMenuEnabled = false`, so the legacy branch) →
|
||||
`contextmenu.ContextMenuArea` → `contextMenuGestures`/`onRightClickDown`
|
||||
(`isSecondaryPressed`) → `ContextMenuPopup` → `Popup.native.kt` (hosted by
|
||||
`LocalPopupHost` at the app root). Items are real: `TextFieldSelectionManager` /
|
||||
`SelectionManager.contextMenuBuilder` emit Cut/Copy/Paste/SelectAll with real actions.
|
||||
SDL right-click → `PointerButton.Secondary` (`SDL3EventMapper.kt`) →
|
||||
SDL right-click → `PointerButton.Secondary` (`AppEvent.kt`) →
|
||||
`isSecondaryPressed` (`PointerEventBridge`). The three "NOP" seams belong to the
|
||||
DISABLED *new* context-menu API and are unreachable - **DONE:** their misleading
|
||||
DISABLED *new* context-menu API and are unreachable - **DONE:** their misleading
|
||||
`TODO(CMP-7819)` comments corrected to say so, in all three files.
|
||||
**REMAINING:** an interactive right-click smoke check (no headless driver here - fold
|
||||
into manual/WIN-SMOKE). Known limitation, not a breakage: Paste enablement is
|
||||
plain-text-only (`ClipboardPasteState.hasClip = hasText`, see P2 below).
|
||||
**REMAINING:** an interactive right-click smoke check (no headless driver here - fold
|
||||
into manual/WIN-SMOKE). Known limitation, not a breakage: Paste enablement is
|
||||
plain-text-only (`ClipboardPasteState.hasClip = hasText`, see P2 below).
|
||||
- [ ] **P1** DatePicker/TimePicker localization - VERIFIED current state:
|
||||
`material3/.../internal/PlatformDateFormat.native.kt` is a real kotlinx-datetime
|
||||
formatter that DOES honor CLDR patterns/skeletons (renders "Jul 29, 2026" /
|
||||
@@ -417,14 +417,14 @@ re-vendoring.** The debt is **completing native-actual stubs**.
|
||||
(author):** bundle a CLDR subset or K/N i18n lib for localized names + locale-aware
|
||||
first-day/24h; also unblocks `CalendarLocale.native.kt:20` (fixed `"en"`). Ships
|
||||
readable English dates today - polish, not a P0 gate.
|
||||
- [x] **P0** Float pointer coordinates - `SDL3EventMapper.kt` `.toInt()`-truncated SDL's
|
||||
Float `mb.x`/`mb.y`/`mm.x`/`mm.y` and the wheel `mouse_x/y` before the DPR multiply in
|
||||
- [x] **P0** Float pointer coordinates - `AppEvent.kt` `.toInt()`-truncated SDL's
|
||||
Float `mb.x`/`mb.y`/`mm.x`/`mm.y` and the wheel `mouse_x/y` before the DPR multiply in
|
||||
`ComposeWindow.kt`. On 2× displays a click at logical 100.9 → physical 200 not ~201,
|
||||
quantizing the caret to 2px steps near glyph edges. **DONE:** widened
|
||||
quantizing the caret to 2px steps near glyph edges. **DONE:** widened
|
||||
`LegacyPointerEvent.x/y` and `AppEvent.MouseWheel.x/y` to `Float`, dropped the
|
||||
`.toInt()` at the three mapper construction sites, and removed the now-redundant
|
||||
`.toFloat()` at the two `ComposeWindow` read sites. Consumers fully contained (verified
|
||||
by grep). Builds + runs clean on macosArm64.
|
||||
by grep). Builds + runs clean on macosArm64.
|
||||
|
||||
### P1 - quality / parity
|
||||
|
||||
@@ -521,7 +521,7 @@ re-vendoring.** The debt is **completing native-actual stubs**.
|
||||
Static lib built from source per host (`scripts/build-sdl/build-all.py`, ref
|
||||
`release-3.4.12`); linked into the exe via `sdl3.def` (`staticLibraries=libSDL3.a`). Today
|
||||
only tests/examples + Windows D3D12/GPU are off (`build-all.py:311-319`). `SDL_Init` uses
|
||||
**`SDL_INIT_VIDEO` only** (`SDL3Backend.kt:49`).
|
||||
**`SDL_INIT_VIDEO` only** (`Sdl3Backend.kt:49`).
|
||||
|
||||
**USED (keep ON):** Video/window, Events, Clipboard, Dialog (file open/save - no cheaper
|
||||
substitute; Linux uses portal/zenity, keep deps), OpenGL + Metal contexts, Render (2D CPU-
|
||||
@@ -554,7 +554,7 @@ joystick.
|
||||
disabled SDL subsystems.)
|
||||
- [ ] **P2** (higher-risk, flag-don't-apply) Render-driver pruning to software-only. Only
|
||||
the CPU-raster fallback uses `SDL_Render`; GL/Metal go direct. But
|
||||
`SDL_CreateRenderer(window, null)` (`SDL3Backend.kt:117`) lets SDL pick the first
|
||||
`SDL_CreateRenderer(window, null)` (`Sdl3Backend.kt:117`) lets SDL pick the first
|
||||
driver - with only software present it picks software (fine) but couples the fallback
|
||||
to that assumption. **Conservative: leave render drivers alone.**
|
||||
|
||||
@@ -732,7 +732,7 @@ Rule-3 vendors (like `FontRasterizationSettings.native.kt` now has a `VENDOR-BAS
|
||||
The multi-window probe exited 139 with no output, so it had silently been
|
||||
asserting nothing. Root cause: an OpenGL context is per-WINDOW but "current" is
|
||||
per-THREAD, and `SDL_GL_MakeCurrent` ran only once at creation
|
||||
(`SDL3Backend.init`) with nothing re-binding it per frame. With two windows open,
|
||||
(`Sdl3Backend.init`) with nothing re-binding it per frame. With two windows open,
|
||||
whichever initialised last owned the thread - so window A issued its draw and
|
||||
swap against window B's context (silent corruption while both lived), and
|
||||
destroying B left the current context dangling, faulting in `present()`.
|
||||
|
||||
@@ -273,17 +273,6 @@ mirrors or you will have every class twice.
|
||||
| Collection | `androidx.collection:collection:1.5.0` |
|
||||
| Graphics Shapes | `androidx.graphics:graphics-shapes:1.1.0` |
|
||||
|
||||
### Infrastructure
|
||||
|
||||
| Library | Version |
|
||||
|---|---|
|
||||
| kotlinx-coroutines | 1.11.0 |
|
||||
| kotlinx-serialization | 1.11.0 |
|
||||
| kotlinx-datetime | 0.8.0 |
|
||||
| kotlinx-io-okio | 0.9.1 |
|
||||
| Okio | 3.18.2 |
|
||||
| Ktor | 3.5.2 |
|
||||
|
||||
## Building
|
||||
|
||||
Build the native libraries once per machine, then build any app target:
|
||||
@@ -298,6 +287,10 @@ command line tools; Linux needs gcc/g++ and the X11 / Wayland / audio dev
|
||||
headers; Windows needs a mingw-w64 g++ on PATH. See [TOOLING.md](TOOLING.md) for
|
||||
the full build and verification workflow.
|
||||
|
||||
## Support
|
||||
|
||||
[Bitsycore's Discord](https://discord.gg/kGnraVAtDR)
|
||||
|
||||
## Documentation
|
||||
|
||||
- [TOOLING.md](TOOLING.md): building the native libs, vendoring, and verification.
|
||||
|
||||
@@ -11,12 +11,6 @@ plugins {
|
||||
alias(libs.plugins.kotlin.plugin.compose)
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
|
||||
val vHostSupportsMingw = rootProject.extra["vHostSupportsMingw"] as Boolean
|
||||
|
||||
kotlin {
|
||||
|
||||
+1
-2
@@ -14,7 +14,6 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.snapshots.Snapshot
|
||||
import com.compose.sdl.res.currentImageLoader
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
@@ -141,7 +140,7 @@ fun nativeComposeApp(content: @Composable ApplicationScope.() -> Unit) {
|
||||
runtime.scope = this
|
||||
|
||||
// App-level composition: no UI tree - it only declares Window()s.
|
||||
val appClock = SDL3FrameClock()
|
||||
val appClock = Sdl3FrameClock()
|
||||
val appRecomposer = Recomposer(coroutineContext + appClock)
|
||||
// The clock must be in the collector's context - runRecomposeAndApplyChanges
|
||||
// awaits parent frames through it.
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import sdl3.SDL_GetTicksNS
|
||||
|
||||
Both come from delegating to the runtime's BroadcastFrameClock, which is
|
||||
exactly upstream's dispatch structure. */
|
||||
internal class SDL3FrameClock : MonotonicFrameClock {
|
||||
internal class Sdl3FrameClock : MonotonicFrameClock {
|
||||
private val broadcast = BroadcastFrameClock()
|
||||
|
||||
override suspend fun <R> withFrameNanos(onFrame: (Long) -> R): R =
|
||||
+4
-4
@@ -56,7 +56,7 @@ internal class WindowInstance(
|
||||
private val initialHeight = inHeight
|
||||
private val icon = inIcon
|
||||
// Assigned by init() from the first backend that comes up (see makeBackend()).
|
||||
lateinit var backend: SDL3Backend
|
||||
lateinit var backend: Sdl3Backend
|
||||
private set
|
||||
private var renderBackend: RenderBackend? = null
|
||||
lateinit var host: ComposeRootHost
|
||||
@@ -65,7 +65,7 @@ internal class WindowInstance(
|
||||
private set
|
||||
private var popupHost: com.compose.sdl.window.PopupHostState? = null
|
||||
|
||||
val frameClock = SDL3FrameClock()
|
||||
val frameClock = Sdl3FrameClock()
|
||||
private var recomposer: Recomposer? = null
|
||||
private var recomposeJob: Job? = null
|
||||
private var composition: Composition? = null
|
||||
@@ -128,11 +128,11 @@ internal class WindowInstance(
|
||||
needsFrame = true
|
||||
}
|
||||
|
||||
// Creates + initialises an SDL3Backend for [mode] and its RenderBackend. On
|
||||
// Creates + initialises an Sdl3Backend for [mode] and its RenderBackend. On
|
||||
// success commits `backend` and returns the renderer; else tears everything
|
||||
// down and returns null so the caller can retry with a different mode.
|
||||
private fun makeBackend(mode: GpuMode): RenderBackend? {
|
||||
val vBackend = SDL3Backend(
|
||||
val vBackend = Sdl3Backend(
|
||||
initialTitle, initialWidth, initialHeight, gpuMode = mode,
|
||||
iconLightResourcePaths = icon?.light ?: emptyList(),
|
||||
iconDarkResourcePaths = icon?.dark ?: emptyList(),
|
||||
|
||||
@@ -2827,7 +2827,7 @@ final class com.compose.sdl.window/PopupHostState { // com.compose.sdl.window/Po
|
||||
}
|
||||
|
||||
final class com.compose.sdl/ComposeNativeWindow { // com.compose.sdl/ComposeNativeWindow|null[0]
|
||||
constructor <init>(com.compose.sdl/SDL3Backend, com.compose.sdl/GpuMode, kotlin/String) // com.compose.sdl/ComposeNativeWindow.<init>|<init>(com.compose.sdl.SDL3Backend;com.compose.sdl.GpuMode;kotlin.String){}[0]
|
||||
constructor <init>(com.compose.sdl/Sdl3Backend, com.compose.sdl/GpuMode, kotlin/String) // com.compose.sdl/ComposeNativeWindow.<init>|<init>(com.compose.sdl.Sdl3Backend;com.compose.sdl.GpuMode;kotlin.String){}[0]
|
||||
|
||||
final val fps // com.compose.sdl/ComposeNativeWindow.fps|{}fps[0]
|
||||
final fun <get-fps>(): kotlin/Int // com.compose.sdl/ComposeNativeWindow.fps.<get-fps>|<get-fps>(){}[0]
|
||||
@@ -2912,39 +2912,39 @@ final class com.compose.sdl/RawSdlHandles { // com.compose.sdl/RawSdlHandles|nul
|
||||
final fun toString(): kotlin/String // com.compose.sdl/RawSdlHandles.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl/SDL3Backend { // com.compose.sdl/SDL3Backend|null[0]
|
||||
constructor <init>(kotlin/String = ..., kotlin/Int = ..., kotlin/Int = ..., com.compose.sdl/GpuMode = ..., kotlin.collections/List<kotlin/String> = ..., kotlin.collections/List<kotlin/String> = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ...) // com.compose.sdl/SDL3Backend.<init>|<init>(kotlin.String;kotlin.Int;kotlin.Int;com.compose.sdl.GpuMode;kotlin.collections.List<kotlin.String>;kotlin.collections.List<kotlin.String>;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean){}[0]
|
||||
final class com.compose.sdl/Sdl3Backend { // com.compose.sdl/Sdl3Backend|null[0]
|
||||
constructor <init>(kotlin/String = ..., kotlin/Int = ..., kotlin/Int = ..., com.compose.sdl/GpuMode = ..., kotlin.collections/List<kotlin/String> = ..., kotlin.collections/List<kotlin/String> = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ...) // com.compose.sdl/Sdl3Backend.<init>|<init>(kotlin.String;kotlin.Int;kotlin.Int;com.compose.sdl.GpuMode;kotlin.collections.List<kotlin.String>;kotlin.collections.List<kotlin.String>;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean){}[0]
|
||||
|
||||
final val gpuMode // com.compose.sdl/SDL3Backend.gpuMode|{}gpuMode[0]
|
||||
final fun <get-gpuMode>(): com.compose.sdl/GpuMode // com.compose.sdl/SDL3Backend.gpuMode.<get-gpuMode>|<get-gpuMode>(){}[0]
|
||||
final val pixelDensity // com.compose.sdl/SDL3Backend.pixelDensity|{}pixelDensity[0]
|
||||
final fun <get-pixelDensity>(): kotlin/Float // com.compose.sdl/SDL3Backend.pixelDensity.<get-pixelDensity>|<get-pixelDensity>(){}[0]
|
||||
final val windowId // com.compose.sdl/SDL3Backend.windowId|{}windowId[0]
|
||||
final fun <get-windowId>(): kotlin/UInt // com.compose.sdl/SDL3Backend.windowId.<get-windowId>|<get-windowId>(){}[0]
|
||||
final val gpuMode // com.compose.sdl/Sdl3Backend.gpuMode|{}gpuMode[0]
|
||||
final fun <get-gpuMode>(): com.compose.sdl/GpuMode // com.compose.sdl/Sdl3Backend.gpuMode.<get-gpuMode>|<get-gpuMode>(){}[0]
|
||||
final val pixelDensity // com.compose.sdl/Sdl3Backend.pixelDensity|{}pixelDensity[0]
|
||||
final fun <get-pixelDensity>(): kotlin/Float // com.compose.sdl/Sdl3Backend.pixelDensity.<get-pixelDensity>|<get-pixelDensity>(){}[0]
|
||||
final val windowId // com.compose.sdl/Sdl3Backend.windowId|{}windowId[0]
|
||||
final fun <get-windowId>(): kotlin/UInt // com.compose.sdl/Sdl3Backend.windowId.<get-windowId>|<get-windowId>(){}[0]
|
||||
|
||||
final var glContext // com.compose.sdl/SDL3Backend.glContext|{}glContext[0]
|
||||
final fun <get-glContext>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/SDL3Backend.glContext.<get-glContext>|<get-glContext>(){}[0]
|
||||
final var metalView // com.compose.sdl/SDL3Backend.metalView|{}metalView[0]
|
||||
final fun <get-metalView>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/SDL3Backend.metalView.<get-metalView>|<get-metalView>(){}[0]
|
||||
final var pixelHeight // com.compose.sdl/SDL3Backend.pixelHeight|{}pixelHeight[0]
|
||||
final fun <get-pixelHeight>(): kotlin/Int // com.compose.sdl/SDL3Backend.pixelHeight.<get-pixelHeight>|<get-pixelHeight>(){}[0]
|
||||
final var pixelWidth // com.compose.sdl/SDL3Backend.pixelWidth|{}pixelWidth[0]
|
||||
final fun <get-pixelWidth>(): kotlin/Int // com.compose.sdl/SDL3Backend.pixelWidth.<get-pixelWidth>|<get-pixelWidth>(){}[0]
|
||||
final var renderer // com.compose.sdl/SDL3Backend.renderer|{}renderer[0]
|
||||
final fun <get-renderer>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/SDL3Backend.renderer.<get-renderer>|<get-renderer>(){}[0]
|
||||
final var vsyncEnabled // com.compose.sdl/SDL3Backend.vsyncEnabled|{}vsyncEnabled[0]
|
||||
final fun <get-vsyncEnabled>(): kotlin/Boolean // com.compose.sdl/SDL3Backend.vsyncEnabled.<get-vsyncEnabled>|<get-vsyncEnabled>(){}[0]
|
||||
final var window // com.compose.sdl/SDL3Backend.window|{}window[0]
|
||||
final fun <get-window>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/SDL3Backend.window.<get-window>|<get-window>(){}[0]
|
||||
final var windowHeight // com.compose.sdl/SDL3Backend.windowHeight|{}windowHeight[0]
|
||||
final fun <get-windowHeight>(): kotlin/Int // com.compose.sdl/SDL3Backend.windowHeight.<get-windowHeight>|<get-windowHeight>(){}[0]
|
||||
final var windowWidth // com.compose.sdl/SDL3Backend.windowWidth|{}windowWidth[0]
|
||||
final fun <get-windowWidth>(): kotlin/Int // com.compose.sdl/SDL3Backend.windowWidth.<get-windowWidth>|<get-windowWidth>(){}[0]
|
||||
final var glContext // com.compose.sdl/Sdl3Backend.glContext|{}glContext[0]
|
||||
final fun <get-glContext>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/Sdl3Backend.glContext.<get-glContext>|<get-glContext>(){}[0]
|
||||
final var metalView // com.compose.sdl/Sdl3Backend.metalView|{}metalView[0]
|
||||
final fun <get-metalView>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/Sdl3Backend.metalView.<get-metalView>|<get-metalView>(){}[0]
|
||||
final var pixelHeight // com.compose.sdl/Sdl3Backend.pixelHeight|{}pixelHeight[0]
|
||||
final fun <get-pixelHeight>(): kotlin/Int // com.compose.sdl/Sdl3Backend.pixelHeight.<get-pixelHeight>|<get-pixelHeight>(){}[0]
|
||||
final var pixelWidth // com.compose.sdl/Sdl3Backend.pixelWidth|{}pixelWidth[0]
|
||||
final fun <get-pixelWidth>(): kotlin/Int // com.compose.sdl/Sdl3Backend.pixelWidth.<get-pixelWidth>|<get-pixelWidth>(){}[0]
|
||||
final var renderer // com.compose.sdl/Sdl3Backend.renderer|{}renderer[0]
|
||||
final fun <get-renderer>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/Sdl3Backend.renderer.<get-renderer>|<get-renderer>(){}[0]
|
||||
final var vsyncEnabled // com.compose.sdl/Sdl3Backend.vsyncEnabled|{}vsyncEnabled[0]
|
||||
final fun <get-vsyncEnabled>(): kotlin/Boolean // com.compose.sdl/Sdl3Backend.vsyncEnabled.<get-vsyncEnabled>|<get-vsyncEnabled>(){}[0]
|
||||
final var window // com.compose.sdl/Sdl3Backend.window|{}window[0]
|
||||
final fun <get-window>(): kotlinx.cinterop/CPointer<out kotlinx.cinterop/CPointed>? // com.compose.sdl/Sdl3Backend.window.<get-window>|<get-window>(){}[0]
|
||||
final var windowHeight // com.compose.sdl/Sdl3Backend.windowHeight|{}windowHeight[0]
|
||||
final fun <get-windowHeight>(): kotlin/Int // com.compose.sdl/Sdl3Backend.windowHeight.<get-windowHeight>|<get-windowHeight>(){}[0]
|
||||
final var windowWidth // com.compose.sdl/Sdl3Backend.windowWidth|{}windowWidth[0]
|
||||
final fun <get-windowWidth>(): kotlin/Int // com.compose.sdl/Sdl3Backend.windowWidth.<get-windowWidth>|<get-windowWidth>(){}[0]
|
||||
|
||||
final fun applyThemeIcon() // com.compose.sdl/SDL3Backend.applyThemeIcon|applyThemeIcon(){}[0]
|
||||
final fun destroy(kotlin/Boolean = ...) // com.compose.sdl/SDL3Backend.destroy|destroy(kotlin.Boolean){}[0]
|
||||
final fun init(): kotlin/Boolean // com.compose.sdl/SDL3Backend.init|init(){}[0]
|
||||
final fun updateWindowSize() // com.compose.sdl/SDL3Backend.updateWindowSize|updateWindowSize(){}[0]
|
||||
final fun applyThemeIcon() // com.compose.sdl/Sdl3Backend.applyThemeIcon|applyThemeIcon(){}[0]
|
||||
final fun destroy(kotlin/Boolean = ...) // com.compose.sdl/Sdl3Backend.destroy|destroy(kotlin.Boolean){}[0]
|
||||
final fun init(): kotlin/Boolean // com.compose.sdl/Sdl3Backend.init|init(){}[0]
|
||||
final fun updateWindowSize() // com.compose.sdl/Sdl3Backend.updateWindowSize|updateWindowSize(){}[0]
|
||||
}
|
||||
|
||||
final value class <#A: kotlin/Any?> androidx.compose.ui/SessionMutex { // androidx.compose.ui/SessionMutex|null[0]
|
||||
@@ -4863,7 +4863,7 @@ final val com.compose.sdl/com_compose_sdl_GpuMode_CpuRaster$stableprop // com.co
|
||||
final val com.compose.sdl/com_compose_sdl_GpuMode_Metal$stableprop // com.compose.sdl/com_compose_sdl_GpuMode_Metal$stableprop|#static{}com_compose_sdl_GpuMode_Metal$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_GpuMode_OpenGL$stableprop // com.compose.sdl/com_compose_sdl_GpuMode_OpenGL$stableprop|#static{}com_compose_sdl_GpuMode_OpenGL$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_RawSdlHandles$stableprop // com.compose.sdl/com_compose_sdl_RawSdlHandles$stableprop|#static{}com_compose_sdl_RawSdlHandles$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_SDL3Backend$stableprop // com.compose.sdl/com_compose_sdl_SDL3Backend$stableprop|#static{}com_compose_sdl_SDL3Backend$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_Sdl3Backend$stableprop // com.compose.sdl/com_compose_sdl_Sdl3Backend$stableprop|#static{}com_compose_sdl_Sdl3Backend$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_TextLayoutConfig$stableprop // com.compose.sdl/com_compose_sdl_TextLayoutConfig$stableprop|#static{}com_compose_sdl_TextLayoutConfig$stableprop[0]
|
||||
|
||||
final var androidx.compose.ui.platform/isDebugInspectorInfoEnabled // androidx.compose.ui.platform/isDebugInspectorInfoEnabled|{}isDebugInspectorInfoEnabled[0]
|
||||
@@ -5387,9 +5387,9 @@ final fun com.compose.sdl/com_compose_sdl_GpuMode_CpuRaster$stableprop_getter():
|
||||
final fun com.compose.sdl/com_compose_sdl_GpuMode_Metal$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_GpuMode_Metal$stableprop_getter|com_compose_sdl_GpuMode_Metal$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_GpuMode_OpenGL$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_GpuMode_OpenGL$stableprop_getter|com_compose_sdl_GpuMode_OpenGL$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_RawSdlHandles$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_RawSdlHandles$stableprop_getter|com_compose_sdl_RawSdlHandles$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_SDL3Backend$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_SDL3Backend$stableprop_getter|com_compose_sdl_SDL3Backend$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_Sdl3Backend$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_Sdl3Backend$stableprop_getter|com_compose_sdl_Sdl3Backend$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_TextLayoutConfig$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_TextLayoutConfig$stableprop_getter|com_compose_sdl_TextLayoutConfig$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/createRenderBackend(com.compose.sdl/SDL3Backend, com.compose.sdl/GpuMode): com.compose.sdl/RenderBackend? // com.compose.sdl/createRenderBackend|createRenderBackend(com.compose.sdl.SDL3Backend;com.compose.sdl.GpuMode){}[0]
|
||||
final fun com.compose.sdl/createRenderBackend(com.compose.sdl/Sdl3Backend, com.compose.sdl/GpuMode): com.compose.sdl/RenderBackend? // com.compose.sdl/createRenderBackend|createRenderBackend(com.compose.sdl.Sdl3Backend;com.compose.sdl.GpuMode){}[0]
|
||||
final fun com.compose.sdl/fileManagerName(): kotlin/String // com.compose.sdl/fileManagerName|fileManagerName(){}[0]
|
||||
final fun com.compose.sdl/hasComposeResource(kotlin/String): kotlin/Boolean // com.compose.sdl/hasComposeResource|hasComposeResource(kotlin.String){}[0]
|
||||
final fun com.compose.sdl/injectKey(kotlin/Int, kotlin/Boolean) // com.compose.sdl/injectKey|injectKey(kotlin.Int;kotlin.Boolean){}[0]
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import androidx.compose.ui.geometry.Offset
|
||||
|
||||
/* Actuals for the vendored `DragAndDrop.kt` expect classes.
|
||||
* Backed by SDL3's SDL_EVENT_DROP_* stream (file / text / begin / position /
|
||||
* complete) - see Sdl3DragAndDropOwner + SDL3EventMapper for the pump side.
|
||||
* complete) - see Sdl3DragAndDropOwner + AppEvent.kt for the pump side.
|
||||
*
|
||||
* DragAndDropTransferData carries the payload a drop into the window
|
||||
* delivered: zero or more file paths (SDL_EVENT_DROP_FILE) plus an optional
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import androidx.compose.ui.node.ModifierNodeElement
|
||||
|
||||
/** The per-window DragAndDropManager backing ComposeOwner. Holds a root
|
||||
* DragAndDropNode installed on the root LayoutNode via [modifier]; the SDL
|
||||
* event pump (see SDL3EventMapper + ComposeWindow) drives [handleDrop] which
|
||||
* event pump (see AppEvent.kt + ComposeWindow) drives [handleDrop] which
|
||||
* accumulates BEGIN → FILE / TEXT / POSITION → COMPLETE into a single
|
||||
* DragAndDropEvent and dispatches through the node tree.
|
||||
*
|
||||
|
||||
@@ -8,8 +8,8 @@ package androidx.compose.ui.input.key
|
||||
|
||||
/**
|
||||
* Project [Key] actual - assigns a unique sequential Long to each named
|
||||
* key. SDL3EventMapper picks the right `Key.X` by switch on SDL scancode
|
||||
* (`kKeyForScancode` in `SDL3EventMapper.kt`). Comparison works because
|
||||
* key. The SDL event mapper picks the right `Key.X` by switch on SDL scancode
|
||||
* (`kKeyForScancode` in `AppEvent.kt`). Comparison works because
|
||||
* Key is a value class - `Key(42L) == Key(42L)`.
|
||||
*/
|
||||
@kotlin.jvm.JvmInline
|
||||
|
||||
+2
-2
@@ -213,10 +213,10 @@ private fun sdlWriteEntry(entry: ClipEntry?) {
|
||||
// The SDL3-backed Clipboard implementation. Singleton because SDL's clipboard
|
||||
// is process-global - allocating a new one per Window() would only waste
|
||||
// memory. Consumed by :desktop-native-window when seeding LocalClipboard.
|
||||
private object SDL3Clipboard : Clipboard {
|
||||
private object Sdl3Clipboard : Clipboard {
|
||||
override suspend fun getClipEntry(): ClipEntry? = sdlReadEntry()
|
||||
override suspend fun setClipEntry(clipEntry: ClipEntry?) { sdlWriteEntry(clipEntry) }
|
||||
override val nativeClipboard: NativeClipboard get() = nativeClipboardSentinel
|
||||
}
|
||||
|
||||
fun platformClipboard(): Clipboard = SDL3Clipboard
|
||||
fun platformClipboard(): Clipboard = Sdl3Clipboard
|
||||
|
||||
+2
-3
@@ -9,7 +9,7 @@ import kotlinx.cinterop.*
|
||||
import sdl3.*
|
||||
|
||||
// ==================
|
||||
// MARK: SDL3EventMapper
|
||||
// MARK: AppEvent + the SDL3 event mapper
|
||||
// ==================
|
||||
|
||||
/** Events carry the SDL window id they belong to (0 = unknown - injected test
|
||||
@@ -83,8 +83,7 @@ fun pollEvents(): List<AppEvent> {
|
||||
}
|
||||
|
||||
private fun mapEvent(e: SDL_Event): AppEvent? {
|
||||
val type = e.type
|
||||
return when (type) {
|
||||
return when (e.type) {
|
||||
SDL_EVENT_QUIT -> AppEvent.Quit
|
||||
|
||||
SDL_EVENT_MOUSE_BUTTON_DOWN -> {
|
||||
@@ -7,8 +7,6 @@ import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.input.key.KeyEvent
|
||||
import kotlinx.cinterop.COpaquePointer
|
||||
import kotlinx.cinterop.reinterpret
|
||||
import kotlinx.cinterop.toKString
|
||||
import sdl3.SDL_GetRendererName
|
||||
import sdl3.SDL_MaximizeWindow
|
||||
import sdl3.SDL_MinimizeWindow
|
||||
import sdl3.SDL_RaiseWindow
|
||||
@@ -36,7 +34,7 @@ import sdl3.SDL_SetWindowTitle
|
||||
them subscribes the caller to recomposition. The setter methods
|
||||
call into SDL and also push the new value into the snapshot. */
|
||||
class ComposeNativeWindow constructor(
|
||||
private val backend: SDL3Backend,
|
||||
private val backend: Sdl3Backend,
|
||||
val gpuMode: GpuMode,
|
||||
initialTitle: String,
|
||||
) {
|
||||
|
||||
@@ -16,7 +16,7 @@ package com.compose.sdl
|
||||
|
||||
/** Create the render backend for the selected [GpuMode]; null when the
|
||||
backend can't initialise (caller falls back / reports). */
|
||||
expect fun createRenderBackend(inSdl: SDL3Backend, inGpu: GpuMode): RenderBackend?
|
||||
expect fun createRenderBackend(inSdl: Sdl3Backend, inGpu: GpuMode): RenderBackend?
|
||||
|
||||
/** The renderer module's per-OS default GpuMode (used for GpuMode.Auto). */
|
||||
expect fun rendererPreferredGpuMode(): GpuMode
|
||||
|
||||
+3
-3
@@ -4,10 +4,10 @@ import kotlinx.cinterop.*
|
||||
import sdl3.*
|
||||
|
||||
// ==================
|
||||
// MARK: SDL3Backend
|
||||
// MARK: Sdl3Backend
|
||||
// ==================
|
||||
|
||||
class SDL3Backend(
|
||||
class Sdl3Backend(
|
||||
private val title: String = "ComposeNativeSDL3",
|
||||
private val width: Int = 800,
|
||||
private val height: Int = 600,
|
||||
@@ -29,7 +29,7 @@ class SDL3Backend(
|
||||
) {
|
||||
init {
|
||||
require(gpuMode !is GpuMode.Auto) {
|
||||
"SDL3Backend received GpuMode.Auto - resolve via preferredGpuMode() first"
|
||||
"Sdl3Backend received GpuMode.Auto - resolve via preferredGpuMode() first"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@ import com.compose.sdl.renderer.skia.SkiaBridge
|
||||
// MARK: Linux GPU defaults
|
||||
// ==================
|
||||
|
||||
internal actual fun makeMetalBridge(backend: SDL3Backend): SkiaBridge? = null
|
||||
internal actual fun makeMetalBridge(backend: Sdl3Backend): SkiaBridge? = null
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.compose.sdl
|
||||
import com.compose.sdl.renderer.skia.SkiaBridge
|
||||
import com.compose.sdl.renderer.skia.SkiaMetalBridge
|
||||
|
||||
internal actual fun makeMetalBridge(backend: SDL3Backend): SkiaBridge? {
|
||||
internal actual fun makeMetalBridge(backend: Sdl3Backend): SkiaBridge? {
|
||||
val bridge = SkiaMetalBridge(backend)
|
||||
return if (bridge.init()) bridge else null
|
||||
}
|
||||
+1
-1
@@ -37,7 +37,7 @@ import sdl3.SDL_Metal_GetLayer
|
||||
per frame, so we tear the BackendRenderTarget + Surface down every frame
|
||||
(cheap - the DirectContext + device + queue persist). */
|
||||
@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
|
||||
internal class SkiaMetalBridge(private val backend: SDL3Backend) : SkiaBridge {
|
||||
internal class SkiaMetalBridge(private val backend: Sdl3Backend) : SkiaBridge {
|
||||
private var mDevice: MTLDeviceProtocol? = null
|
||||
private var mQueue: MTLCommandQueueProtocol? = null
|
||||
private var mLayer: CAMetalLayer? = null
|
||||
|
||||
@@ -7,7 +7,7 @@ import kotlin.experimental.ExperimentalNativeApi
|
||||
// MARK: Metal bridge factory (skia-only)
|
||||
// ==================
|
||||
|
||||
internal expect fun makeMetalBridge(backend: SDL3Backend): SkiaBridge?
|
||||
internal expect fun makeMetalBridge(backend: Sdl3Backend): SkiaBridge?
|
||||
|
||||
actual fun rendererPreferredGpuMode(): GpuMode {
|
||||
@OptIn(ExperimentalNativeApi::class)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import com.compose.sdl.renderer.skia.SkiaRenderBackend
|
||||
actual delegates here when Skia is the selected renderer). Mirrors the
|
||||
SDL3 module's createRenderBackend / rendererPreferredGpuMode in the same
|
||||
package; exactly one renderer module is included per target. */
|
||||
actual fun createRenderBackend(inSdl: SDL3Backend, inGpu: GpuMode): RenderBackend? {
|
||||
actual fun createRenderBackend(inSdl: Sdl3Backend, inGpu: GpuMode): RenderBackend? {
|
||||
val vResolved = if (inGpu is GpuMode.Auto) rendererPreferredGpuMode() else inGpu
|
||||
return try {
|
||||
SkiaRenderBackend(inSdl, vResolved)
|
||||
|
||||
+2
-6
@@ -4,13 +4,9 @@ import com.compose.sdl.*
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import org.jetbrains.skia.BackendRenderTarget
|
||||
import org.jetbrains.skia.Bitmap
|
||||
import org.jetbrains.skia.Canvas
|
||||
import org.jetbrains.skia.ColorAlphaType
|
||||
import org.jetbrains.skia.ColorType
|
||||
import org.jetbrains.skia.DirectContext
|
||||
import org.jetbrains.skia.Image
|
||||
import org.jetbrains.skia.ImageInfo
|
||||
import org.jetbrains.skia.Surface
|
||||
import org.jetbrains.skia.SurfaceColorFormat
|
||||
import org.jetbrains.skia.SurfaceOrigin
|
||||
@@ -28,7 +24,7 @@ import sdl3.SDL_GL_SwapWindow
|
||||
Resize: tear down and rebuild the BackendRenderTarget + Surface; the
|
||||
DirectContext is reused. The default GL framebuffer (id 0) is wrapped
|
||||
directly; we don't manage an offscreen FBO. */
|
||||
internal class SkiaGLBridge(private val backend: SDL3Backend) : SkiaBridge {
|
||||
internal class SkiaGLBridge(private val backend: Sdl3Backend) : SkiaBridge {
|
||||
private var mContext: DirectContext? = null
|
||||
private var mRT: BackendRenderTarget? = null
|
||||
private var mSurface: Surface? = null
|
||||
@@ -40,7 +36,7 @@ internal class SkiaGLBridge(private val backend: SDL3Backend) : SkiaBridge {
|
||||
|
||||
A GL context is per-window but "current" is per-THREAD state, so with more
|
||||
than one window open the last one to touch GL owns the thread. SDL makes a
|
||||
context current once at creation (SDL3Backend.init) and nothing re-bound it
|
||||
context current once at creation (Sdl3Backend.init) and nothing re-bound it
|
||||
per frame, so window A issued its draw and swap against window B's context:
|
||||
silent corruption while both live, and a hard crash (SIGSEGV in present)
|
||||
the moment B is destroyed and the current context is left dangling.
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.jetbrains.skia.Color as SkColor
|
||||
elevation shadows ride behind it via skiaLeafDrawer + the SkiaBackedCanvas
|
||||
manual-vendor. */
|
||||
internal class SkiaRenderBackend(
|
||||
private val sdl: SDL3Backend,
|
||||
private val sdl: Sdl3Backend,
|
||||
private val gpuMode: GpuMode,
|
||||
) : RenderBackend {
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import sdl3.*
|
||||
/** Owns the CPU pixel buffer Skia draws into, plus the streaming SDL_Texture
|
||||
used to push that buffer onto the window. All three (buffer, Skia surface,
|
||||
SDL texture) get reallocated when the window resizes. */
|
||||
internal class SkiaSurfaceBridge(private val backend: SDL3Backend) : SkiaBridge {
|
||||
internal class SkiaSurfaceBridge(private val backend: Sdl3Backend) : SkiaBridge {
|
||||
private var mWidth = 0
|
||||
private var mHeight = 0
|
||||
private var mPixels: CPointer<UByteVar>? = null
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ import com.compose.sdl.renderer.skia.SkiaBridge
|
||||
// No Metal on Windows. The default Skia bridge is CPU raster (GpuMode.CpuRaster →
|
||||
// SkiaSurfaceBridge), so no GPU-context bridge is provided here yet. A D3D/Vulkan
|
||||
// bridge can be added later (Route 1a milestone 2).
|
||||
internal actual fun makeMetalBridge(backend: SDL3Backend): SkiaBridge? = null
|
||||
internal actual fun makeMetalBridge(backend: Sdl3Backend): SkiaBridge? = null
|
||||
|
||||
@@ -36,7 +36,7 @@ internal fun AnimationScreen() {
|
||||
"animation.core",
|
||||
"animate*AsState, AnimationSpec (tween / spring / repeatable / infiniteRepeatable), " +
|
||||
"Easing (Linear, FastOutSlowIn, CubicBezier), rememberInfiniteTransition. " +
|
||||
"All driven by the SDL3FrameClock via withFrameNanos.",
|
||||
"All driven by the Sdl3FrameClock via withFrameNanos.",
|
||||
)
|
||||
|
||||
// ============
|
||||
|
||||
@@ -31,7 +31,7 @@ internal fun GestureScreen() {
|
||||
ScreenTitle(
|
||||
"pointerInput + gesture DSL",
|
||||
"Suspending Modifier.pointerInput { } with detectTapGestures / detectDragGestures " +
|
||||
"on top. Awaits resume on the SDL3FrameClock; no per-event polling.",
|
||||
"on top. Awaits resume on the Sdl3FrameClock; no per-event polling.",
|
||||
)
|
||||
|
||||
// ============
|
||||
|
||||
+1
-1
@@ -278,7 +278,7 @@ internal object IconCodec {
|
||||
}
|
||||
|
||||
/** An 8-byte little-endian [width][height] header + straight-alpha RGBA - the
|
||||
format the runtime (WindowIcon.kt / SDL3Backend) reads. */
|
||||
format the runtime (WindowIcon.kt / Sdl3Backend) reads. */
|
||||
fun rgbaBlob(inW: Int, inH: Int, inRgba: ByteArray): ByteArray {
|
||||
val vOut = ByteArray(8 + inRgba.size)
|
||||
le32(vOut, 0, inW)
|
||||
|
||||
Reference in New Issue
Block a user