mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
On desktop, replace Gdx clipboard with a proxy using AWT (#11857)
This commit is contained in:
parent
e5e52fe916
commit
1c25839ddb
42
desktop/src/com/unciv/app/desktop/AwtClipboard.kt
Normal file
42
desktop/src/com/unciv/app/desktop/AwtClipboard.kt
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.unciv.app.desktop
|
||||||
|
|
||||||
|
import java.awt.Toolkit
|
||||||
|
import java.awt.datatransfer.DataFlavor
|
||||||
|
import java.awt.datatransfer.StringSelection
|
||||||
|
import java.awt.datatransfer.Clipboard as ClipboardAwt
|
||||||
|
import com.badlogic.gdx.utils.Clipboard as ClipboardGdx
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plug-in replacement for Gdx Lwjgl3Clipboard that goes through AWT instead of GLFW and removes the stack size limitation.
|
||||||
|
*
|
||||||
|
* Gdx.app.clipboard on desktop is a Lwjgl3Clipboard instance, which allocates a buffer on the stack for UTF8 conversion at the Lwjgl3-GLFW interface.
|
||||||
|
* The default stack size is a severe limitation, which we **originally** treated by increasing the limit, which can only be done statically at launch time:
|
||||||
|
```
|
||||||
|
// 386 is an almost-arbitrary choice from the saves I had at the moment and their GZipped size.
|
||||||
|
// There must be a reason for lwjgl3 being so stingy, which for me meant to stay conservative.
|
||||||
|
System.setProperty("org.lwjgl.system.stackSize", "384")
|
||||||
|
```
|
||||||
|
* - See [setContents](https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-lwjgl3/src/com/badlogic/gdx/backends/lwjgl3/Lwjgl3Clipboard.java#L40)
|
||||||
|
* - See [glfwSetClipboardString](https://github.com/LWJGL/lwjgl3/blob/master/modules/lwjgl/glfw/src/generated/java/org/lwjgl/glfw/GLFW.java#L5068-L5077)
|
||||||
|
* - See [Higher available clipboard size](https://github.com/orgs/LWJGL/discussions/769)
|
||||||
|
*/
|
||||||
|
class AwtClipboard : ClipboardGdx {
|
||||||
|
// A lazy seems to work too, but not keeping a reference when not active is safer (also debuggable while a lazy is not):
|
||||||
|
private val clipboard: ClipboardAwt
|
||||||
|
get() = Toolkit.getDefaultToolkit().systemClipboard
|
||||||
|
|
||||||
|
override fun hasContents(): Boolean {
|
||||||
|
return DataFlavor.stringFlavor in clipboard.availableDataFlavors
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getContents(): String? {
|
||||||
|
val transferable = clipboard.getContents(null)
|
||||||
|
if (!transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) return null
|
||||||
|
return transferable.getTransferData(DataFlavor.stringFlavor) as String
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setContents(content: String?) {
|
||||||
|
val selection = StringSelection(content) // Yes this supports null
|
||||||
|
clipboard.setContents(selection, selection)
|
||||||
|
}
|
||||||
|
}
|
@ -36,10 +36,6 @@ internal object DesktopLauncher {
|
|||||||
// Solves a rendering problem in specific GPUs and drivers.
|
// Solves a rendering problem in specific GPUs and drivers.
|
||||||
// For more info see https://github.com/yairm210/Unciv/pull/3202 and https://github.com/LWJGL/lwjgl/issues/119
|
// For more info see https://github.com/yairm210/Unciv/pull/3202 and https://github.com/LWJGL/lwjgl/issues/119
|
||||||
System.setProperty("org.lwjgl.opengl.Display.allowSoftwareOpenGL", "true")
|
System.setProperty("org.lwjgl.opengl.Display.allowSoftwareOpenGL", "true")
|
||||||
// This setting (default 64) limits clipboard transfers. Value in kB!
|
|
||||||
// 386 is an almost-arbitrary choice from the saves I had at the moment and their GZipped size.
|
|
||||||
// There must be a reason for lwjgl3 being so stingy, which for me meant to stay conservative.
|
|
||||||
System.setProperty("org.lwjgl.system.stackSize", "384")
|
|
||||||
|
|
||||||
val isRunFromJAR = DesktopLauncher.javaClass.`package`.specificationVersion != null
|
val isRunFromJAR = DesktopLauncher.javaClass.`package`.specificationVersion != null
|
||||||
ImagePacker.packImages(isRunFromJAR)
|
ImagePacker.packImages(isRunFromJAR)
|
||||||
|
@ -6,10 +6,18 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
|||||||
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio
|
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio
|
||||||
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALMusic
|
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALMusic
|
||||||
import com.badlogic.gdx.utils.Array
|
import com.badlogic.gdx.utils.Array
|
||||||
|
import com.badlogic.gdx.utils.Clipboard
|
||||||
import com.unciv.ui.audio.MusicController
|
import com.unciv.ui.audio.MusicController
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Problem: Not all exceptions playing Music can be caught on the desktop platform using a try-catch around the play method.
|
* ### Notes
|
||||||
|
* - Since this is the one replacement wrapping Lwjgl3Application that will be running Unciv-desktop, and we want to replace Gdx.app.clipboard,
|
||||||
|
* the hook for [AwtClipboard] is implemented here as [getClipboard] override.
|
||||||
|
* - ***This class is never properly initialized before use!*** (because the super constructor runs until the game is quit.)
|
||||||
|
* Therefore, fields must be initialized on-demand or from upstream UncivGame
|
||||||
|
*
|
||||||
|
* ### Problem
|
||||||
|
* Not all exceptions playing Music can be caught on the desktop platform using a try-catch around the play method.
|
||||||
* Unciv 3.17.13 to 4.0.5 all exacerbated the problem due to using Music from various threads - and Gdx documents it isn't threadsafe.
|
* Unciv 3.17.13 to 4.0.5 all exacerbated the problem due to using Music from various threads - and Gdx documents it isn't threadsafe.
|
||||||
* But even with that fixed, music streams can have codec failures _after_ the first buffer's worth of data, so the problem is only mitigated.
|
* But even with that fixed, music streams can have codec failures _after_ the first buffer's worth of data, so the problem is only mitigated.
|
||||||
*
|
*
|
||||||
@ -18,7 +26,7 @@ import com.unciv.ui.audio.MusicController
|
|||||||
*
|
*
|
||||||
* This catches those Exceptions and reports them through a callback mechanism, and also provides a callback from the app loop
|
* This catches those Exceptions and reports them through a callback mechanism, and also provides a callback from the app loop
|
||||||
* that allows MusicController to make its Music calls on a thread guaranteed to be safe for OpenALMusic.
|
* that allows MusicController to make its Music calls on a thread guaranteed to be safe for OpenALMusic.
|
||||||
* #
|
*
|
||||||
* ### Approach:
|
* ### Approach:
|
||||||
* - Subclass [OpenALLwjgl3Audio] overriding [update][OpenALLwjgl3Audio.update] with equivalent code catching any Exceptions and Errors
|
* - Subclass [OpenALLwjgl3Audio] overriding [update][OpenALLwjgl3Audio.update] with equivalent code catching any Exceptions and Errors
|
||||||
* - Get the framework to use the subclassed Audio by overriding Lwjgl3ApplicationBase.createAudio
|
* - Get the framework to use the subclassed Audio by overriding Lwjgl3ApplicationBase.createAudio
|
||||||
@ -46,6 +54,7 @@ class HardenGdxAudio(
|
|||||||
) : Lwjgl3Application(game, config) {
|
) : Lwjgl3Application(game, config) {
|
||||||
private var updateCallback: (()->Unit)? = null
|
private var updateCallback: (()->Unit)? = null
|
||||||
private var exceptionHandler: ((Throwable, Music)->Unit)? = null
|
private var exceptionHandler: ((Throwable, Music)->Unit)? = null
|
||||||
|
private lateinit var awtClipboard: AwtClipboard // normal initialization won't run, including initializing lazy delegates!
|
||||||
|
|
||||||
/** Hooks part 1
|
/** Hooks part 1
|
||||||
*
|
*
|
||||||
@ -69,6 +78,12 @@ class HardenGdxAudio(
|
|||||||
this.exceptionHandler = exceptionHandler
|
this.exceptionHandler = exceptionHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** This redirects `Gdx.app.clipboard` on desktop to our [AwtClipboard] replacement */
|
||||||
|
override fun getClipboard(): Clipboard {
|
||||||
|
if (!::awtClipboard.isInitialized) awtClipboard = AwtClipboard()
|
||||||
|
return awtClipboard
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Desktop implementation of the [Audio][com.badlogic.gdx.Audio] interface that
|
* Desktop implementation of the [Audio][com.badlogic.gdx.Audio] interface that
|
||||||
* unlike its superclass catches exceptions and allows passing them into application code for handling.
|
* unlike its superclass catches exceptions and allows passing them into application code for handling.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user