Ver Fonte

x11 jna access

milan jurkulák há 2 anos atrás
pai
commit
f2856f96a6

+ 3 - 1
build.gradle.kts

@@ -96,7 +96,9 @@ allprojects {
         // jwm
 //        implementation("io.github.humbleui:jwm:0.4.8")
         // jna
-//        implementation("net.java.dev.jna:jna-platform:5.6.0")
+        implementation("net.java.dev.jna:jna-platform:5.6.0")
+        // hid
+//        implementation('org.hid4java:hid4java')
         // dbus
         // implementation(libs.dbus.java.core)
         // implementation(libs.dbus.java.transport.native.unixsocket)

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

@@ -29,7 +29,7 @@ fun main() = application(
     val menuState = rememberVisibilityState()
 
     val handleMenuFocus: (Boolean) -> Unit = { focus ->
-        if (!menuState.isWindowFocus && !focus) {
+        if (!menuState.isWindowFocus && !focus && !controlCenterState.isWindowFocus) {
             menuState.hide()
         }
     }

+ 10 - 10
src/main/kotlin/eu/mjdev/desktop/data/App.kt

@@ -4,7 +4,7 @@ import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.graphics.Color
 import eu.mjdev.desktop.helpers.exception.EmptyException.Companion.EmptyException
-import eu.mjdev.desktop.windows.WindowsTracker
+import eu.mjdev.desktop.provider.DesktopProvider
 import java.io.File
 
 @Suppress("unused", "MemberVisibilityCanBePrivate", "HasPlatformType")
@@ -42,7 +42,7 @@ class App(
 
     var process: Process? = null
     val isRunning: Boolean
-        get() = (process?.isAlive ?: false)
+        get() = (process?.isAlive ?: false) || process?.children()?.anyMatch { it.isAlive } == true
 
     var isStarted: Boolean = false
 
@@ -100,20 +100,20 @@ class App(
         return this
     }
 
-    fun requestWindowFocus() {
-        WindowsTracker().getWindowByPid(process?.pid())?.toFront() ?: closeWindow()
+    fun requestWindowFocus(api: DesktopProvider) {
+        api.windowsTracker.getWindowByPid(process?.pid())?.toFront() ?: closeWindow(api)
     }
 
-    fun minimizeWindow() {
-        WindowsTracker().getWindowByPid(process?.pid())?.minimize()
+    fun minimizeWindow(api: DesktopProvider) {
+        api.windowsTracker.getWindowByPid(process?.pid())?.minimize()
     }
 
-    fun maximizeWindow() {
-        WindowsTracker().getWindowByPid(process?.pid())?.maximize()
+    fun maximizeWindow(api: DesktopProvider) {
+        api.windowsTracker.getWindowByPid(process?.pid())?.maximize()
     }
 
-    fun closeWindow() {
-        WindowsTracker().getWindowByPid(process?.pid())?.close() ?: exit()
+    fun closeWindow(api: DesktopProvider) {
+        api.windowsTracker.getWindowByPid(process?.pid())?.close() ?: exit()
     }
 
     fun exit() {

+ 5 - 3
src/main/kotlin/eu/mjdev/desktop/provider/AppsProvider.kt

@@ -16,10 +16,10 @@ import java.util.*
 
 @Suppress("unused", "MemberVisibilityCanBePrivate", "UNNECESSARY_SAFE_CALL")
 class AppsProvider(
-    val desktopProvider: DesktopProvider
+    val api: DesktopProvider
 ) {
     val scope
-        get() = desktopProvider.scope
+        get() = api.scope
 
     val homeDir by lazy { runCatching { File(System.getProperty("user.home")) }.getOrNull() }
 
@@ -144,7 +144,8 @@ class AppsProvider(
     fun startApp(app: App) {
         scope.launch(Dispatchers.IO) {
             if (app.isRunning) {
-                app.requestWindowFocus()
+                // todo menu to switch
+                app.requestWindowFocus(api)
             } else {
                 app.onStarting {
                     favoriteApps.invalidate()
@@ -156,6 +157,7 @@ class AppsProvider(
                         result.printStackTrace()
                     }
                 }.start()
+                favoriteApps.invalidate()
             }
         }
     }

+ 3 - 1
src/main/kotlin/eu/mjdev/desktop/provider/DesktopProvider.kt

@@ -14,6 +14,7 @@ import eu.mjdev.desktop.helpers.managers.ConnectivityManager
 import eu.mjdev.desktop.helpers.managers.FileSystemWatcher
 import eu.mjdev.desktop.helpers.managers.KCEFHelper
 import eu.mjdev.desktop.provider.AIProvider.AiPluginGemini
+import eu.mjdev.desktop.windows.WindowsTracker
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import java.awt.GraphicsDevice
@@ -29,7 +30,8 @@ class DesktopProvider(
     val connection: ConnectivityManager = ConnectivityManager(),
 //    val scriptManager: ScriptEngineManager = ScriptEngineManager(),
     val kcefHelper: KCEFHelper = KCEFHelper(scope),
-    val aiProvider: AIProvider = AIProvider(scope, AiPluginGemini(scope))
+    val aiProvider: AIProvider = AIProvider(scope, AiPluginGemini(scope)),
+    val windowsTracker: WindowsTracker = WindowsTracker()
 ) {
     private val __currentUser: User by lazy { User.load() }
     private val _currentUser: MutableState<User> = mutableStateOf(__currentUser)

+ 94 - 2
src/main/kotlin/eu/mjdev/desktop/windows/WindowsTracker.kt

@@ -1,13 +1,105 @@
 package eu.mjdev.desktop.windows
 
+import com.sun.jna.Native
+import com.sun.jna.platform.unix.X11
+import com.sun.jna.platform.unix.X11.*
+import com.sun.jna.ptr.IntByReference
+import com.sun.jna.ptr.PointerByReference
+
 @Suppress("unused")
 class WindowsTracker {
+    private val x11: X11 = X11.INSTANCE
+    private val display: Display = x11.XOpenDisplay(null)
+    private val rootWindow: Window
+        get() = x11.XDefaultRootWindow(display)
+    val allWindows: List<SystemWindow>
+        get() = recurse(rootWindow, 0)
 
-    @Suppress("UNUSED_PARAMETER")
     fun getWindowByPid(
         pid: Long?
     ): IWindow? {
-        return null // todo
+        allWindows.forEachIndexed { idx, wn ->
+            println("$idx, ${wn.name}")
+        }
+        return if (pid == null) null else null
+    }
+
+    @Suppress("DEPRECATED_IDENTITY_EQUALS")
+    private fun recurse(root: Window, depth: Int): List<SystemWindow> {
+        return runCatching {
+            val windowList = mutableListOf<SystemWindow>()
+            val windowRef = WindowByReference()
+            val parentRef = WindowByReference()
+            val childrenRef = PointerByReference()
+            val childCountRef = IntByReference()
+            x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef)
+            if (childrenRef.value == null) return emptyList()
+            val ids: LongArray
+            if (Native.LONG_SIZE === java.lang.Long.BYTES) {
+                ids = childrenRef.value.getLongArray(0, childCountRef.value)
+            } else if (Native.LONG_SIZE === Integer.BYTES) {
+                val intIds: IntArray = childrenRef.value.getIntArray(0, childCountRef.value)
+                ids = LongArray(intIds.size)
+                for (i in intIds.indices) {
+                    ids[i] = intIds[i].toLong()
+                }
+            } else return emptyList()
+//            throw IllegalStateException("Unexpected size for Native.LONG_SIZE" + Native.LONG_SIZE)
+            for (id in ids) {
+                if (id == 0L) continue
+                val window = Window(id)
+                val name = XTextProperty()
+                val pids = mutableListOf<Long>()
+                // todo
+                x11.XGetWMName(display, window, name)
+//            x11.XGetWindowAttributes()
+//            x11.XGetGeometry()
+//            x11.XGetWMHints()
+//            x11.XGetVisualInfo()
+//            x11.XGetWindowProperty()
+//            x11.XGetKeyboardMapping()
+//            x11.XGetModifierMapping()
+//            x11.XGetKeyboardControl()
+                windowList.add(
+                    SystemWindow(
+                        this,
+                        id,
+                        name.value ?: "",
+                        pids
+                    )
+                )
+//                x11.XFree(name.getPointer())
+                recurse(window, depth + 1)
+            }
+            windowList
+        }.getOrNull() ?: emptyList()
+    }
+
+    class SystemWindow(
+        val windowTracker: WindowsTracker,
+        val id: Long,
+        val name: String,
+        val pids: List<Long>
+    ) : IWindow {
+        override fun toBack() {
+
+        }
+
+        override fun toFront() {
+
+        }
+
+        override fun minimize() {
+
+        }
+
+        override fun maximize() {
+
+        }
+
+        override fun close() {
+
+        }
     }
 
     interface IWindow {