diff --git a/desktop/build.gradle.kts b/desktop/build.gradle.kts index 931728d..bd10132 100644 --- a/desktop/build.gradle.kts +++ b/desktop/build.gradle.kts @@ -1,13 +1,37 @@ // SleepyOwl for the Linux desktop (LINUX_PLAN.md): windows, desktop screens, later the mpv player and system integration. // Run: ./gradlew :desktop:run, or tools/linux/desktop.sh without Gradle around the process. +// Package: ./gradlew :desktop:packageDeb → desktop/build/deb/sleepyowl__amd64.deb (LINUX_PLAN.md L10). +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.attribute.PosixFilePermissions +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.compose) alias(libs.plugins.compose.multiplatform) } +/** The desktop app's version: the About screen, the log, the .deb. */ +val appVersion = "0.1.0" + kotlin { jvmToolchain(21) } +// BuildInfo.VERSION from appVersion: one place for the number. +val buildInfo = tasks.register("buildInfo") { + val version = appVersion + val out = layout.buildDirectory.dir("generated/buildinfo") + inputs.property("version", version) + outputs.dir(out) + doLast { + out.get().file("BuildInfo.kt").asFile.apply { parentFile.mkdirs() }.writeText( + "package ru.stenfredd.sleepyowl.desktop\n\n/** Generated by desktop/build.gradle.kts. */\nobject BuildInfo {\n const val VERSION = \"$version\"\n}\n", + ) + } +} +sourceSets.main { kotlin.srcDir(buildInfo) } + dependencies { implementation(project(":ui:shared")) implementation(project(":playback:engine-mpv")) @@ -32,9 +56,26 @@ compose.desktop { application { mainClass = "ru.stenfredd.sleepyowl.desktop.MainKt" jvmArgs += awtOpens + nativeDistributions { + // jpackage of JDK 21 with a jlink'd JRE inside: createDistributable → build/compose/binaries/main/app/sleepyowl. + // The .deb around it is ours (packageDeb below): jpackage's own one can't depend on libmpv2. + javaHome = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(21) }.get() + .metadata.installationPath.asFile.absolutePath + packageName = "sleepyowl" + packageVersion = appVersion + description = "Jellyfin client" + vendor = "StenFredd" + // suggestRuntimeModules gives java.instrument, jdk.security.auth (dbus-java), jdk.unsupported; jdeps can't see + // TLS (jdk.crypto.ec: the public address over https) or locale data (jdk.localedata: track languages in Russian). + modules("java.instrument", "jdk.security.auth", "jdk.unsupported", "jdk.crypto.ec", "jdk.localedata") + linux { iconFile = file("src/main/resources/icons/sleepyowl-256.png") } + } } } +// Licence texts of "О приложении": the TV's (app/src/main/assets/licenses) next to the desktop's own in resources/licenses. +tasks.processResources { from(rootProject.file("app/src/main/assets/licenses")) { into("licenses") } } + tasks.withType().configureEach { jvmArgs(awtOpens) } // Classpath into a file: tools/linux/desktop.sh starts the app without Gradle. @@ -45,3 +86,75 @@ tasks.register("desktopClasspath") { outputs.file(out) doLast { out.get().asFile.writeText(cp.joinToString(":")) } } + +/** + * The .deb: jpackage's app image in /opt/sleepyowl, `sleepyowl` in /usr/bin, the menu entry and the icons. The Debian + * version gets the build time (0.1.0-202610271530), so `sudo apt install ./sleepyowl_*.deb` always takes a new build as + * an update. Menus and icon caches refresh by dpkg's triggers (desktop-file-utils, hicolor-icon-theme): no scripts. + */ +abstract class PackageDeb : DefaultTask() { + @get:InputDirectory abstract val appImage: DirectoryProperty + @get:InputFile abstract val desktopFile: RegularFileProperty + @get:InputDirectory abstract val icons: DirectoryProperty + @get:Input abstract val version: Property + @get:Input abstract val maintainer: Property + @get:Input abstract val depends: ListProperty + @get:OutputDirectory abstract val outDir: DirectoryProperty + @get:Inject abstract val exec: ExecOperations + @get:Inject abstract val fs: FileSystemOperations + + @TaskAction fun build() { + val debVersion = "${version.get()}-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")) + val root = temporaryDir.resolve("root") + fs.delete { delete(root) } + fs.copy { from(appImage); into(root.resolve("opt/sleepyowl")) } + root.resolve("usr/bin").mkdirs() + Files.createSymbolicLink(root.resolve("usr/bin/sleepyowl").toPath(), Path.of("../../opt/sleepyowl/bin/sleepyowl")) + fs.copy { from(desktopFile); into(root.resolve("usr/share/applications")) } + icons.get().asFile.listFiles()!!.forEach { png -> + val size = Regex("sleepyowl-(\\d+)\\.png").matchEntire(png.name)?.groupValues?.get(1) ?: return@forEach + fs.copy { from(png); into(root.resolve("usr/share/icons/hicolor/${size}x$size/apps")); rename { "sleepyowl.png" } } + } + // Debian's modes whatever the umask: 755 for directories and programs, 644 for the rest. + root.walkTopDown().filter { !Files.isSymbolicLink(it.toPath()) }.forEach { + Files.setPosixFilePermissions(it.toPath(), PosixFilePermissions.fromString(if (it.isDirectory || it.canExecute()) "rwxr-xr-x" else "rw-r--r--")) + } + val kb = root.walkTopDown().filter { it.isFile }.sumOf { it.length() } / 1024 + root.resolve("DEBIAN").mkdirs() + root.resolve("DEBIAN/control").writeText( + """ + Package: sleepyowl + Version: $debVersion + Architecture: amd64 + Maintainer: ${maintainer.get()} + Installed-Size: $kb + Depends: ${depends.get().joinToString(", ")} + Section: video + Priority: optional + Description: Jellyfin client for movies and series + SleepyOwl plays movies and series from a Jellyfin server with mpv, in a window, full screen or in a + small always-on-top window. + """.trimIndent() + "\n", + ) + val out = outDir.get().asFile.apply { listFiles()?.forEach { it.delete() } }.resolve("sleepyowl_${debVersion}_amd64.deb") + exec.exec { commandLine("dpkg-deb", "--root-owner-group", "-Zxz", "--build", root, out) } + logger.lifecycle("Built $out") + } +} + +tasks.register("packageDeb") { + group = "distribution" + dependsOn("createDistributable") + appImage = layout.buildDirectory.dir("compose/binaries/main/app/sleepyowl") + desktopFile = layout.projectDirectory.file("packaging/sleepyowl.desktop") + icons = layout.projectDirectory.dir("src/main/resources/icons") + version = appVersion + maintainer = "StenFredd " + // libmpv2, libEGL and libOpenGL are loaded through JNA, so nothing finds them on its own; the rest is what dpkg-shlibdeps gave + // for the JRE's, Skiko's and JNA's libraries in L10 (Mint 22 / Ubuntu 24.04 names). + depends = listOf( + "libmpv2 (>= 0.37)", "libegl1", "libopengl0", "libgl1", "libc6 (>= 2.34)", "libstdc++6", "libfontconfig1 (>= 2.12.6)", + "libx11-6", "libxext6", "libxi6", "libxrender1", "libxtst6", "libasound2t64 | libasound2", + ) + outDir = layout.buildDirectory.dir("deb") +} diff --git a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/App.kt b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/App.kt index 9e650bf..cd0e4d3 100644 --- a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/App.kt +++ b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/App.kt @@ -186,8 +186,9 @@ private fun Navigation(stack: NavStack, session: JellyfinSession, onBack: () -> is Screen.Series -> Page(onBack) { SeriesScreen(screen, onOpen = ::open) } is Screen.Person -> Page(onBack) { PersonScreen(screen, onOpen = ::open) } is Screen.Items -> Page(onBack) { ItemsScreen(screen, onOpen = ::open) } - // The player opens in its own window; licences and the debug tour are the TV's. - is Screen.Player, is Screen.License, is Screen.Tour -> Unit + is Screen.License -> Page(onBack) { LicenseScreen(screen) } + // The player opens in its own window; the debug tour is the TV's. + is Screen.Player, is Screen.Tour -> Unit } } } diff --git a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/DesktopModule.kt b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/DesktopModule.kt index 9b3fbf9..00f57a9 100644 --- a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/DesktopModule.kt +++ b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/DesktopModule.kt @@ -58,10 +58,6 @@ private class DesktopUiPlatform(private val settings: DesktopSettings) : UiPlatf override val tourAvailable = false } -object BuildInfo { - const val VERSION = "0.1.0" -} - /** * Images: the API's client (`ServerRouting` sends them to the LAN address at home), a disk cache in * `~/.cache/sleepyowl/images` that keeps posters across launches, a memory cache of a quarter of the heap. diff --git a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/LicenseScreen.kt b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/LicenseScreen.kt new file mode 100644 index 0000000..be688c2 --- /dev/null +++ b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/LicenseScreen.kt @@ -0,0 +1,126 @@ +package ru.stenfredd.sleepyowl.desktop + +import androidx.compose.foundation.focusable +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.text.BasicText +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import ru.stenfredd.sleepyowl.ui.Screen +import ru.stenfredd.sleepyowl.ui.theme.AppColors +import ru.stenfredd.sleepyowl.ui.theme.AppDimens +import ru.stenfredd.sleepyowl.ui.theme.AppType + +/** A component of the desktop app and its licence; [asset] is the licence text in the `licenses/` resources. */ +@Immutable +data class Component(val name: String, val note: String?, val license: String, val asset: String) + +/** + * "О приложении" on the desktop: built from other parts than the TV (mpv instead of Media3 and libVLC, a JRE inside the + * package). The texts: the TV's `app/src/main/assets/licenses` (copied in by the build) and the desktop's own. + */ +object Licenses { + val app = Component("SleepyOwl", "это приложение", "GPL-3.0", "GPL-3.0.txt") + + val components = listOf( + Component("mpv, FFmpeg", "системная libmpv, движок воспроизведения", "GPL-2.0+", "GPL-2.0.txt"), + Component("OpenJDK", "Java внутри пакета", "GPL-2.0 + Classpath", "OpenJDK-GPL-2.0-CE.txt"), + Component("Jellyfin SDK", "Jellyfin, работа с сервером", "LGPL-3.0", "LGPL-3.0.txt"), + Component("Compose Multiplatform, Skiko", "JetBrains, интерфейс", "Apache 2.0", "Apache-2.0.txt"), + Component("Skia", "Google, графика внутри Skiko", "BSD-3-Clause", "Skia-BSD-3.txt"), + Component("AndroidX Lifecycle, DataStore", "Google", "Apache 2.0", "Apache-2.0.txt"), + Component("Kotlin, kotlinx", "JetBrains", "Apache 2.0", "Apache-2.0.txt"), + Component("Koin", "Kotzilla, связывание компонентов", "Apache 2.0", "Apache-2.0.txt"), + Component("Coil", "загрузка картинок", "Apache 2.0", "Apache-2.0.txt"), + Component("OkHttp", "Square, сеть", "Apache 2.0", "Apache-2.0.txt"), + Component("JNA", "вызовы libmpv, X11, OpenGL", "Apache 2.0", "Apache-2.0.txt"), + Component("dbus-java", "MPRIS и хранитель экрана", "MIT", "MIT.txt"), + Component("Шрифт Onest", null, "OFL 1.1", "Onest-OFL.txt"), + Component("Шрифт JetBrains Mono", null, "OFL 1.1", "JetBrainsMono-OFL.txt"), + ) +} + +/** Text of a licence; the wheel, ↑/↓ and PgUp/PgDn scroll it. */ +@Composable +fun LicenseScreen(screen: Screen.License) { + var paragraphs by remember { mutableStateOf(emptyList()) } + LaunchedEffect(screen.asset) { + paragraphs = withContext(Dispatchers.IO) { + runCatching { Licenses::class.java.getResourceAsStream("/licenses/${screen.asset}")!!.bufferedReader().use { it.readText() } } + .getOrDefault("Текст лицензии не найден.") + .split(Regex("""\n\s*\n""")) + // Hard-wrapped lines are joined: the screen wraps them itself. + .map { p -> p.trim().replace(Regex("""\s*\n\s*"""), " ") } + .filter { it.isNotEmpty() } + } + } + + val list = rememberLazyListState() + val scope = rememberCoroutineScope() + val requester = remember { FocusRequester() } + val step = with(LocalDensity.current) { 120.dp.toPx() } + val page = with(LocalDensity.current) { 400.dp.toPx() } + LaunchedEffect(Unit) { runCatching { requester.requestFocus() } } + + LazyColumn( + state = list, + modifier = Modifier + .fillMaxSize() + .focusRequester(requester) + .onKeyEvent { e -> + if (e.type != KeyEventType.KeyDown) return@onKeyEvent false + val by = when (e.key) { + Key.DirectionDown -> step + Key.DirectionUp -> -step + Key.PageDown, Key.Spacebar -> page + Key.PageUp -> -page + else -> return@onKeyEvent false + } + scope.launch { list.animateScrollBy(by) } + true + } + .focusable(), + contentPadding = PaddingValues(start = AppDimens.CONTENT_START.dp, end = AppDimens.CONTENT_START.dp, top = AppDimens.CONTENT_TOP.dp, bottom = 80.dp), + ) { + item(key = "title", contentType = "title") { + Column(Modifier.padding(bottom = 18.dp)) { + BasicText(screen.name, style = AppType.Display.copy(fontSize = 26.sp)) + BasicText(screen.license, Modifier.padding(top = 6.dp), style = AppType.MonoLabel) + } + } + itemsIndexed(paragraphs, contentType = { _, _ -> "text" }) { _, p -> + BasicText( + p, + Modifier.widthIn(max = 720.dp).padding(bottom = 10.dp), + style = AppType.Body.copy(fontSize = 11.5.sp, lineHeight = 17.sp, color = AppColors.TextSecondary), + ) + } + } +} diff --git a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerFrame.kt b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerFrame.kt index 353ca1c..5b26272 100644 --- a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerFrame.kt +++ b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerFrame.kt @@ -71,7 +71,11 @@ internal class PlayerFrame(private val player: DesktopPlayer) { fun dispose() { saveTimer.stop() savePlace() + // A player with the focus (closed by ×, Ctrl+W, the menu, or a movie watched to its end) hands it to the + // library, not to whatever window the window manager picks. Played in the background, the focus stays put. + val hadFocus = window.isActive window.dispose() + if (hadFocus) player.showLibrary() } /** Puts the window in the player's mode as it changes, and the mini window in the video's proportions. */ diff --git a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerUi.kt b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerUi.kt index 184b5c6..eab49fb 100644 --- a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerUi.kt +++ b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerUi.kt @@ -565,8 +565,8 @@ internal fun PlayerContent( onOnTop = ::toggleOnTop, onLibrary = ::showLibrary, onClose = onClose, ) OsdLayout.Compact -> CompactOsd( - state, info, ui, shownPosition, plan?.spans.orEmpty(), playing, player, - onToggle = session::togglePlayPause, onSeek = ::scrubBy, onScrub = ::scrubTo, + state, info, episodes, ui, shownPosition, plan?.spans.orEmpty(), playing, player, + onToggle = session::togglePlayPause, onSeek = ::scrubBy, onScrub = ::scrubTo, onEpisode = ::playEpisode, onVolume = ::setVolume, onMute = ::toggleMute, onMenu = { ui.menuAt = it }, onFullscreen = ::toggleFullscreen, onOnTop = ::toggleOnTop, onLibrary = ::showLibrary, onClose = onClose, ) @@ -753,11 +753,12 @@ internal fun FullOsd( } } -/** 480–900 px: a thin title line with × on top, one row at the bottom; panels from ⋯. */ +/** 480–900 px: a thin title line with × on top, one row at the bottom (⏮ ⏯ ⏭ for an episode); panels from ⋯. */ @Composable internal fun CompactOsd( state: PlaybackUiState, info: PlayerInfo?, + episodes: SeasonEpisodes?, ui: PlayerUiState, positionMs: Long, spans: List, @@ -766,6 +767,7 @@ internal fun CompactOsd( onToggle: () -> Unit, onSeek: (Long) -> Unit, onScrub: (Long, Boolean) -> Unit, + onEpisode: (UUID) -> Unit, onVolume: (Int) -> Unit, onMute: () -> Unit, onMenu: (Offset) -> Unit, @@ -789,9 +791,17 @@ internal fun CompactOsd( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp), ) { - PlayButton(playing, 36.dp, onClick = onToggle) - IconButton(AppIcon.Replay, 32.dp, 15.dp, onClick = { onSeek(-10_000) }, bare = true) - IconButton(AppIcon.Forward, 32.dp, 15.dp, onClick = { onSeek(10_000) }, bare = true) + // An episode: ⏮ ⏯ ⏭ — in a small window the episodes matter more than ±10 s (←/→ and the wheel over + // the timeline still seek); a movie: ⏯ ⟲ ⟳. + if (episodes != null) { + IconButton(AppIcon.Previous, 32.dp, 13.dp, onClick = { episodes.previous?.let(onEpisode) }, bare = true) + PlayButton(playing, 36.dp, onClick = onToggle) + IconButton(AppIcon.Next, 32.dp, 13.dp, onClick = { episodes.next?.let(onEpisode) }, bare = true) + } else { + PlayButton(playing, 36.dp, onClick = onToggle) + IconButton(AppIcon.Replay, 32.dp, 15.dp, onClick = { onSeek(-10_000) }, bare = true) + IconButton(AppIcon.Forward, 32.dp, 15.dp, onClick = { onSeek(10_000) }, bare = true) + } TimeLabel(positionMs, state.durationMs, Modifier.padding(horizontal = 4.dp)) Timeline( positionMs, state.durationMs, state.bufferedMs, info?.chaptersMs.orEmpty(), spans, ui, diff --git a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/SettingsScreen.kt b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/SettingsScreen.kt index f89398f..1b2d197 100644 --- a/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/SettingsScreen.kt +++ b/desktop/src/main/kotlin/ru/stenfredd/sleepyowl/desktop/SettingsScreen.kt @@ -124,7 +124,7 @@ fun SettingsScreen( Section.Desktop -> DesktopSection(focus) Section.Keys -> KeysSection() Section.Account -> AccountSection(vm, focus, onOpen, onSignedOut, onSwitched) - Section.About -> AboutSection(vm) + Section.About -> AboutSection(vm, focus, onOpen) } } } @@ -522,7 +522,7 @@ private fun InfoLine(key: String, value: String) { // --- О приложении --- @Composable -private fun AboutSection(vm: SettingsViewModel) { +private fun AboutSection(vm: SettingsViewModel, focus: ScreenFocus, onOpen: (Screen) -> Unit) { Column(verticalArrangement = Arrangement.spacedBy(5.dp)) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { OwlMark() @@ -531,6 +531,39 @@ private fun AboutSection(vm: SettingsViewModel) { BasicText("Версия ${vm.about.version}", style = AppType.MonoMeta) BasicText(vm.about.device, style = AppType.MonoMeta.copy(color = AppColors.TextDim)) } - // The list of components and their licences comes with the package (L10): the desktop is built from other parts. - Note("Приложение — свободное ПО под лицензией GPL-3.0.") + Setting("Лицензии", "Приложение — свободное ПО под лицензией GPL-3.0. Ниже — из чего оно собрано; щелчок — текст лицензии.") { + Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + for ((i, c) in (listOf(Licenses.app) + Licenses.components).withIndex()) { + LicenseRow(c, { onOpen(Screen.License(c.name, c.license, c.asset)) }, Modifier.hoverFocus().remembered(focus, "license/$i")) + } + } + } +} + +private val RowFocus = FocusStyle(scale = 1f, corner = 7.dp, ring = 0.5.dp, glows = listOf(FocusStyle.Glow(15.dp, 0.dp, Color(0x737C5CFF)))) + +@Composable +private fun LicenseRow(component: Component, onClick: () -> Unit, modifier: Modifier) { + var focused by remember { mutableStateOf(false) } + val shape = RoundedCornerShape(7.dp) + Row( + modifier + .focusCard(RowFocus) + .widthIn(max = 560.dp) + .fillMaxWidth() + .height(34.dp) + .background(if (focused) AppColors.SurfaceFocused else AppColors.Surface, shape) + .border(0.5.dp, if (focused) AppColors.Accent else AppColors.BorderSubtle, shape) + .onFocusChanged { focused = it.isFocused } + .clickable(interactionSource = null, indication = null, onClick = onClick) + .padding(horizontal = 11.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + BasicText(component.name, style = AppType.CardTitle.copy(fontSize = 12.sp, fontWeight = FontWeight.SemiBold), maxLines = 1) + component.note?.let { + BasicText(it, Modifier.weight(1f), style = AppType.Body.copy(fontSize = 10.5.sp, color = AppColors.TextDim), maxLines = 1, overflow = TextOverflow.Ellipsis) + } ?: Box(Modifier.weight(1f)) + BasicText(component.license, style = AppType.MonoCaption.copy(color = AppColors.Accent), maxLines = 1) + } } diff --git a/desktop/src/main/resources/licenses/GPL-2.0.txt b/desktop/src/main/resources/licenses/GPL-2.0.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/desktop/src/main/resources/licenses/GPL-2.0.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/desktop/src/main/resources/licenses/OpenJDK-GPL-2.0-CE.txt b/desktop/src/main/resources/licenses/OpenJDK-GPL-2.0-CE.txt new file mode 100644 index 0000000..8b400c7 --- /dev/null +++ b/desktop/src/main/resources/licenses/OpenJDK-GPL-2.0-CE.txt @@ -0,0 +1,347 @@ +The GNU General Public License (GPL) + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you +can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for +a fee, you must give the recipients all the rights that you have. You must +make sure that they, too, receive or can get the source code. And you must +show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must be licensed for +everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included +without limitation in the term "modification".) Each licensee is addressed as +"you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is +not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as +you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may +at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus +forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all of +these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or + in part contains or is derived from the Program or any part thereof, to be + licensed as a whole at no charge to all third parties under the terms of + this License. + + c) If the modified program normally reads commands interactively when run, + you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms +of this License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on +the Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and +2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above + on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord with + Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code +distributed need not include anything that is normally distributed (in either +source or binary form) with the major components (compiler, kernel, and so on) +of the operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source +code from the same place counts as distribution of the source code, even though +third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the Program +or its derivative works. These actions are prohibited by law if you do not +accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor to +copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance by +third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In +such case, this License incorporates the limitation as if written in the body +of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the +General Public License from time to time. Such new versions will be similar in +spirit to the present version, but may differ in detail to address new problems +or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any later +version", you have the option of following the terms and conditions either of +that version or of any later version published by the Free Software Foundation. +If the Program does not specify a version number of this License, you may +choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, +YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE +PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + + Copyright (C) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it +starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes + with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free + software, and you are welcome to redistribute it under certain conditions; + type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + 'Gnomovision' (which makes passes at compilers) written by James Hacker. + + signature of Ty Coon, 1 April 1989 + + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. + + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Oracle America and/or its affiliates are +subject to the following clarification and special exception to the GPL, but +only where Oracle has expressly included in the particular source file's header +the words "Oracle designates this particular file as subject to the "Classpath" +exception as provided by Oracle in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. diff --git a/desktop/src/main/resources/licenses/Skia-BSD-3.txt b/desktop/src/main/resources/licenses/Skia-BSD-3.txt new file mode 100644 index 0000000..e32636d --- /dev/null +++ b/desktop/src/main/resources/licenses/Skia-BSD-3.txt @@ -0,0 +1,29 @@ +Copyright (c) 2011 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/LicensesTest.kt b/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/LicensesTest.kt new file mode 100644 index 0000000..5f9b51d --- /dev/null +++ b/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/LicensesTest.kt @@ -0,0 +1,15 @@ +package ru.stenfredd.sleepyowl.desktop + +import org.junit.Assert.assertTrue +import org.junit.Test + +/** Every row of "О приложении" opens a text: the TV's ones are copied in by the build, the desktop's own are resources. */ +class LicensesTest { + @Test + fun everyLicenceHasItsText() { + for (c in listOf(Licenses.app) + Licenses.components) { + val text = Licenses::class.java.getResourceAsStream("/licenses/${c.asset}")?.use { it.readBytes().size } ?: 0 + assertTrue("${c.name}: no licenses/${c.asset}", text > 500) + } + } +} diff --git a/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerRenderTest.kt b/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerRenderTest.kt index 1369931..6cea167 100644 --- a/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerRenderTest.kt +++ b/desktop/src/test/kotlin/ru/stenfredd/sleepyowl/desktop/PlayerRenderTest.kt @@ -69,8 +69,8 @@ class PlayerRenderTest { } render("compact", 720, 405) { CompactOsd( - state, info, PlayerUiState(), state.positionMs, spans, playing = false, player, - onToggle = {}, onSeek = {}, onScrub = { _, _ -> }, onVolume = {}, onMute = {}, onMenu = {}, onFullscreen = {}, onOnTop = {}, onLibrary = {}, onClose = {}, + state, info, season, PlayerUiState(), state.positionMs, spans, playing = false, player, + onToggle = {}, onSeek = {}, onScrub = { _, _ -> }, onEpisode = {}, onVolume = {}, onMute = {}, onMenu = {}, onFullscreen = {}, onOnTop = {}, onLibrary = {}, onClose = {}, ) val ui = PlayerUiState() PlayerMenu(listOf(listOf(MenuItem("Во весь экран", "F") {}), listOf(MenuItem("Аудио", "A") {}, MenuItem("Субтитры", "C") {}), listOf(MenuItem("Закрыть плеер", "Ctrl+W") {})), Offset(380f, 60f), ui, onDismiss = {}) diff --git a/tools/linux/k2.py b/tools/linux/k2.py index e3165fe..b0257da 100755 --- a/tools/linux/k2.py +++ b/tools/linux/k2.py @@ -3,8 +3,8 @@ tools/linux/k2.py runs it; PASS/FAIL per check, screenshots in $STAND/shots/k2-*.png -Everything happens on the stand's display :87 and its own D-Bus (stand.sh): the user's screen, focus and desktop are -not touched; the video is muted, the app runs niced. The player's state is read back from MPRIS (status, position, +Everything happens on the stand's display :87 and its own D-Bus (stand.sh): the user's screen, focus, desktop and sound +are not touched (mpv plays into ao=null), the app runs niced. The player's state is read back from MPRIS (status, position, volume, title), the windows from X11 (_NET_WM_STATE, geometry, frame), the screensaver from fake_screensaver.py. The player settings start from scratch (first launch) and are put back afterwards, as is the test account's watch data. """ @@ -202,7 +202,7 @@ def run_logs(): def start_app(item, start): - env = dict(os.environ, DESKTOP_NOBUILD="1", SLEEPYOWL_MPV_OPTIONS="mute=yes") + env = dict(os.environ, DESKTOP_NOBUILD="1", SLEEPYOWL_MPV_OPTIONS="ao=null") subprocess.run(["nice", "-n", "15", STAND_SH, "app", "--play", item, "--start", str(start)], env=env, check=True, capture_output=True) ok = wait(lambda: mpris_present() and player() and (mpris("Metadata") or ""), 60, 0.5) time.sleep(2) @@ -359,6 +359,7 @@ try: shot("before-close") click(p["x"] + p["w"] - 21, p["y"] + 21); time.sleep(2) check("× closes the player, library stays", player() is None and library() is not None) + check("…and the library has the focus", "FOCUSED" in library()["states"], library()["states"]) calls = [l for l in ss_lines() if l.startswith(("Inhibit", "UnInhibit"))] check("MPRIS gone, screensaver allowed", not mpris_present() and calls and calls[-1].startswith("UnInhibit"), calls[-2:]) sh(STAND_SH, "stop") diff --git a/tools/linux/stand.sh b/tools/linux/stand.sh index b2fa7b8..11d4938 100755 --- a/tools/linux/stand.sh +++ b/tools/linux/stand.sh @@ -2,6 +2,8 @@ # Test stand of the desktop app (LINUX_PLAN.md §3 «Как проверяем»): a private virtual display :87 with the real # window manager (Muffin), so window, mouse and keyboard tests do not touch the user's screen. Muffin and the app share # the stand's own D-Bus session bus: the app's MPRIS player and screensaver calls never reach the user's desktop. +# mpv plays into no sound device (ao=null, unless SLEEPYOWL_MPV_OPTIONS says otherwise): the stand never touches the +# user's PipeWire — WirePlumber remembers a stream's mute by its role, and that would follow the user's own viewing. # # stand.sh up start Xvfb :87 (1920×1080), the stand's D-Bus and Muffin, if not running # stand.sh down stop the app, Muffin and Xvfb @@ -14,7 +16,8 @@ # # The app's files live in $STAND (default ~/.cache/sleepyowl-test): its own config with the test account, # cache, log and lock — the user's own ~/.config/sleepyowl is never used. Gradle builds before `app` unless -# DESKTOP_NOBUILD=1. +# DESKTOP_NOBUILD=1. SLEEPYOWL_APP= runs that instead of the Gradle build, e.g. the packaged app unpacked by +# `dpkg-deb -x sleepyowl_*.deb DIR` → SLEEPYOWL_APP=DIR/opt/sleepyowl/bin/sleepyowl (also for k2.py). set -e R=$(cd "$(dirname "$0")/../.." && pwd) STAND=${STAND:-$HOME/.cache/sleepyowl-test} @@ -60,9 +63,9 @@ case "$1" in shift up >/dev/null stop_app - [ -n "$DESKTOP_NOBUILD" ] || (cd "$R" && ./gradlew -q :desktop:classes :desktop:desktopClasspath) + [ -n "$DESKTOP_NOBUILD$SLEEPYOWL_APP" ] || (cd "$R" && ./gradlew -q :desktop:classes :desktop:desktopClasspath) DISPLAY=$D DBUS_SESSION_BUS_ADDRESS=$(cat "$STAND/run/dbus.addr") XDG_CONFIG_HOME="$STAND/config" XDG_CACHE_HOME="$STAND/cache" XDG_STATE_HOME="$STAND/state" \ - SLEEPYOWL_RUNTIME_DIR="$STAND/run" DESKTOP_NOBUILD=1 "$R/tools/linux/desktop.sh" "$@" >"$STAND/app.out" 2>&1 & + SLEEPYOWL_RUNTIME_DIR="$STAND/run" SLEEPYOWL_MPV_OPTIONS="${SLEEPYOWL_MPV_OPTIONS:-ao=null}" DESKTOP_NOBUILD=1 "${SLEEPYOWL_APP:-$R/tools/linux/desktop.sh}" "$@" >"$STAND/app.out" 2>&1 & echo $! >"$STAND/run/app.pid" echo "app started, pid $(cat "$STAND/run/app.pid")" ;; stop) stop_app ;; @@ -72,5 +75,5 @@ case "$1" in in) shift; DISPLAY=$D python3 "$R/tools/linux/xinput.py" "$@" ;; log) cat "$STAND/state/sleepyowl/log/sleepyowl.log" ;; bus) shift; DBUS_SESSION_BUS_ADDRESS=$(cat "$STAND/run/dbus.addr") "$@" ;; - *) sed -n '2,19p' "$0"; exit 1 ;; + *) sed -n '2,21p' "$0"; exit 1 ;; esac