Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/build-natives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ jobs:
shell: cmd
run: call fs-watcher\src\main\native\windows\build.bat

- name: Build share Windows DLLs
if: steps.natives-cache.outputs.cache-hit != 'true'
shell: cmd
run: call share\src\main\native\windows\build.bat

- name: Build decorated-window-tao Windows DLLs
if: steps.natives-cache.outputs.cache-hit != 'true'
shell: cmd
Expand All @@ -144,6 +149,7 @@ jobs:
"media-control/nucleus_media_control_windows.dll"
"spellcheck/nucleus_spellcheck.dll"
"fs-watcher/nucleus_fs_watcher.dll"
"share/nucleus_share.dll"
"decorated-window-tao/nucleus_tao.dll"
"decorated-window-tao/nucleus_tao_windows_deco.dll"
"decorated-window-tao/nucleus_tao_gl.dll"
Expand Down Expand Up @@ -263,6 +269,10 @@ jobs:
if: steps.natives-cache.outputs.cache-hit != 'true'
run: bash fs-watcher/src/main/native/macos/build.sh

- name: Build share macOS dylibs
if: steps.natives-cache.outputs.cache-hit != 'true'
run: bash share/src/main/native/macos/build.sh

- name: Build decorated-window-tao macOS dylibs
if: steps.natives-cache.outputs.cache-hit != 'true'
run: bash decorated-window-tao/src/main/native/macos/build.sh
Expand Down Expand Up @@ -290,6 +300,7 @@ jobs:
"media-control/libnucleus_media_control_macos.dylib"
"spellcheck/libnucleus_spellcheck.dylib"
"fs-watcher/libnucleus_fs_watcher.dylib"
"share/libnucleus_share.dylib"
"decorated-window-tao/libnucleus_tao.dylib"
"decorated-window-tao/libnucleus_tao_metal.dylib"
"decorated-window-tao/libnucleus_tao_dnd.dylib"
Expand Down Expand Up @@ -423,6 +434,10 @@ jobs:
if: steps.natives-cache.outputs.cache-hit != 'true'
run: bash fs-watcher/src/main/native/linux/build.sh

- name: Build share Linux native libraries
if: steps.natives-cache.outputs.cache-hit != 'true'
run: bash share/src/main/native/linux/build.sh

