mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-23 03:23:17 -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.
|
||||
// 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")
|
||||
// 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
|
||||
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.OpenALMusic
|
||||
import com.badlogic.gdx.utils.Array
|
||||
import com.badlogic.gdx.utils.Clipboard
|
||||
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.
|
||||
* 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
|
||||
* that allows MusicController to make its Music calls on a thread guaranteed to be safe for OpenALMusic.
|
||||
* #
|
||||
*
|
||||
* ### Approach:
|
||||
* - 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
|
||||
@ -46,6 +54,7 @@ class HardenGdxAudio(
|
||||
) : Lwjgl3Application(game, config) {
|
||||
private var updateCallback: (()->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
|
||||
*
|
||||
@ -69,6 +78,12 @@ class HardenGdxAudio(
|
||||
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
|
||||
* unlike its superclass catches exceptions and allows passing them into application code for handling.
|
||||
|
Loading…
x
Reference in New Issue
Block a user