diff --git a/src/main/kotlin/io/gitlab/jfronny/globalmenu/GlobalMenuService.kt b/src/main/kotlin/io/gitlab/jfronny/globalmenu/GlobalMenuService.kt index 8b47262..3b5db97 100644 --- a/src/main/kotlin/io/gitlab/jfronny/globalmenu/GlobalMenuService.kt +++ b/src/main/kotlin/io/gitlab/jfronny/globalmenu/GlobalMenuService.kt @@ -1,10 +1,16 @@ package io.gitlab.jfronny.globalmenu +import com.canonical.Dbusmenu +import com.canonical.appmenu.Registrar import com.intellij.openapi.application.Application import com.intellij.openapi.application.ApplicationActivationListener import com.intellij.openapi.wm.IdeFrame import com.intellij.openapi.wm.impl.IdeFrameImpl import com.intellij.openapi.wm.impl.ProjectFrameHelper +import io.gitlab.jfronny.globalmenu.proxy.DbusmenuImpl +import org.freedesktop.dbus.DBusPath +import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder +import org.freedesktop.dbus.types.UInt32 import javax.swing.JMenuBar class GlobalMenuService(private val app: Application) : ApplicationActivationListener { @@ -34,11 +40,20 @@ class GlobalMenuService(private val app: Application) : ApplicationActivationLis GlobalMenu.Log.warn("${submenu.text}.${component?.text}") } } - peer.performLocked { - val ptr = GlobalMenu.Native.create(peer.nativePtr) -// peer.registerCleaner { -// GlobalMenu.Native.destroy(ptr) -// } + val conn = DBusConnectionBuilder.forSessionBus().build() + + val menu: Dbusmenu = DbusmenuImpl() + // firefox seems to use mObjectPath(nsPrintfCString("/com/canonical/menu/%u", sID++)) + conn.exportObject("/com/canonical/dbusmenu", menu) + + if (peer is WLPeer) { + peer.performLocked { + val ptr = GlobalMenu.Native.create(peer.nativePtr) + GlobalMenu.Native.setAddress(ptr, conn.uniqueName, menu.objectPath) + } + } else { + val registrar = conn.getRemoteObject("org.canonical.AppMenu.Registrar", "/com/canonical/AppMenu/Registrar", Registrar::class.java) + registrar.RegisterWindow(UInt32(peer.nativePtr), DBusPath(menu.objectPath)) } } } \ No newline at end of file diff --git a/src/main/kotlin/io/gitlab/jfronny/globalmenu/Reflect.kt b/src/main/kotlin/io/gitlab/jfronny/globalmenu/Reflect.kt index 6d54769..bccaaa2 100644 --- a/src/main/kotlin/io/gitlab/jfronny/globalmenu/Reflect.kt +++ b/src/main/kotlin/io/gitlab/jfronny/globalmenu/Reflect.kt @@ -15,18 +15,36 @@ private val peerField = Component::class.java.getDeclaredField("peer").apply { i val Component.peer: Peer get() = Peer(peerField.get(this)) -private val componentPeerClass = Class.forName("sun.awt.wl.WLComponentPeer") -private val performLockedMethod = Reflect.instanceProcedure(componentPeerClass, "performLocked", Runnable::class.java).unchecked1 -private val nativePtrField = componentPeerClass.getDeclaredField("nativePtr").apply { setAccessible(this) } +sealed interface Peer { + val nativePtr: Long +} +fun Peer(peer: Any): Peer { + if (X11Peer.componentPeerClass.isInstance(peer)) return X11Peer(peer) + if (WLPeer.componentPeerClass.isInstance(peer)) return WLPeer(peer) + throw IllegalArgumentException("Unknown peer type: ${peer.javaClass}") +} +class X11Peer(private val inner: Any) : Peer { + override val nativePtr: Long get() = getPtrMethod(inner) -class Peer(private val inner: Any) { - val nativePtr: Long get() = nativePtrField.getLong(inner) + companion object { + val componentPeerClass = Class.forName("sun.awt.X11.XComponentPeer") + private val getPtrMethod = Reflect.instanceFunction(componentPeerClass, "getWindow", Long::class.java).unchecked + } +} +class WLPeer(private val inner: Any) : Peer { + override val nativePtr: Long get() = nativePtrField.getLong(inner) fun performLocked(runnable: Runnable) { performLockedMethod(inner, runnable) } fun registerCleaner(runnable: Runnable) { GlobalMenu.Cleaner.register(this, runnable) } + + companion object { + val componentPeerClass = Class.forName("sun.awt.wl.WLComponentPeer") + private val performLockedMethod = Reflect.instanceProcedure(componentPeerClass, "performLocked", Runnable::class.java).unchecked1 + private val nativePtrField = componentPeerClass.getDeclaredField("nativePtr").apply { setAccessible(this) } + } } private val wlDisplayClass = Class.forName("sun.awt.wl.WLDisplay") diff --git a/src/main/kotlin/io/gitlab/jfronny/globalmenu/proxy/DbusmenuImpl.kt b/src/main/kotlin/io/gitlab/jfronny/globalmenu/proxy/DbusmenuImpl.kt new file mode 100644 index 0000000..c1ab4e9 --- /dev/null +++ b/src/main/kotlin/io/gitlab/jfronny/globalmenu/proxy/DbusmenuImpl.kt @@ -0,0 +1,58 @@ +package io.gitlab.jfronny.globalmenu.proxy + +import com.canonical.* +import org.freedesktop.dbus.types.UInt32 +import org.freedesktop.dbus.types.Variant + +class DbusmenuImpl : Dbusmenu { + override fun getObjectPath(): String { + TODO("Not yet implemented") + } + + override fun getVersion(): UInt32 { + TODO("Not yet implemented") + } + + override fun getTextDirection(): String { + TODO("Not yet implemented") + } + + override fun getStatus(): String { + TODO("Not yet implemented") + } + + override fun getIconThemePath(): Dbusmenu.PropertyIconThemePathType { + TODO("Not yet implemented") + } + + override fun GetLayout(parentId: Int, recursionDepth: Int, propertyNames: MutableList?): GetLayoutTuple { + TODO("Not yet implemented") + } + + override fun GetGroupProperties( + ids: MutableList?, + propertyNames: MutableList? + ): MutableList { + TODO("Not yet implemented") + } + + override fun GetProperty(id: Int, name: String?): Variant<*> { + TODO("Not yet implemented") + } + + override fun Event(id: Int, eventId: String?, data: Variant<*>?, timestamp: UInt32?) { + TODO("Not yet implemented") + } + + override fun EventGroup(events: MutableList?): MutableList { + TODO("Not yet implemented") + } + + override fun AboutToShow(id: Int): Boolean { + TODO("Not yet implemented") + } + + override fun AboutToShowGroup(ids: MutableList?): AboutToShowGroupTuple { + TODO("Not yet implemented") + } +}