- name: Build decorated-window-tao Linux native libraries
if: steps.natives-cache.outputs.cache-hit != 'true'
run: bash decorated-window-tao/src/main/native/linux/build.sh
Expand All @@ -444,6 +459,7 @@ jobs:
"scheduler/libnucleus_scheduler_linux.so"
"media-control/libnucleus_media_control_linux.so"
"fs-watcher/libnucleus_fs_watcher.so"
"share/libnucleus_share.so"
"decorated-window-tao/libnucleus_tao.so"
"decorated-window-tao/libnucleus_tao_egl.so"
"decorated-window-tao/libnucleus_tao_linux_widget.so"
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/pre-merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ jobs:
"fs-watcher/src/main/resources/nucleus/native/darwin-x64/libnucleus_fs_watcher.dylib"
"fs-watcher/src/main/resources/nucleus/native/linux-x64/libnucleus_fs_watcher.so"
"fs-watcher/src/main/resources/nucleus/native/linux-aarch64/libnucleus_fs_watcher.so"
"share/src/main/resources/nucleus/native/win32-x64/nucleus_share.dll"
"share/src/main/resources/nucleus/native/win32-aarch64/nucleus_share.dll"
"share/src/main/resources/nucleus/native/darwin-aarch64/libnucleus_share.dylib"
"share/src/main/resources/nucleus/native/darwin-x64/libnucleus_share.dylib"
"share/src/main/resources/nucleus/native/linux-x64/libnucleus_share.so"
"share/src/main/resources/nucleus/native/linux-aarch64/libnucleus_share.so"
"notification-macos/src/main/resources/nucleus/native/darwin-aarch64/libnucleus_notification.dylib"
"notification-macos/src/main/resources/nucleus/native/darwin-x64/libnucleus_notification.dylib"
"service-management-macos/src/main/resources/nucleus/native/darwin-aarch64/libnucleus_service_management.dylib"
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/publish-maven.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ jobs:
"fs-watcher/src/main/resources/nucleus/native/darwin-x64/libnucleus_fs_watcher.dylib"
"fs-watcher/src/main/resources/nucleus/native/linux-x64/libnucleus_fs_watcher.so"
"fs-watcher/src/main/resources/nucleus/native/linux-aarch64/libnucleus_fs_watcher.so"
"share/src/main/resources/nucleus/native/win32-x64/nucleus_share.dll"
"share/src/main/resources/nucleus/native/win32-aarch64/nucleus_share.dll"
"share/src/main/resources/nucleus/native/darwin-aarch64/libnucleus_share.dylib"
"share/src/main/resources/nucleus/native/darwin-x64/libnucleus_share.dylib"
"share/src/main/resources/nucleus/native/linux-x64/libnucleus_share.so"
"share/src/main/resources/nucleus/native/linux-aarch64/libnucleus_share.so"
"notification-macos/src/main/resources/nucleus/native/darwin-aarch64/libnucleus_notification.dylib"
"notification-macos/src/main/resources/nucleus/native/darwin-x64/libnucleus_notification.dylib"
"service-management-macos/src/main/resources/nucleus/native/darwin-aarch64/libnucleus_service_management.dylib"
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Published releases are `2.5.x` (latest tag `v2.5.0`). Do not treat `IDEAL_API.md
- `autolaunch` - Start at login (Win32/MSIX/SMAppService/systemd/Flatpak portal)
- `scheduler` / `scheduler-testing` - OS-scheduled background tasks (Task Scheduler / launchd / systemd) + test doubles
- `fs-watcher` - Native filesystem watcher over the Rust `notify` crate. One native watcher per `FsWatcher` (all registrations share it; events are routed back by root in `lib.rs`, so an inotify instance is per watcher, not per path — #571). The backend is handed the canonical root on macOS and Linux (one watch per real directory; inotify keys watches by inode and `notify` keeps one spelling per descriptor, so aliases must share it — Kotlin projects events back onto each registration's spelling), the registered spelling on Windows (`canonicalize()` yields `\\?\` paths there). On macOS the Rust side also feeds FSEvents through `FsEventsNormalizer` before the debouncer: FSEvents reports an inode's *accumulated* flags (a rename of an old file arrives as `Create`+`Rename`+`Modify` on the gone path), which otherwise folds renames into a bare `Created(new)` and deletes into `Modified` (#570). Renames the backend cannot pair are `Removed(old)` + `Created(new)`, never dropped; `Raw` delivery never emits `Moved`
- `share` - Native share sheet, the repo's first **Kotlin Multiplatform library** (inspired by `robius-share`, THIRD_PARTY_NOTICES §5). `commonMain` holds the API (`ShareSheet.share { title; text(); url(); file() }`, suspend, throws `ShareException(ShareError)`); Android (`Intent.ACTION_SEND` chooser), iOS (`UIActivityViewController`) and the web (`js` + `wasmJs` sharing `webMain`, Web Share API through `js()` bodies so one source compiles for both; needs a user gesture, file items must be fetchable URIs) are pure Kotlin, only the `jvm` target goes through the Rust JNI crate (Windows `DataTransferManager` interop, macOS `NSSharingServicePicker`, Linux XDG portal over a hand-rolled D-Bus client). The KMP module keeps the JVM JNI layout (`src/main/native`, `src/main/resources` added to `jvmMain`) so CI globs stay uniform; `nucleus.native-module` wires `jvmProcessResources` when the multiplatform plugin is applied (target must be named `jvm`). Android files are copied under `cacheDir/nucleus-share` and served by the library's own `NucleusShareProvider` (`${applicationId}.nucleus.share`, no AndroidX), which also tracks the resumed activity. Desktop parents: `ShareSheet.share(request, ShareParent.Windows(hwnd) / MacOs(nsWindow, anchor) / Linux(portalParent, keepAlive))`; apps on `nucleus-application` call `NucleusWindow.share(request, anchor)` (`compileOnly` dependency, like FileKit), which resolves them from the Tao window. A Wayland `xdg_foreign` export must outlive the portal dialog while `share` returns before it closes: `keepAlive` is handed to the crate as a `java.lang.Runnable` (`Completion`, run on `Drop`, so every path releases it) that the Linux portal thread drops once the portal answers; the Kotlin side closes it itself (once) when the share fails or is cancelled before the native call. Kotlin 2.4 compiles the iOS klibs on any host, so iOS code is checked on Windows too; in a KMP module the aggregate `detekt` is NO-SOURCE — the root build wires the per-source-set `detekt*MainSourceSet` tasks into `check`
- `service-management-macos` - macOS `SMAppService` — login items, launch agents, daemons
- `native-ssl` / `native-http` / `native-http-okhttp` / `native-http-ktor` - OS trust store integration
- `linux-hidpi` - Native HiDPI scale detection on Linux
Expand All @@ -43,7 +44,7 @@ Published releases are `2.5.x` (latest tag `v2.5.0`). Do not treat `IDEAL_API.md
- `decorated-window-material3` - Material 3 color mapping
- `plugin-build/plugin` - Gradle plugin for packaging & distribution
- `buildSrc` - Build-only convention plugins (`nucleus.native-module`: the shared `buildNative*` wiring for every JNI module)
- `examples/` - Demo & sample applications: `nucleus-demo` (flagship), `compose-demo`, `tao-demo`, `swing-tao-demo`, `jewel-demo`, `cmp-demo` (KMP), `window-scaffold-demo`, `satellite-demo` (satellite workspace: floating palettes following the focused document, docking into a `DockLayout`, drag-to-dock, layout snapshots), `tabs-demo` (Chrome-like tabs: tear-off, merge, reorder, state following a tab between windows, layout snapshots), `jewel-tabs-demo` (the same tab workspace wearing Jewel's `TabStrip` / `TabData.Editor` chrome), `tab-satellites-demo` (the two archetypes composed: one `SatelliteWorkspace` per tab window, palettes drawing the window's selected tab), `reader-dock-demo` (a right-to-left book reader composing **both** archetypes: its seforim are tabs and its every pane is a satellite — layered right side with per-pane widths, `sideOrder` putting the right side outside the bottom one, the reader's own 1 dp + 5 dp-grip splitters and hover headers, Classic/Islands styles, one dock per tab window hung on `TabWindows(windowBodyWrapper)` so the strip stays the top of the window and a tab change touches no panel — the target layout of SeforimApp), `zstd-demo`, `scheduler-demo`, `service-management-demo`, `system-info-demo`, `fs-watcher-smoke`, `orphan-reflect-smoke`, `extra-launcher-demo`, `macos-appex-demo` (a macOS Network Extension `.appex` embedded and signed through `macOS { appExtensions { } }`), `tao-native-test` (GraalVM + SLF4J fixture), `benchmark-demo` (JIT-vs-GraalVM-O3, ports under `ports/`), `gstreamer-demo` / `mediafoundation-demo` / `avfoundation-demo` (platform video into a `TextureView`), plus `shared` (Compose helper used by the tao demos). `native-proxy` and `spellcheck` directories on disk are **not** on `main` — ignore them unless the matching feature branch is checked out.
- `examples/` - Demo & sample applications: `nucleus-demo` (flagship), `compose-demo`, `tao-demo`, `swing-tao-demo`, `jewel-demo`, `cmp-demo` (KMP), `window-scaffold-demo`, `satellite-demo` (satellite workspace: floating palettes following the focused document, docking into a `DockLayout`, drag-to-dock, layout snapshots), `tabs-demo` (Chrome-like tabs: tear-off, merge, reorder, state following a tab between windows, layout snapshots), `jewel-tabs-demo` (the same tab workspace wearing Jewel's `TabStrip` / `TabData.Editor` chrome), `tab-satellites-demo` (the two archetypes composed: one `SatelliteWorkspace` per tab window, palettes drawing the window's selected tab), `reader-dock-demo` (a right-to-left book reader composing **both** archetypes: its seforim are tabs and its every pane is a satellite — layered right side with per-pane widths, `sideOrder` putting the right side outside the bottom one, the reader's own 1 dp + 5 dp-grip splitters and hover headers, Classic/Islands styles, one dock per tab window hung on `TabWindows(windowBodyWrapper)` so the strip stays the top of the window and a tab change touches no panel — the target layout of SeforimApp), `share-demo` (every `ShareSheet` payload on the desktop bridge; `-Dshare.demo.auto=<button>` presses one at startup), `share-web-demo` (the same on the Web Share API, Kotlin/JS), `zstd-demo`, `scheduler-demo`, `service-management-demo`, `system-info-demo`, `fs-watcher-smoke`, `orphan-reflect-smoke`, `extra-launcher-demo`, `macos-appex-demo` (a macOS Network Extension `.appex` embedded and signed through `macOS { appExtensions { } }`), `tao-native-test` (GraalVM + SLF4J fixture), `benchmark-demo` (JIT-vs-GraalVM-O3, ports under `ports/`), `gstreamer-demo` / `mediafoundation-demo` / `avfoundation-demo` (platform video into a `TextureView`), plus `shared` (Compose helper used by the tao demos). `native-proxy` and `spellcheck` directories on disk are **not** on `main` — ignore them unless the matching feature branch is checked out.

## Build & Run

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ Each module is published independently to Maven Central — use them together or
| `nucleus.scheduler` | OS-scheduled background tasks (Task Scheduler / launchd / systemd) |
| `nucleus.scheduler-testing` | Test doubles for `scheduler` |
| `nucleus.fs-watcher` | Native filesystem watcher |
| `nucleus.share` | Native share sheet, Kotlin Multiplatform (Android, iOS, macOS, Windows, Linux, web) |
| `nucleus.service-management-macos` | macOS `SMAppService` — login items, launch agents, daemons |
| `nucleus.native-ssl` | OS trust store integration |
| `nucleus.native-http` | HTTP client with native SSL |
Expand Down
25 changes: 22 additions & 3 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ Full license texts are in [`licenses/`](licenses/):
| [`licenses/LICENSE-APACHE-2.0.txt`](licenses/LICENSE-APACHE-2.0.txt) | Gradle plugin (derived), `tao`, AccessKit crates (Apache option) |
| [`licenses/LICENSE-MIT-accesskit.txt`](licenses/LICENSE-MIT-accesskit.txt) | AccessKit crates (MIT option) |
| [`licenses/LICENSE-BSD-3-Clause-angle.txt`](licenses/LICENSE-BSD-3-Clause-angle.txt) | ANGLE runtime libraries and EGL/KHR headers |
| [`licenses/LICENSE-MIT-robius.txt`](licenses/LICENSE-MIT-robius.txt) | `robius-share` (derived source in `share`) |

Both artifacts that redistribute third-party code ship this file and `licenses/` inside their JAR
under `META-INF/` (`nucleus.decorated-window-tao` and the `dev.nucleusframework` Gradle plugin), as
required by Apache-2.0 §4(a).
The artifacts that redistribute third-party code ship this file and `licenses/` inside their JAR
under `META-INF/` (`nucleus.decorated-window-tao`, the desktop JAR of `nucleus.share` and the
`dev.nucleusframework` Gradle plugin), as required by Apache-2.0 §4(a) and the MIT notice clause.

---

Expand Down Expand Up @@ -97,6 +98,24 @@ Khronos/ANGLE EGL headers used at build time

---

## 5. robius-share — derived source, compiled into a shipped binary (MIT)

The `share` module's desktop bridge follows `robius-share`'s payload model and per-platform
strategies (Windows `DataTransferManager` interop, macOS `NSSharingServicePicker`, the Linux XDG
portal), and its minimal D-Bus client is ported from it:

| Nucleus file | Derived from |
|--------------|--------------|
| `share/src/main/native/src/platform/linux/{mod,dbus}.rs` | `crates/share/src/sys/linux.rs`, `crates/share/src/sys/linux/dbus.rs` |
| `share/src/main/native/src/platform/{windows,macos}.rs` | `crates/share/src/sys/{windows,macos}.rs` |
| `share/src/commonMain/kotlin/dev/nucleusframework/share/MimeTypes.kt` | `primaryMimeType` in `crates/share/src/sys/android/ShareSheet.java` |

- Project: Project Robius — https://github.com/project-robius/robius (commit `71966dc2`)
- License: MIT — [`licenses/LICENSE-MIT-robius.txt`](licenses/LICENSE-MIT-robius.txt)
- Copyright (c) 2023-2025 Project Robius

---

## Build-time tools (not redistributed)

These are resolved on the build machine and are **not** shipped inside any Nucleus artifact. They
Expand Down
22 changes: 18 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import org.apache.tools.ant.taskdefs.condition.Os
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension

plugins {
// `clean` (deletes the root build directory) comes from here: Kotlin/JS applies the
// lifecycle plugin to the root project, which forbids registering a `clean` of our own.
base
alias(libs.plugins.kotlin) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.androidKotlinMultiplatformLibrary) apply false
alias(libs.plugins.vanniktechMavenPublish) apply false
alias(libs.plugins.graalvmNative) apply false
// Freezes public ABI for every published library module: `apiCheck` fails on
Expand Down Expand Up @@ -156,6 +160,20 @@ subprojects {
config.setFrom(rootProject.files("config/detekt/detekt.yml"))
}

// In a multiplatform module the aggregate `detekt` task has no source: the
// analysis runs per source set, and only these tasks enforce the KDoc rules.
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
tasks.named("check") {
dependsOn(
tasks.matching {
it.name.startsWith("detekt") &&
!it.name.startsWith("detektBaseline") &&
it.name.endsWith("MainSourceSet")
},
)
}
}

tasks.withType<Detekt>().configureEach {
jvmTarget.set("25")
}
Expand Down Expand Up @@ -190,10 +208,6 @@ tasks.withType<DependencyUpdatesTask> {

fun String.isNonStable() = "^[0-9,.v-]+(-r)?$".toRegex().matches(this).not()

tasks.register("clean", Delete::class.java) {
delete(rootProject.layout.buildDirectory)
}

tasks.register("cleanNativeLibs", Delete::class.java) {
group = "cleanup"
description = "Cleans all native libraries from resources and system cache"
Expand Down
Loading
Loading