2
0

DesktopProvider.kt 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. package eu.mjdev.desktop.provider
  2. import androidx.compose.runtime.*
  3. import androidx.compose.ui.graphics.ImageBitmap
  4. import androidx.compose.ui.graphics.toAwtImage
  5. import androidx.compose.ui.platform.*
  6. import androidx.compose.ui.unit.DpSize
  7. import androidx.compose.ui.unit.dp
  8. import coil3.ImageLoader
  9. import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
  10. import eu.mjdev.desktop.components.controlcenter.pages.*
  11. import eu.mjdev.desktop.data.App
  12. import eu.mjdev.desktop.data.DesktopFile
  13. import eu.mjdev.desktop.data.User
  14. import eu.mjdev.desktop.extensions.Compose.asyncImageLoader
  15. import eu.mjdev.desktop.helpers.adb.AdbDiscover.Companion.adbDevicesHandler
  16. import eu.mjdev.desktop.helpers.bitmap.Bitmap
  17. import eu.mjdev.desktop.helpers.internal.Palette
  18. import eu.mjdev.desktop.managers.*
  19. import eu.mjdev.desktop.helpers.system.DBus
  20. import eu.mjdev.desktop.helpers.system.OsRelease
  21. import eu.mjdev.desktop.helpers.system.Shell
  22. import eu.mjdev.desktop.managers.WindowsManager
  23. import eu.mjdev.desktop.provider.AIProvider.AiPluginGemini
  24. import eu.mjdev.desktop.theme.gtk.GtkThemeHelper
  25. import kotlinx.coroutines.CoroutineScope
  26. import kotlinx.coroutines.Dispatchers
  27. import java.awt.*
  28. import java.io.File
  29. import java.io.FileReader
  30. import java.net.URI
  31. import javax.script.ScriptEngine
  32. import javax.script.ScriptEngineManager
  33. import kotlin.system.exitProcess
  34. @Suppress("unused", "MemberVisibilityCanBePrivate", "SameParameterValue")
  35. class DesktopProvider(
  36. val scope: CoroutineScope = CoroutineScope(Dispatchers.IO),
  37. val args: List<String> = emptyList(),
  38. val imageLoader: ImageLoader? = null,
  39. val isDebug: Boolean = true,
  40. val isFirstStart: Boolean = true, // todo
  41. val isInstalled: Boolean = false, // todo
  42. ) : AutoCloseable {
  43. val scriptManager: ScriptEngineManager by lazy { ScriptEngineManager() }
  44. val scriptEngine: ScriptEngine by lazy {
  45. scriptManager.getEngineByName("JavaScript").apply {
  46. // todo
  47. }
  48. }
  49. val osDetails by lazy { OsRelease() }
  50. val toolkit: Toolkit by lazy { Toolkit.getDefaultToolkit() }
  51. val kcefHelper: KCEFHelper by lazy { KCEFHelper(this) }
  52. val gnome: GnomeManager by lazy { GnomeManager() }
  53. val connectionManager: ConnectivityManager by lazy { ConnectivityManager() }
  54. val windowsManager: WindowsManager by lazy { WindowsManager(this) }
  55. val dbus: DBus by lazy { DBus() }
  56. val ai: AIProvider by lazy {
  57. // todo user can configure
  58. AIProvider(scope, AiPluginGemini(scope))
  59. }
  60. val appsProvider by lazy { AppsProvider(this) }
  61. val mounts by lazy {
  62. FileSystemWatcher(scope) {
  63. println("Mounted: ${this.targetDirectory}")
  64. }
  65. }
  66. val gtkTheme: GtkThemeHelper by lazy { GtkThemeHelper(this) }
  67. val palette: Palette by lazy { Palette(this) }
  68. val homeDir: File
  69. get() = currentUser.homeDir
  70. val allUsers: List<User>
  71. get() = User.allUsers
  72. val machineName: String
  73. get() = Shell.executeAndRead("hostname").trim()
  74. // todo state
  75. val currentUser: User
  76. get() = allUsers.firstOrNull { u -> u.isLoggedIn } ?: User.Nobody
  77. val controlCenterPagesState: MutableState<List<ControlCenterPage>> = mutableStateOf(CONTROL_CENTER_PAGES)
  78. var lastTheme: String = ""
  79. val adbHandler = adbDevicesHandler(
  80. coroutineScope = scope,
  81. onAdded = { device ->
  82. println("Device discovered : $device")
  83. // when device connected
  84. },
  85. onRemoved = { device ->
  86. println("Device removed : $device")
  87. // when device removed
  88. }
  89. )
  90. val containerSize: DpSize
  91. get() = runCatching {
  92. toolkit.screenSize.let { screen -> DpSize(screen.width.dp, screen.height.dp) }
  93. }.getOrNull() ?: DpSize.Zero
  94. val isAlwaysOnTopSupported
  95. get() = runCatching {
  96. toolkit.isAlwaysOnTopSupported
  97. }.getOrNull() ?: false
  98. val cursorSize
  99. get() = toolkit.getBestCursorSize(32, 32).let {
  100. DpSize(it.width.dp, it.height.dp)
  101. }
  102. val desktopUtils: Desktop by lazy {
  103. Desktop.getDesktop()
  104. }
  105. val controlCenterPages
  106. get() = controlCenterPagesState.value
  107. val graphicsEnvironment: GraphicsEnvironment
  108. get() = GraphicsEnvironment.getLocalGraphicsEnvironment()
  109. val graphicsDevice: GraphicsDevice
  110. get() = graphicsEnvironment.defaultScreenDevice
  111. val isTransparencySupported
  112. get() = graphicsDevice.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT)
  113. init {
  114. runCatching {
  115. mounts.init()
  116. }
  117. runCatching {
  118. dbus.updateEnvironment()
  119. }
  120. runCatching {
  121. lastTheme = gnome.getGTKTheme()
  122. }
  123. // runCatching {
  124. // gnome.setGTKTheme(THEME_MJDEV)
  125. // }
  126. }
  127. override fun close() {
  128. // runCatching {
  129. // gnome.setGTKTheme(lastTheme)
  130. // }
  131. runCatching {
  132. mounts.dispose()
  133. }
  134. runCatching {
  135. kcefHelper.dispose()
  136. }
  137. runCatching {
  138. windowsManager.dispose()
  139. }
  140. }
  141. fun openMail(emailAddress: String) = runCatching {
  142. desktopUtils.mail(URI.create("mailto:$emailAddress"))
  143. }
  144. fun openBrowser(url: String) = runCatching {
  145. desktopUtils.browse(URI.create(url))
  146. }
  147. fun openDirectoryForFile(path: String) = runCatching {
  148. desktopUtils.browseFileDirectory(File(path))
  149. }
  150. fun moveToTrash(file: File) = runCatching {
  151. desktopUtils.moveToTrash(file)
  152. }
  153. fun moveToTrash(filePath: String) = runCatching {
  154. moveToTrash(File(filePath))
  155. }
  156. fun openFileInAssociated(file: File) = runCatching {
  157. desktopUtils.open(file)
  158. }
  159. fun openFileInAssociated(filePath: String) = runCatching {
  160. openFileInAssociated(File(filePath))
  161. }
  162. fun runScript(script: String): Any = runCatching {
  163. scriptEngine.eval(script)
  164. }
  165. fun runScript(file: File): Any = runCatching {
  166. scriptEngine.eval(FileReader(file))
  167. }
  168. fun beep() = runCatching {
  169. toolkit.beep()
  170. }
  171. fun sync() = runCatching {
  172. toolkit.sync()
  173. }
  174. fun createCustomCursor(cursor: Image, hotSpot: Point, name: String): Cursor? = runCatching {
  175. toolkit.createCustomCursor(cursor, hotSpot, name)
  176. }.getOrNull()
  177. fun createCustomCursor(cursor: Bitmap, hotSpot: Point, name: String): Cursor? = runCatching {
  178. toolkit.createCustomCursor(cursor.image, hotSpot, name)
  179. }.getOrNull()
  180. fun createCustomCursor(cursor: ImageBitmap, hotSpot: Point, name: String): Cursor? = runCatching {
  181. toolkit.createCustomCursor(cursor.toAwtImage(), hotSpot, name)
  182. }.getOrNull()
  183. // todo
  184. // fun createCustomCursor(cursor: ImageVector, hotSpot: Point, name: String) =
  185. // toolkit.createCustomCursor(cursor, hotSpot, name)
  186. @Suppress("UNUSED_PARAMETER")
  187. fun login(
  188. user: String,
  189. password: String
  190. ): Boolean {
  191. // todo
  192. return true
  193. }
  194. fun logOut() {
  195. // todo
  196. exitProcess(0)
  197. }
  198. fun shutdown() {
  199. // todo
  200. exitProcess(0)
  201. }
  202. fun restart() {
  203. // todo
  204. exitProcess(0)
  205. }
  206. companion object {
  207. private val CONTROL_CENTER_PAGES = listOf(
  208. MainSettingsPage(),
  209. EthSettingsPage(),
  210. WifiSettingsPage(),
  211. BluetoothSettingsPage(),
  212. DisplaySettingsPage(),
  213. SoundSettingsPage(),
  214. AIPage(),
  215. DevicesPage()
  216. )
  217. val LocalDesktop = staticCompositionLocalOf {
  218. println("default empty desktop provider created")
  219. DesktopProvider()
  220. }
  221. @Composable
  222. fun rememberDesktopProvider(
  223. scope: CoroutineScope = rememberCoroutineScope(),
  224. imageLoader: ImageLoader = asyncImageLoader(),
  225. isDebug: Boolean = LocalInspectionMode.current,
  226. args: List<String> = emptyList(),
  227. ) = remember {
  228. println("default initialized desktop provider created")
  229. DesktopProvider(
  230. scope = scope,
  231. imageLoader = imageLoader,
  232. args = args,
  233. isDebug = isDebug || args.contains("-d")
  234. )
  235. }
  236. fun Desktop.startApp(app: App) {
  237. startApp(app.desktopFile)
  238. }
  239. fun Desktop.startApp(
  240. desktopFile: DesktopFile?
  241. ) {
  242. open(desktopFile?.file)
  243. }
  244. }
  245. }