Ver Fonte

exit app resources cleanup

milan jurkulák há 1 ano atrás
pai
commit
e1a9658d06

+ 1 - 1
.run/mjdev-desktop [runDebug].run.xml

@@ -4,7 +4,7 @@
       <option name="executionName" />
       <option name="externalProjectPath" value="$PROJECT_DIR$" />
       <option name="externalSystemIdString" value="GRADLE" />
-      <option name="scriptParameters" value="" />
+      <option name="scriptParameters" value="--stacktrace" />
       <option name="taskDescriptions">
         <list />
       </option>

+ 0 - 15
src/main/kotlin/eu/mjdev/desktop/Main.kt

@@ -1,9 +1,7 @@
 package eu.mjdev.desktop
 
-import androidx.compose.runtime.DisposableEffect
 import eu.mjdev.desktop.components.main.MainWindow
 import eu.mjdev.desktop.helpers.application.application
-import eu.mjdev.desktop.helpers.system.Shell
 
 fun main(
     args: Array<String>
@@ -11,18 +9,5 @@ fun main(
     args = args.toList(),
     exitProcessOnExit = true
 ) {
-    // net devices  : ls /sys/class/net
-    // connect gui  : nmtui
-    // eth settings : iwconfig
     MainWindow()
-    DisposableEffect(Unit) {
-        println("App started with args: ${args.toList()}")
-        Shell {
-            // todo
-//            autoStartApps()
-        }
-        onDispose {
-            println("App ended.")
-        }
-    }
 }

+ 4 - 0
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/WifiSettingsPage.kt

@@ -110,3 +110,7 @@ fun WifiRow(
 fun WifiSettingsPagePreview() = preview {
     WifiSettingsPage().render()
 }
+
+// net devices  : ls /sys/class/net
+// connect gui  : nmtui
+// eth settings : iwconfig

+ 18 - 24
src/main/kotlin/eu/mjdev/desktop/components/image/ImageAny.kt

@@ -17,9 +17,6 @@ import coil3.compose.AsyncImage
 import eu.mjdev.desktop.components.video.VideoView
 import eu.mjdev.desktop.extensions.Compose.asyncImageLoader
 import eu.mjdev.desktop.extensions.Compose.preview
-import eu.mjdev.desktop.extensions.Custom.flowBlock
-import eu.mjdev.desktop.helpers.internal.ImagesProvider
-import eu.mjdev.desktop.helpers.internal.ImagesProvider.Companion.getOne
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import org.jetbrains.skia.Bitmap
 import java.io.File
@@ -40,17 +37,14 @@ fun ImageAny(
     onLoading: () -> Unit = {},
     onFail: (error: Throwable) -> Unit = {}
 ) = withDesktopScope {
-    val image = flowBlock(null) {
-        (src as? ImagesProvider).let { provider -> provider?.getOne() ?: src }
-    }
     // todo from mime
-    val isGif = image.value.toString().trim().endsWith(".gif")
+    val isGif = src.toString().trim().endsWith(".gif")
     // todo from mime
-    val isVideo = image.value.toString().trim().let {
+    val isVideo = src.toString().trim().let {
         it.endsWith(".mp4") || it.endsWith(".mpg")
     }
     when {
-        image.value == null -> ComposeImage(
+        src == null -> ComposeImage(
             modifier = modifier,
             imageVector = Icons.Default.BrokenImage,
             alignment = alignment,
@@ -60,13 +54,13 @@ fun ImageAny(
             contentScale = contentScale
         )
 
-        image.value is Color -> Box(
-            modifier = modifier.background(image.value as Color)
+        src is Color -> Box(
+            modifier = modifier.background(src)
         )
 
-        image.value is Painter -> ComposeImage(
+        src is Painter -> ComposeImage(
             modifier = modifier,
-            painter = image.value as Painter,
+            painter = src,
             alignment = alignment,
             alpha = alpha,
             contentDescription = contentDescription,
@@ -74,9 +68,9 @@ fun ImageAny(
             contentScale = contentScale
         )
 
-        image.value is Bitmap -> ComposeImage(
+        src is Bitmap -> ComposeImage(
             modifier = modifier,
-            bitmap = (image.value as Bitmap).asComposeImageBitmap(),
+            bitmap = src.asComposeImageBitmap(),
             alignment = alignment,
             alpha = alpha,
             contentDescription = contentDescription,
@@ -84,9 +78,9 @@ fun ImageAny(
             contentScale = contentScale
         )
 
-        image.value is ImageBitmap -> ComposeImage(
+        src is ImageBitmap -> ComposeImage(
             modifier = modifier,
-            bitmap = image.value as ImageBitmap,
+            bitmap = src,
             alignment = alignment,
             alpha = alpha,
             contentDescription = contentDescription,
@@ -94,9 +88,9 @@ fun ImageAny(
             contentScale = contentScale
         )
 
-        image.value is ImageVector -> ComposeImage(
+        src is ImageVector -> ComposeImage(
             modifier = modifier,
-            imageVector = image.value as ImageVector,
+            imageVector = src,
             alignment = alignment,
             alpha = alpha,
             contentDescription = contentDescription,
@@ -107,16 +101,16 @@ fun ImageAny(
         isGif -> GifView(
             modifier = modifier,
             src = when {
-                image.value is File -> (image.value as File).absolutePath
-                else -> image.value.toString()
+                src is File -> src.absolutePath
+                else -> src.toString()
             }
         )
 
         isVideo -> VideoView(
             modifier = modifier,
             src = when {
-                image.value is File -> (image.value as File).absolutePath
-                else -> image.value.toString()
+                src is File -> src.absolutePath
+                else -> src.toString()
             },
             alignment = alignment,
             alpha = alpha,
@@ -127,7 +121,7 @@ fun ImageAny(
 
         else -> AsyncImage(
             modifier = modifier,
-            model = image.value,
+            model = src,
             contentDescription = contentDescription,
             contentScale = contentScale,
             filterQuality = filterQuality,

+ 14 - 1
src/main/kotlin/eu/mjdev/desktop/components/main/MainWindow.kt

@@ -14,6 +14,7 @@ import eu.mjdev.desktop.components.info.InfoWindow
 import eu.mjdev.desktop.components.installer.Installer
 import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
 import eu.mjdev.desktop.extensions.Compose.preview
+import eu.mjdev.desktop.helpers.system.Shell
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindowState.Companion.rememberChromeWindowState
 import eu.mjdev.desktop.windows.DesktopWindow
@@ -71,8 +72,20 @@ fun MainWindow() = withDesktopScope {
         )
     }
     DisposableEffect(Unit) {
+        println("App started with args: $appArgs")
+        println("First start : $isFirstStart")
+        println("Debug mode : $isDebug")
+        Shell {
+            if (!isDebug) {
+                println("Starting autostart apps")
+                autoStartApps()
+            } else {
+                println("Starting autostart apps omitted in debug mode.")
+            }
+        }
         onDispose {
-            api.close()
+            dispose()
+            println("App ended.")
         }
     }
 }

+ 8 - 2
src/main/kotlin/eu/mjdev/desktop/data/DesktopFile.kt

@@ -12,7 +12,7 @@ import java.io.File
 @Suppress("unused", "MemberVisibilityCanBePrivate", "ConstPropertyName", "PropertyName")
 class DesktopFile(
     var file: File = File(""),
-    val correctDir: File = File("/tmp/.corrected-desktop-files/"),
+    val correctDir: File = File("/var/tmp/mjdev-desktop/corrected-desktop-files/"),
     val correctedFile: File = File(correctDir, file.name),
     var fileData: String = (if (correctedFile.exists()) correctedFile else file).text,
     private var content: DesktopFileParser = (runCatching {
@@ -47,6 +47,7 @@ class DesktopFile(
         get() = correctedFile.exists()
 
     init {
+        correctDir.mkdirs()
         if (isApp && !isCorrect) {
             runCatching {
                 correctedFile.let { f ->
@@ -103,13 +104,18 @@ class DesktopFile(
     }
 
     fun writeTo(f: File) {
+        println("Writing: file:///${f.absolutePath}")
         if (!f.parentFile.exists()) {
             f.parentFile.mkdirs()
         }
         if (f.exists()) {
             f.delete()
         }
-        f.createNewFile()
+        if (f.parentFile.exists()) {
+            f.createNewFile()
+        } else {
+            println("Cant store file: ${f.absolutePath}")
+        }
         content.store(f)
     }
 

+ 2 - 2
src/main/kotlin/eu/mjdev/desktop/extensions/Custom.kt

@@ -97,7 +97,7 @@ object Custom {
 
     fun File.listDesktopFiles(
         ext: String = DesktopFile.EXTENSION
-    ): List<DesktopFile> = listFiles(ext) { f -> DesktopFile(f) }
+    ): List<DesktopFile> = if (exists()) listFiles(ext) { f -> DesktopFile(f) } else emptyList()
 
     inline fun <reified T : Any> MutableList<T>.addIfNotExists(
         element: T,
@@ -129,7 +129,7 @@ object Custom {
         get() = if (exists()) readTextAsLocale() else Locale.ENGLISH
 
     val File.desktopFiles: List<DesktopFile>
-        get() = listDesktopFiles()
+        get() = if (exists()) listDesktopFiles() else emptyList()
 
 //    inline fun <T, K> distinctList(
 //        vararg lists: List<T>,

+ 9 - 2
src/main/kotlin/eu/mjdev/desktop/helpers/application/Application.kt

@@ -8,7 +8,10 @@
 
 package eu.mjdev.desktop.helpers.application
 
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Composition
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.Recomposer
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.configureSwingGlobalsForCompose
 import androidx.compose.ui.platform.LocalDensity
@@ -42,6 +45,7 @@ fun application(
         }
     }
     if (exitProcessOnExit) {
+        println("Exiting application.")
         exitProcess(0)
     }
 }
@@ -76,7 +80,10 @@ suspend fun awaitApplication(
                                 LocalDensity provides GlobalDensity,
                                 LocalLayoutDirection provides GlobalLayoutDirection,
                                 LocalLocalization providesDefault defaultPlatformLocalization(),
-                                LocalDesktop provides rememberDesktopProvider()
+                                LocalDesktop provides rememberDesktopProvider(
+                                    application = applicationScope,
+                                    args = args
+                                )
                             ) {
                                 applicationScope.content()
                             }

+ 4 - 3
src/main/kotlin/eu/mjdev/desktop/helpers/application/ApplicationScope.kt

@@ -9,7 +9,10 @@
 package eu.mjdev.desktop.helpers.application
 
 import androidx.compose.material.MaterialTheme
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.mutableStateOf
 import eu.mjdev.desktop.extensions.Compose.launchedEffect
 import eu.mjdev.desktop.helpers.application.block.SCOPED_BLOCK
 import eu.mjdev.desktop.helpers.application.block.invokeAllOnce
@@ -33,8 +36,6 @@ open class ApplicationScope(
             isOpenState.value = value
         }
 
-    val isDebug get() = args.contains("--debug")
-
     fun dispatchStart() = CoroutineScope(Dispatchers.IO).launch {
         sessionStartHandlers.invokeAllOnce(this@ApplicationScope)
     }

+ 2 - 1
src/main/kotlin/eu/mjdev/desktop/helpers/application/l10n/Translations.kt

@@ -11,7 +11,7 @@ package eu.mjdev.desktop.helpers.application.l10n
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.platform.PlatformLocalization
 
-fun translationFor(localeTag: String) = when(localeTag) {
+fun translationFor(localeTag: String) = when (localeTag) {
     "" -> Translations.en()
     "en_AU" -> Translations.enAU()
     "en_CA" -> Translations.enCA()
@@ -20,6 +20,7 @@ fun translationFor(localeTag: String) = when(localeTag) {
     else -> null
 }
 
+// todo i18n
 @Composable
 fun defaultPlatformLocalization(): PlatformLocalization {
     val copy = getString(Strings.Copy)

+ 7 - 2
src/main/kotlin/eu/mjdev/desktop/helpers/internal/Palette.kt

@@ -88,6 +88,11 @@ class Palette(
         createFromPalette()
     }
 
-    fun createFromPalette() =
-        api.themeManager.createFromPalette()
+    fun dispose() {
+        clearSystemTheme()
+    }
+
+    fun createFromPalette() = api.themeManager.createFromPalette()
+
+    fun clearSystemTheme() = api.themeManager.clearSystemTheme()
 }

+ 2 - 1
src/main/kotlin/eu/mjdev/desktop/managers/apps/AppsManager.kt

@@ -115,7 +115,8 @@ class AppsManager(
         (allAppsDesktopFilesLocal +
                 allAppsDesktopFilesShared +
                 allAppsDesktopFilesFlatPack +
-                allAppsDesktopFilesSnap).distinctBy { it.file.name }
+                allAppsDesktopFilesSnap
+                ).distinctBy { it.file.name }
     }
 
     val currentLocale: Locale

+ 2 - 0
src/main/kotlin/eu/mjdev/desktop/managers/processes/ProcessManager.kt

@@ -78,6 +78,8 @@ class ProcessManager(
         job?.cancel()
     }
 
+    fun dispose() = close()
+
     // todo : something raises error
     fun hasAppProcess(app: App?): Boolean = runCatching {
         val appCmd = app?.cmd

+ 4 - 0
src/main/kotlin/eu/mjdev/desktop/managers/theme/base/ThemeManagerStub.kt

@@ -17,4 +17,8 @@ open class ThemeManagerStub(
     open fun createFromPalette() {
         // no op
     }
+
+    open fun clearSystemTheme() {
+        // no op
+    }
 }

+ 10 - 3
src/main/kotlin/eu/mjdev/desktop/managers/theme/linux/ThemeManagerLinux.kt

@@ -42,6 +42,13 @@ class ThemeManagerLinux(
     private val systemGtk3CssFile = systemGtk3ThemeDir["gtk.css"]
     private val systemGtk4CssFile = systemGtk4ThemeDir["gtk.css"]
 
+    override fun clearSystemTheme() {
+        println("Deleting : file:///${systemGtk3CssFile.absolutePath}")
+        systemGtk3CssFile.delete()
+        println("Deleting : file:///${systemGtk4CssFile.absolutePath}")
+        systemGtk4CssFile.delete()
+    }
+
     override fun createFromPalette() {
         createDesktopFile()
         createCssFile(gtk3CssFile)
@@ -65,7 +72,7 @@ class ThemeManagerLinux(
                 MetacityTheme = THEME_ADWAITA_DARK
                 IconTheme = THEME_ADWAITA_DARK
                 CursorTheme = THEME_CURSOR_BLOOM
-                ButtonLayout = "close,minimize,maximize:"
+                ButtonLayout = "minimize,maximize,close:"
                 UseOverlayScrollbars = true
             }
             write()
@@ -247,12 +254,12 @@ class ThemeManagerLinux(
                 border-top-left-radius: 8px;
                 border: 2px solid ${bgColor.hexRgb};
             	border-top: none;
-                position: relative;
+                /* position: relative; */
                 box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
             }
             
             window:before, window:after {
-                position:absolute;
+                /* position:absolute; */
                 z-index: -1;
                 box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
                 top: 0;

+ 23 - 11
src/main/kotlin/eu/mjdev/desktop/provider/DesktopProvider.kt

@@ -1,13 +1,13 @@
 package eu.mjdev.desktop.provider
 
 import androidx.compose.runtime.*
-import androidx.compose.ui.platform.LocalInspectionMode
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
 import coil3.ImageLoader
 import eu.mjdev.desktop.components.controlcenter.pages.*
 import eu.mjdev.desktop.data.User
 import eu.mjdev.desktop.extensions.Compose.asyncImageLoader
+import eu.mjdev.desktop.helpers.application.ApplicationScope
 import eu.mjdev.desktop.helpers.internal.Palette
 import eu.mjdev.desktop.helpers.system.Shell
 import eu.mjdev.desktop.managers.apps.AppsManager
@@ -31,17 +31,16 @@ import java.awt.Toolkit
 import java.io.File
 import java.net.URI
 import kotlin.coroutines.CoroutineContext
-import kotlin.system.exitProcess
 
 @Suppress("unused", "MemberVisibilityCanBePrivate", "SameParameterValue", "RedundantSuspendModifier")
 class DesktopProvider(
+    val application: ApplicationScope? = null,
     val scope: CoroutineScope = CoroutineScope(Dispatchers.IO),
     val args: List<String> = emptyList(),
     val imageLoader: ImageLoader? = null,
-    val isDebug: Boolean = true,
-    val isFirstStart: Boolean = true, // todo
-    val isInstalled: Boolean = false, // todo
 ) : AutoCloseable {
+    var isFirstStart: Boolean = true // todo
+    var isInstalled: Boolean = false // todo
     val osManager by lazy { osManager(this) }
     val toolkit: Toolkit by lazy { Toolkit.getDefaultToolkit() }
     val kcefHelper by lazy { kcefManager(this) }
@@ -60,6 +59,10 @@ class DesktopProvider(
     //    val windowsManager by lazy { WindowsManager(this) }
     //    val dbus: DBus by lazy { DBus() }
 
+    val appArgs
+        get() = application?.args ?: emptyList()
+    val isDebug: Boolean
+        get() = false // todo
     val homeDir
         get() = currentUser.homeDir
     val allUsers
@@ -129,7 +132,9 @@ class DesktopProvider(
 //    }
 
     override fun close() {
-        processManager.close()
+        println("Cleaning up resources.")
+        processManager.dispose()
+        palette.dispose()
 //        runCatching {
 //            mounts.dispose()
 //        }
@@ -141,6 +146,8 @@ class DesktopProvider(
 //        }
     }
 
+    fun dispose() = close()
+
     fun runAsync(
         context: CoroutineContext = Dispatchers.IO,
         block: suspend () -> Unit
@@ -215,8 +222,8 @@ class DesktopProvider(
         Shell.executeAndRead("/usr/bin/loginctl", "lock-sessions")
     }
 
-    suspend fun logOut() {
-        exitProcess(0)
+    suspend fun logOut() = runAsync {
+        application?.exitApplication()
     }
 
     suspend fun suspend() {
@@ -254,23 +261,28 @@ class DesktopProvider(
         )
 
         val LocalDesktop = staticCompositionLocalOf {
-            println("default empty desktop provider created")
+            println("Default empty desktop provider created.")
             DesktopProvider()
         }
 
+        const val APP_PARAM_DEBUG = "--debug"
+
+        // todo application
         @Composable
         fun rememberDesktopProvider(
+            application: ApplicationScope?,
             scope: CoroutineScope = rememberCoroutineScope(),
             imageLoader: ImageLoader = asyncImageLoader(),
-            isDebug: Boolean = LocalInspectionMode.current,
+//            isDebug: Boolean = LocalInspectionMode.current,
             args: List<String> = emptyList(),
         ) = remember {
             println("default initialized desktop provider created")
             DesktopProvider(
+                application = application,
                 scope = scope,
                 imageLoader = imageLoader,
                 args = args,
-                isDebug = isDebug || args.contains("-d")
+//                isDebug = isDebug || args.contains(APP_PARAM_DEBUG)
             )
         }
     }

+ 7 - 0
src/main/kotlin/eu/mjdev/desktop/provider/DesktopScope.kt

@@ -11,6 +11,11 @@ open class DesktopScope(
     val isDebug
         get() = api.isDebug
 
+    var isFirstStart = api.isFirstStart
+
+    val appArgs
+        get() = api.appArgs
+
     val scope
         get() = api.scope
 
@@ -125,6 +130,8 @@ open class DesktopScope(
     val processManager
         get() = api.processManager
 
+    fun dispose() = api.dispose()
+
     companion object {
         @Composable
         fun withDesktopScope(