DesktopProvider.kt 8.3 KB

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