feat: get the first menu to show
This commit is contained in:
parent
184ca19652
commit
9a813fbbaf
@ -33,7 +33,8 @@ dependencies {
|
|||||||
}
|
}
|
||||||
extraResources(project(mapOf("path" to ":native", "configuration" to "results")))
|
extraResources(project(mapOf("path" to ":native", "configuration" to "results")))
|
||||||
implementation("io.gitlab.jfronny:commons-unsafe:2.0.0-SNAPSHOT")
|
implementation("io.gitlab.jfronny:commons-unsafe:2.0.0-SNAPSHOT")
|
||||||
implementation("com.github.hypfvieh:dbus-java-core:5.0.0")
|
// implementation("com.github.hypfvieh:dbus-java-core:5.0.0")
|
||||||
|
// implementation("com.github.hypfvieh:dbus-java-transport-native-unixsocket:5.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
val copyExtraResources by tasks.creating(Copy::class) {
|
val copyExtraResources by tasks.creating(Copy::class) {
|
||||||
@ -66,25 +67,26 @@ abstract class InterfaceGenerateTask : DefaultTask() {
|
|||||||
false,
|
false,
|
||||||
introspectionData,
|
introspectionData,
|
||||||
objectPath.get(),
|
objectPath.get(),
|
||||||
busName.get(),
|
busName.get()
|
||||||
null,
|
|
||||||
true
|
|
||||||
)
|
)
|
||||||
val analyze = generator.analyze(true)!!
|
val analyze = generator.analyze(true)!!
|
||||||
if (analyze.isEmpty()) throw IllegalStateException("No interfaces found")
|
if (analyze.isEmpty()) throw IllegalStateException("No interfaces found")
|
||||||
@OptIn(ExperimentalPathApi::class)
|
@OptIn(ExperimentalPathApi::class)
|
||||||
output.deleteRecursively()
|
output.deleteRecursively()
|
||||||
output.createDirectories()
|
output.createDirectories()
|
||||||
val regex = Regex("List<org\\.freedesktop\\.dbus\\.Struct<Integer>, ([^_\\n]+)>")
|
val illegalStruct = Regex("List<org\\.freedesktop\\.dbus\\.Struct<Integer>, ([^_\\n]+)>")
|
||||||
val memory = LinkedHashMap<String, String>()
|
val illegalTuple = Regex("public ([A-Za-z]+Tuple) ")
|
||||||
|
val fieldPattern = Regex("@Position\\(\\d+\\)\\r?\\n +private (.+) [a-zA-Z]+;")
|
||||||
|
val structMemory = LinkedHashMap<String, String>()
|
||||||
|
val tupleMemory = LinkedHashMap<String, String>()
|
||||||
for (entry in analyze) {
|
for (entry in analyze) {
|
||||||
if (entry.key.path.equals("/.java")) continue // Skip incorrectly generated file
|
if (entry.key.path.equals("/.java") || entry.key.path.endsWith("Tuple.java")) continue // Skip incorrectly generated file
|
||||||
val pth = output.resolve(entry.key.path.trimStart('/'))
|
val pth = output.resolve(entry.key.path.trimStart('/'))
|
||||||
pth.createParentDirs()
|
pth.createParentDirs()
|
||||||
// Fix the incorrect generic type
|
// Fix the incorrect generic type
|
||||||
Files.writeString(pth, entry.value.replace(regex) { match ->
|
Files.writeString(pth, entry.value.replace(illegalStruct) { match ->
|
||||||
memory.computeIfAbsent(match.groups[1]!!.value) { type ->
|
structMemory.computeIfAbsent(match.groups[1]!!.value) { type ->
|
||||||
val name = "Struct${memory.size + 1}"
|
val name = "Struct${structMemory.size + 1}"
|
||||||
Files.writeString(output.resolve("com/canonical").resolve("$name.java"), """
|
Files.writeString(output.resolve("com/canonical").resolve("$name.java"), """
|
||||||
package com.canonical;
|
package com.canonical;
|
||||||
|
|
||||||
@ -107,6 +109,13 @@ abstract class InterfaceGenerateTask : DefaultTask() {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
}.replace(illegalTuple) { match ->
|
||||||
|
tupleMemory.computeIfAbsent(match.groups[1]!!.value) { type ->
|
||||||
|
val impl = analyze[analyze.keys.first { it.path.contains(type) }]!!
|
||||||
|
val found = fieldPattern.findAll(impl).toList()
|
||||||
|
if (found.size != 2) throw IllegalStateException("Tuple must have exactly two fields")
|
||||||
|
"io.gitlab.jfronny.globalmenu.DPair<${found[0].groups[1]!!.value}, ${found[1].groups[1]!!.value}>"
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.github.hypfvieh:dbus-java-utils:5.0.0")
|
classpath("com.github.hypfvieh:dbus-java-utils:4.3.2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
src/main/java/io/gitlab/jfronny/globalmenu/DPair.java
Normal file
30
src/main/java/io/gitlab/jfronny/globalmenu/DPair.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package io.gitlab.jfronny.globalmenu;
|
||||||
|
|
||||||
|
import org.freedesktop.dbus.Tuple;
|
||||||
|
import org.freedesktop.dbus.annotations.Position;
|
||||||
|
|
||||||
|
public class DPair<A, B> extends Tuple {
|
||||||
|
@Position(0) private A a;
|
||||||
|
@Position(1) private B b;
|
||||||
|
|
||||||
|
public DPair(A a, B b) {
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setA(A a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A getA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setB(B b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public B getB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package io.gitlab.jfronny.globalmenu
|
package io.gitlab.jfronny.globalmenu
|
||||||
|
|
||||||
import com.canonical.Dbusmenu
|
|
||||||
import com.canonical.appmenu.Registrar
|
import com.canonical.appmenu.Registrar
|
||||||
import com.intellij.openapi.application.Application
|
import com.intellij.openapi.application.Application
|
||||||
import com.intellij.openapi.application.ApplicationActivationListener
|
import com.intellij.openapi.application.ApplicationActivationListener
|
||||||
@ -8,6 +7,7 @@ import com.intellij.openapi.wm.IdeFrame
|
|||||||
import com.intellij.openapi.wm.impl.IdeFrameImpl
|
import com.intellij.openapi.wm.impl.IdeFrameImpl
|
||||||
import com.intellij.openapi.wm.impl.ProjectFrameHelper
|
import com.intellij.openapi.wm.impl.ProjectFrameHelper
|
||||||
import io.gitlab.jfronny.globalmenu.proxy.DbusmenuImpl
|
import io.gitlab.jfronny.globalmenu.proxy.DbusmenuImpl
|
||||||
|
import io.gitlab.jfronny.globalmenu.proxy.SwingMenuHolder
|
||||||
import org.freedesktop.dbus.DBusPath
|
import org.freedesktop.dbus.DBusPath
|
||||||
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
|
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
|
||||||
import org.freedesktop.dbus.types.UInt32
|
import org.freedesktop.dbus.types.UInt32
|
||||||
@ -20,8 +20,6 @@ class GlobalMenuService(private val app: Application) : ApplicationActivationLis
|
|||||||
ideFrame.project?.let { project ->
|
ideFrame.project?.let { project ->
|
||||||
println(ideFrame.javaClass)
|
println(ideFrame.javaClass)
|
||||||
if (ideFrame is ProjectFrameHelper) {
|
if (ideFrame is ProjectFrameHelper) {
|
||||||
// ideFrame.frame.jMenuBar = JMenuBar()
|
|
||||||
// ideFrame.rootPane.jMenuBar
|
|
||||||
visualize(ideFrame.rootPane.jMenuBar, ideFrame.rootPane.peer)
|
visualize(ideFrame.rootPane.jMenuBar, ideFrame.rootPane.peer)
|
||||||
} else if (ideFrame is IdeFrameImpl) {
|
} else if (ideFrame is IdeFrameImpl) {
|
||||||
visualize(ideFrame.jMenuBar, ideFrame.peer)
|
visualize(ideFrame.jMenuBar, ideFrame.peer)
|
||||||
@ -31,29 +29,21 @@ class GlobalMenuService(private val app: Application) : ApplicationActivationLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun visualize(menu: JMenuBar, peer: Peer) {
|
fun visualize(menu: JMenuBar, peer: Peer) {
|
||||||
GlobalMenu.Log.warn("Using peer: $peer")
|
|
||||||
//TODO send to compositor
|
|
||||||
for (i in 0 until menu.menuCount) {
|
|
||||||
val submenu = menu.getMenu(i)
|
|
||||||
for (j in 0 until submenu.itemCount) {
|
|
||||||
val component = submenu.getItem(j)
|
|
||||||
GlobalMenu.Log.warn("${submenu.text}.${component?.text}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val conn = DBusConnectionBuilder.forSessionBus().build()
|
val conn = DBusConnectionBuilder.forSessionBus().build()
|
||||||
|
|
||||||
val menu: Dbusmenu = DbusmenuImpl()
|
val windowPtr = peer.nativePtr
|
||||||
// firefox seems to use mObjectPath(nsPrintfCString("/com/canonical/menu/%u", sID++))
|
val menu = DbusmenuImpl(windowPtr, SwingMenuHolder(menu, "DBusMenuRoot"))
|
||||||
conn.exportObject("/com/canonical/dbusmenu", menu)
|
conn.unExportObject(menu.objectPath)
|
||||||
|
conn.exportObject(menu)
|
||||||
|
|
||||||
if (peer is WLPeer) {
|
if (peer is WLPeer) {
|
||||||
peer.performLocked {
|
peer.performLocked {
|
||||||
val ptr = GlobalMenu.Native.create(peer.nativePtr)
|
val ptr = GlobalMenu.Native.create(windowPtr)
|
||||||
GlobalMenu.Native.setAddress(ptr, conn.uniqueName, menu.objectPath)
|
GlobalMenu.Native.setAddress(ptr, conn.uniqueName, menu.objectPath)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val registrar = conn.getRemoteObject("org.canonical.AppMenu.Registrar", "/com/canonical/AppMenu/Registrar", Registrar::class.java)
|
val registrar = conn.getRemoteObject("org.canonical.AppMenu.Registrar", "/com/canonical/AppMenu/Registrar", Registrar::class.java)
|
||||||
registrar.RegisterWindow(UInt32(peer.nativePtr), DBusPath(menu.objectPath))
|
registrar.RegisterWindow(UInt32(windowPtr), DBusPath(menu.objectPath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,11 +19,14 @@ sealed interface Peer {
|
|||||||
val nativePtr: Long
|
val nativePtr: Long
|
||||||
}
|
}
|
||||||
fun Peer(peer: Any): Peer {
|
fun Peer(peer: Any): Peer {
|
||||||
if (X11Peer.componentPeerClass.isInstance(peer)) return X11Peer(peer)
|
if (peer.javaClass.name.contains("X11")) return X11Peer(peer)
|
||||||
if (WLPeer.componentPeerClass.isInstance(peer)) return WLPeer(peer)
|
if (peer.javaClass.name.contains("WL")) return WLPeer(peer)
|
||||||
throw IllegalArgumentException("Unknown peer type: ${peer.javaClass}")
|
throw IllegalArgumentException("Unknown peer type: ${peer.javaClass}")
|
||||||
}
|
}
|
||||||
class X11Peer(private val inner: Any) : Peer {
|
class X11Peer(private val inner: Any) : Peer {
|
||||||
|
init {
|
||||||
|
componentPeerClass.cast(inner)
|
||||||
|
}
|
||||||
override val nativePtr: Long get() = getPtrMethod(inner)
|
override val nativePtr: Long get() = getPtrMethod(inner)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -32,6 +35,9 @@ class X11Peer(private val inner: Any) : Peer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class WLPeer(private val inner: Any) : Peer {
|
class WLPeer(private val inner: Any) : Peer {
|
||||||
|
init {
|
||||||
|
componentPeerClass.cast(inner)
|
||||||
|
}
|
||||||
override val nativePtr: Long get() = nativePtrField.getLong(inner)
|
override val nativePtr: Long get() = nativePtrField.getLong(inner)
|
||||||
fun performLocked(runnable: Runnable) {
|
fun performLocked(runnable: Runnable) {
|
||||||
performLockedMethod(inner, runnable)
|
performLockedMethod(inner, runnable)
|
||||||
|
@ -1,58 +1,77 @@
|
|||||||
package io.gitlab.jfronny.globalmenu.proxy
|
package io.gitlab.jfronny.globalmenu.proxy
|
||||||
|
|
||||||
import com.canonical.*
|
import com.canonical.*
|
||||||
|
import io.gitlab.jfronny.globalmenu.DPair
|
||||||
import org.freedesktop.dbus.types.UInt32
|
import org.freedesktop.dbus.types.UInt32
|
||||||
import org.freedesktop.dbus.types.Variant
|
import org.freedesktop.dbus.types.Variant
|
||||||
|
|
||||||
class DbusmenuImpl : Dbusmenu {
|
class DbusmenuImpl(windowId: Long, private val menuHolder: MenuHolder) : Dbusmenu {
|
||||||
override fun getObjectPath(): String {
|
private val menuPath: String = "/com/canonical/menu0x${windowId.toString(16)}"
|
||||||
TODO("Not yet implemented")
|
override fun getObjectPath(): String = menuPath
|
||||||
|
// override fun getVersion(): UInt32 = UInt32(3)
|
||||||
|
// override fun getTextDirection(): String = "none"
|
||||||
|
// override fun getStatus(): String = "normal"
|
||||||
|
//
|
||||||
|
// override fun getIconThemePath(): Dbusmenu.PropertyIconThemePathType =
|
||||||
|
// object : Dbusmenu.PropertyIconThemePathType, List<String> by listOf() {}
|
||||||
|
|
||||||
|
override fun GetLayout(parentId: Int, recursionDepth: Int, propertyNames: MutableList<String>?): DPair<UInt32, GetLayoutStruct> {
|
||||||
|
return DPair(
|
||||||
|
UInt32(parentId.toLong()),
|
||||||
|
getLayout(parentId, recursionDepth, propertyNames, menuHolder.find(parentId)!!)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getVersion(): UInt32 {
|
private fun getLayout(parentId: Int, recursionDepth: Int, propertyNames: MutableList<String>?, menu: Menu): GetLayoutStruct {
|
||||||
TODO("Not yet implemented")
|
val properties = readProperties(menu)
|
||||||
|
val children = mutableListOf<Variant<*>>()
|
||||||
|
|
||||||
|
menu.children?.let {
|
||||||
|
for (sm in it) {
|
||||||
|
children.add(Variant(getLayout(parentId, recursionDepth, propertyNames, sm)))
|
||||||
|
}
|
||||||
|
if (it.isNotEmpty()) properties["children-display"] = Variant("submenu")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTextDirection(): String {
|
return GetLayoutStruct(menu.id, properties, children)
|
||||||
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<String>?): GetLayoutTuple {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun GetGroupProperties(
|
override fun GetGroupProperties(
|
||||||
ids: MutableList<Int>?,
|
ids: MutableList<Int>,
|
||||||
propertyNames: MutableList<String>?
|
propertyNames: MutableList<String>?
|
||||||
): MutableList<GetGroupPropertiesStruct> {
|
): MutableList<GetGroupPropertiesStruct> = mutableListOf<GetGroupPropertiesStruct>().apply {
|
||||||
TODO("Not yet implemented")
|
ids.forEach { id ->
|
||||||
|
menuHolder.find(id)?.let { menu ->
|
||||||
|
add(GetGroupPropertiesStruct(id, readProperties(menu)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun GetProperty(id: Int, name: String?): Variant<*> {
|
override fun GetProperty(id: Int, name: String?): Variant<*>? = menuHolder.find(id)?.let { menu -> readProperties(menu)[name] }
|
||||||
TODO("Not yet implemented")
|
|
||||||
|
private fun readProperties(menu: Menu): MutableMap<String, Variant<*>> {
|
||||||
|
if (menu.isSeparator) return mutableMapOf("type" to Variant("separator"))
|
||||||
|
val properties = mutableMapOf<String, Variant<*>>()
|
||||||
|
properties["type"] = Variant("standard")
|
||||||
|
properties["label"] = Variant(menu.label)
|
||||||
|
properties["visible"] = Variant(menu.isVisible)
|
||||||
|
properties["enabled"] = Variant(menu.isEnabled)
|
||||||
|
if (!menu.shortcut.isNullOrEmpty()) properties["shortcut"] = Variant(menu.shortcut)
|
||||||
|
if (!menu.toggleType.isNullOrEmpty()) {
|
||||||
|
properties["toggle-type"] = Variant(menu.toggleType)
|
||||||
|
properties["toggle-state"] = Variant(menu.toggleState)
|
||||||
|
}
|
||||||
|
if (menu.iconData?.isNotEmpty() == true) properties["icon-data"] = Variant(menu.iconData)
|
||||||
|
return properties
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Event(id: Int, eventId: String?, data: Variant<*>?, timestamp: UInt32?) {
|
override fun Event(id: Int, eventId: String?, data: Variant<*>?, timestamp: UInt32?) {
|
||||||
TODO("Not yet implemented")
|
if ("clicked".endsWith(eventId!!)) { //TODO this seems off
|
||||||
|
menuHolder.find(id)?.onEvent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun EventGroup(events: MutableList<EventGroupStruct>?): MutableList<Int> {
|
override fun EventGroup(events: MutableList<EventGroupStruct>?): MutableList<Int>? = null // not needed?
|
||||||
TODO("Not yet implemented")
|
override fun AboutToShow(id: Int): Boolean = true // not needed?
|
||||||
}
|
override fun AboutToShowGroup(ids: MutableList<Int>?): DPair<MutableList<Int>, MutableList<Int>>? = null // not needed?
|
||||||
|
|
||||||
override fun AboutToShow(id: Int): Boolean {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun AboutToShowGroup(ids: MutableList<Int>?): AboutToShowGroupTuple {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
15
src/main/kotlin/io/gitlab/jfronny/globalmenu/proxy/Menu.kt
Normal file
15
src/main/kotlin/io/gitlab/jfronny/globalmenu/proxy/Menu.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package io.gitlab.jfronny.globalmenu.proxy
|
||||||
|
|
||||||
|
interface Menu {
|
||||||
|
val id: Int
|
||||||
|
val isSeparator: Boolean
|
||||||
|
val label: String
|
||||||
|
val isEnabled: Boolean
|
||||||
|
val isVisible: Boolean
|
||||||
|
val iconData: ByteArray?
|
||||||
|
val shortcut: Array<String>?
|
||||||
|
val toggleType: String?
|
||||||
|
val toggleState: Int
|
||||||
|
val children: List<Menu>?
|
||||||
|
fun onEvent()
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package io.gitlab.jfronny.globalmenu.proxy
|
||||||
|
|
||||||
|
interface MenuHolder {
|
||||||
|
fun find(menuId: Int): Menu?
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package io.gitlab.jfronny.globalmenu.proxy
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.globalmenu.GlobalMenu
|
||||||
|
import org.apache.commons.io.output.ByteArrayOutputStream
|
||||||
|
import java.awt.event.ActionEvent
|
||||||
|
import java.awt.event.InputEvent
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
import java.util.*
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
import javax.swing.JCheckBoxMenuItem
|
||||||
|
import javax.swing.JMenu
|
||||||
|
import javax.swing.JMenuItem
|
||||||
|
import javax.swing.JRadioButtonMenuItem
|
||||||
|
|
||||||
|
class SwingMenu(private val menuItem: JMenuItem?, private val holder: SwingMenuHolder) : Menu {
|
||||||
|
override val id = holder.getId(menuItem)
|
||||||
|
override val isSeparator: Boolean get() = menuItem == null
|
||||||
|
override val label: String get() = menuItem?.text ?: ""
|
||||||
|
override val isEnabled: Boolean get() = menuItem?.isEnabled ?: false
|
||||||
|
override val isVisible: Boolean get() = menuItem?.isVisible ?: false
|
||||||
|
override val iconData: ByteArray? get() = menuItem?.icon?.let { icon ->
|
||||||
|
val width = icon.iconWidth
|
||||||
|
val height = icon.iconHeight
|
||||||
|
|
||||||
|
val bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
|
||||||
|
|
||||||
|
bufferedImage.createGraphics().apply {
|
||||||
|
icon.paintIcon(menuItem, this, 0, 0)
|
||||||
|
dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream().use { stream ->
|
||||||
|
ImageIO.write(bufferedImage, "png", stream)
|
||||||
|
stream.toByteArray()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
GlobalMenu.Log.error("Failed to convert icon to byte array", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val shortcut: Array<String>? get() = menuItem?.accelerator?.let { ks ->
|
||||||
|
val s = getModifiersText(ks.modifiers)
|
||||||
|
val vk = keyEvents[ks.keyCode] ?: "UNKNOWN"
|
||||||
|
val l = mutableListOf<String>()
|
||||||
|
val st = StringTokenizer(s)
|
||||||
|
while (st.hasMoreTokens()) l.add(st.nextToken())
|
||||||
|
l.add(vk)
|
||||||
|
l.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getModifiersText(modifiers: Int): String = buildString {
|
||||||
|
if (modifiers and InputEvent.SHIFT_DOWN_MASK != 0) append("Shift ")
|
||||||
|
if (modifiers and InputEvent.CTRL_DOWN_MASK != 0) append("Ctrl ")
|
||||||
|
if (modifiers and InputEvent.META_DOWN_MASK != 0) append("Meta ")
|
||||||
|
if (modifiers and InputEvent.ALT_DOWN_MASK != 0) append("Alt ")
|
||||||
|
if (modifiers and InputEvent.ALT_GRAPH_DOWN_MASK != 0) append("AltGraph ")
|
||||||
|
if (modifiers and InputEvent.BUTTON1_DOWN_MASK != 0) append("Button1 ")
|
||||||
|
if (modifiers and InputEvent.BUTTON2_DOWN_MASK != 0) append("Button2 ")
|
||||||
|
if (modifiers and InputEvent.BUTTON3_DOWN_MASK != 0) append("Button3 ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val toggleType: String? get() = when (menuItem) {
|
||||||
|
is JRadioButtonMenuItem -> "radio"
|
||||||
|
is JCheckBoxMenuItem -> "checkmark"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
override val toggleState: Int get() = if (toggleType?.isNotEmpty() == true) if (menuItem!!.isSelected) 1 else 0 else -1
|
||||||
|
override val children: List<Menu>? get() = if (menuItem is JMenu) {
|
||||||
|
(0 until menuItem.itemCount).map { SwingMenu(menuItem.getItem(it), holder) }
|
||||||
|
} else null
|
||||||
|
|
||||||
|
override fun onEvent() {
|
||||||
|
val event = ActionEvent(menuItem, ActionEvent.ACTION_PERFORMED, menuItem!!.actionCommand)
|
||||||
|
for (it in menuItem.actionListeners) it.actionPerformed(event)
|
||||||
|
if (menuItem is JCheckBoxMenuItem) menuItem.isSelected = !menuItem.isSelected
|
||||||
|
if (menuItem is JRadioButtonMenuItem) menuItem.isSelected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val keyEvents: Map<Int, String> = KeyEvent::class.java.fields
|
||||||
|
.filter { it.modifiers == Modifier.PUBLIC or Modifier.STATIC or Modifier.FINAL && it.name.startsWith("VK_") }
|
||||||
|
.associate { it.getInt(null) to it.name.substring(3) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package io.gitlab.jfronny.globalmenu.proxy
|
||||||
|
|
||||||
|
import javax.swing.JMenuBar
|
||||||
|
import javax.swing.JMenuItem
|
||||||
|
|
||||||
|
class SwingMenuHolder(bar: JMenuBar, menuName: String): MenuHolder {
|
||||||
|
private val root = SwingRootMenu((0 until bar.menuCount).map { bar.getMenu(it) }, menuName, this)
|
||||||
|
|
||||||
|
override fun find(menuId: Int): Menu? {
|
||||||
|
if (menuId == 0) return root
|
||||||
|
return find(root, menuId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun find(parent: Menu, menuId: Int): Menu? {
|
||||||
|
parent.children?.forEach {
|
||||||
|
if (it.id == menuId) return it
|
||||||
|
val found = find(it, menuId)
|
||||||
|
if (found != null) return found
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getId(menuItem: JMenuItem?): Int {
|
||||||
|
return System.identityHashCode(menuItem)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package io.gitlab.jfronny.globalmenu.proxy
|
||||||
|
|
||||||
|
import javax.swing.JMenuItem
|
||||||
|
|
||||||
|
class SwingRootMenu(private val menuItems: List<JMenuItem>?, private val name: String, private val holder: SwingMenuHolder): Menu {
|
||||||
|
override val id: Int get() = 0
|
||||||
|
override val isSeparator: Boolean get() = menuItems == null
|
||||||
|
override val label: String get() = name
|
||||||
|
override val isEnabled: Boolean get() = true
|
||||||
|
override val isVisible: Boolean get() = true
|
||||||
|
override val iconData: ByteArray? get() = null
|
||||||
|
override val shortcut: Array<String>? get() = null
|
||||||
|
override val toggleType: String? get() = null
|
||||||
|
override val toggleState: Int get() = 0
|
||||||
|
override val children: List<Menu>? get() = menuItems?.map { SwingMenu(it, holder) }
|
||||||
|
|
||||||
|
override fun onEvent() {
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user