Moved the JVM entry point to start when needed
This commit is contained in:
1 parent
5eab7a2c20
commit
bf12743457
25 files changed
+748
-784
No files matched your search
@@ -5,13 +5,14 @@ import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.lwjgl.glfw.CallbackBridge;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import net.kdt.pojavlaunch.uikit.*;
|
||||
import net.kdt.pojavlaunch.utils.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
|
||||
public class PLaunchApp {
|
||||
private static float currProgress, maxProgress;
|
||||
private static float currProgress, maxProgress;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {
|
||||
@@ -20,57 +21,56 @@ public class PLaunchApp {
|
||||
// Not on JRE8, ignore exception
|
||||
}
|
||||
|
||||
// User might remove the minecraft folder, this can cause crashes, safety re-create it
|
||||
try {
|
||||
File mcDir = new File(Tools.DIR_GAME_NEW);
|
||||
mcDir.mkdirs();
|
||||
new File(Tools.DIR_ACCOUNT_NEW).mkdirs();
|
||||
if (!new File(mcDir.getAbsolutePath() + "/launcher_profiles.json").exists()) {
|
||||
Tools.write(mcDir.getAbsolutePath() + "/launcher_profiles.json",
|
||||
Tools.read(Tools.DIR_BUNDLE + "/launcher_profiles.json"));
|
||||
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
|
||||
public void uncaughtException(Thread t, Throwable th) {
|
||||
Tools.showError(th);
|
||||
// Block this thread from exiting
|
||||
while (true) {}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("We are on java now! Starting UI...");
|
||||
UIKit.launchUI();
|
||||
}
|
||||
System.setProperty("cacio.managed.screensize", args[2]);
|
||||
|
||||
public static String getStringFromPref(String pref) {
|
||||
try {
|
||||
String plistContent = Tools.read(Tools.DIR_APP_DATA + "/launcher_preferences.plist");
|
||||
plistContent = plistContent.substring(plistContent.indexOf("<key>" + pref + "</key>") + pref.length() + 11);
|
||||
return plistContent.substring(
|
||||
plistContent.indexOf("<string>") + 8,
|
||||
plistContent.indexOf("</string>"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
if (args[0].equals(".LaunchJAR")) {
|
||||
UIKit.callback_JavaGUIViewController_launchJarFile(args[1]);
|
||||
} else {
|
||||
launchMinecraft(args);
|
||||
}
|
||||
}
|
||||
|
||||
// Called from SurfaceViewController
|
||||
public static void launchMinecraft() {
|
||||
try {
|
||||
MinecraftAccount account = MinecraftAccount.load(getStringFromPref("internal_selected_account"));
|
||||
JMinecraftVersionList.Version version = Tools.getVersionInfo(getStringFromPref("selected_version"));
|
||||
System.out.println("Launching Minecraft " + version.id);
|
||||
String configPath;
|
||||
if (version.logging != null) {
|
||||
if (version.logging.client.file.id.equals("client-1.12.xml")) {
|
||||
configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.12.xml";
|
||||
} else if (version.logging.client.file.id.equals("client-1.7.xml")) {
|
||||
configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.7.xml";
|
||||
} else {
|
||||
configPath = Tools.DIR_GAME_NEW + "/" + version.logging.client.file.id;
|
||||
}
|
||||
System.setProperty("log4j.configurationFile", configPath);
|
||||
public static void launchMinecraft(String[] args) throws Throwable {
|
||||
String[] size = args[2].split("x");
|
||||
|
||||
MCOptionUtils.load();
|
||||
MCOptionUtils.set("overrideWidth", size[0]);
|
||||
MCOptionUtils.set("overrideHeight", size[1]);
|
||||
MCOptionUtils.save();
|
||||
|
||||
System.setProperty("org.lwjgl.opengl.libname", System.getenv("POJAV_RENDERER"));
|
||||
|
||||
Tools.mGLFWWindowWidth = Integer.parseInt(size[0]);
|
||||
Tools.mGLFWWindowHeight = Integer.parseInt(size[1]);
|
||||
//GLFW.internalChangeMonitorSize(width, height);
|
||||
//CallbackBridge.mouseX = width / 2;
|
||||
//CallbackBridge.mouseY = height / 2;
|
||||
|
||||
MinecraftAccount account = MinecraftAccount.load(args[0]);
|
||||
JMinecraftVersionList.Version version = Tools.getVersionInfo(args[1]);
|
||||
System.out.println("Launching Minecraft " + version.id);
|
||||
String configPath;
|
||||
if (version.logging != null) {
|
||||
if (version.logging.client.file.id.equals("client-1.12.xml")) {
|
||||
configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.12.xml";
|
||||
} else if (version.logging.client.file.id.equals("client-1.7.xml")) {
|
||||
configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.7.xml";
|
||||
} else {
|
||||
configPath = Tools.DIR_GAME_NEW + "/" + version.logging.client.file.id;
|
||||
}
|
||||
Tools.launchMinecraft(account, version);
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(th);
|
||||
System.setProperty("log4j.configurationFile", configPath);
|
||||
}
|
||||
|
||||
Tools.launchMinecraft(account, version);
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
@@ -37,12 +37,7 @@ import net.kdt.pojavlaunch.utils.JSONUtils;
|
||||
import net.kdt.pojavlaunch.value.DependentLibrary;
|
||||
import net.kdt.pojavlaunch.value.MinecraftAccount;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
/*
|
||||
import org.robovm.apple.foundation.*;
|
||||
import org.robovm.apple.uikit.*;
|
||||
import org.robovm.pods.dialog.*;
|
||||
import org.robovm.pods.*;
|
||||
*/
|
||||
|
||||
public final class Tools
|
||||
{
|
||||
public static final boolean ENABLE_DEV_FEATURES = true; // BuildConfig.DEBUG;
|
||||
@@ -78,6 +73,8 @@ public final class Tools
|
||||
|
||||
public static final String LIBNAME_OPTIFINE = "optifine:OptiFine";
|
||||
|
||||
volatile public static int mGLFWWindowWidth, mGLFWWindowHeight;
|
||||
|
||||
public static void launchMinecraft(MinecraftAccount profile, final JMinecraftVersionList.Version versionInfo) throws Throwable {
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
if (javaVersion.startsWith("1.")) {
|
||||
@@ -125,31 +122,27 @@ public final class Tools
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
new Thread(() -> { try {
|
||||
System.out.println("Args init finished. Now starting game");
|
||||
|
||||
// URLClassLoader loader = new URLClassLoader(urlList.toArray(new URL[0]), ClassLoader.getSystemClassLoader());
|
||||
|
||||
PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader();
|
||||
// add launcher.jar itself
|
||||
loader.addURL(Tools.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL());
|
||||
for (String s : launchClassPath.split(":")) {
|
||||
if (!s.isEmpty()) {
|
||||
loader.addURL(new File(s).toURI().toURL());
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> clazz = loader.loadClass(versionInfo.mainClass);
|
||||
Method method = clazz.getMethod("main", String[].class);
|
||||
method.invoke(null, new Object[]{launchArgs});
|
||||
|
||||
// throw new RuntimeException("Game exited. Check latestlog.txt for more details.");
|
||||
} catch (Throwable th) {
|
||||
showError(th);
|
||||
System.out.println("Args init finished. Now starting game");
|
||||
|
||||
// URLClassLoader loader = new URLClassLoader(urlList.toArray(new URL[0]), ClassLoader.getSystemClassLoader());
|
||||
|
||||
PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader();
|
||||
// add launcher.jar itself
|
||||
loader.addURL(Tools.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL());
|
||||
for (String s : launchClassPath.split(":")) {
|
||||
if (!s.isEmpty()) {
|
||||
loader.addURL(new File(s).toURI().toURL());
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> clazz = loader.loadClass(versionInfo.mainClass);
|
||||
Method method = clazz.getMethod("main", String[].class);
|
||||
method.invoke(null, new Object[]{launchArgs});
|
||||
|
||||
// throw new RuntimeException("Game exited. Check latestlog.txt for more details.");
|
||||
|
||||
}).start();
|
||||
//}).start();
|
||||
|
||||
// JREUtils.launchJavaVM(javaArgList);
|
||||
}
|
||||
@@ -203,13 +196,13 @@ public final class Tools
|
||||
}
|
||||
}
|
||||
minecraftArgs.add("--width");
|
||||
minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowWidth));
|
||||
minecraftArgs.add(Integer.toString(mGLFWWindowWidth));
|
||||
minecraftArgs.add("--height");
|
||||
minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowHeight));
|
||||
minecraftArgs.add(Integer.toString(mGLFWWindowHeight));
|
||||
minecraftArgs.add("--fullscreenWidth");
|
||||
minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowWidth));
|
||||
minecraftArgs.add(Integer.toString(mGLFWWindowWidth));
|
||||
minecraftArgs.add("--fullscreenHeight");
|
||||
minecraftArgs.add(Integer.toString(GLFW.mGLFWWindowHeight));
|
||||
minecraftArgs.add(Integer.toString(mGLFWWindowHeight));
|
||||
String[] argsFromJson = JSONUtils.insertJSONValueList(
|
||||
splitAndFilterEmpty(
|
||||
versionInfo.minecraftArguments == null ?
|
||||
|
||||
@@ -29,9 +29,7 @@ public class UIKit {
|
||||
System.setProperty("os.name", osName);
|
||||
}
|
||||
|
||||
public static void callback_JavaGUIViewController_launchJarFile(final String filepath, int width, int height) {
|
||||
System.setProperty("cacio.managed.screensize", width + "x" + height);
|
||||
|
||||
public static void callback_JavaGUIViewController_launchJarFile(final String filepath) throws Throwable {
|
||||
// Thread for refreshing the AWT buffer
|
||||
new Thread(() -> {
|
||||
try {
|
||||
@@ -58,49 +56,27 @@ public class UIKit {
|
||||
}
|
||||
}, "AWTFBRefreshThread").start();
|
||||
|
||||
// Thread for launching the JAR file
|
||||
new Thread(() -> {
|
||||
String mainClassName = null;
|
||||
try {
|
||||
JarFile jarfile = new JarFile(filepath);
|
||||
String mainClass = jarfile.getManifest().getMainAttributes().getValue("Main-Class");
|
||||
jarfile.close();
|
||||
if (mainClass == null) {
|
||||
throw new IllegalArgumentException("no main manifest attribute, in \"" + filepath + "\"");
|
||||
}
|
||||
// Launch the JAR file
|
||||
String mainClassName = null;
|
||||
|
||||
PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader();
|
||||
loader.addURL(new File(filepath).toURI().toURL());
|
||||
JarFile jarfile = new JarFile(filepath);
|
||||
String mainClass = jarfile.getManifest().getMainAttributes().getValue("Main-Class");
|
||||
jarfile.close();
|
||||
if (mainClass == null) {
|
||||
throw new IllegalArgumentException("no main manifest attribute, in \"" + filepath + "\"");
|
||||
}
|
||||
|
||||
// LabyMod Installer uses FlatLAF which has some macOS-specific codes, so we make it thinks it's running on Linux.
|
||||
patch_FlatLAF_setLinux();
|
||||
PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader();
|
||||
loader.addURL(new File(filepath).toURI().toURL());
|
||||
|
||||
Class<?> clazz = loader.loadClass(mainClass);
|
||||
Method method = clazz.getMethod("main", String[].class);
|
||||
method.invoke(null, new Object[]{new String[]{}});
|
||||
// LabyMod Installer uses FlatLAF which has some macOS-specific codes, so we make it thinks it's running on Linux.
|
||||
patch_FlatLAF_setLinux();
|
||||
|
||||
// throw new RuntimeException("Application exited");
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(th, true);
|
||||
}
|
||||
}, "ModInstallerThread").start();
|
||||
Class<?> clazz = loader.loadClass(mainClass);
|
||||
Method method = clazz.getMethod("main", String[].class);
|
||||
method.invoke(null, new Object[]{new String[]{}});
|
||||
}
|
||||
|
||||
public static void callback_SurfaceViewController_launchMinecraft(int width, int height, String rendererLibName) {
|
||||
MCOptionUtils.load();
|
||||
MCOptionUtils.set("overrideWidth", Integer.toString(width));
|
||||
MCOptionUtils.set("overrideHeight", Integer.toString(height));
|
||||
MCOptionUtils.save();
|
||||
|
||||
System.setProperty("cacio.managed.screensize", width + "x" + height);
|
||||
System.setProperty("org.lwjgl.opengl.libname", rendererLibName);
|
||||
|
||||
GLFW.internalChangeMonitorSize(width, height);
|
||||
CallbackBridge.mouseX = width / 2;
|
||||
CallbackBridge.mouseY = height / 2;
|
||||
PLaunchApp.launchMinecraft();
|
||||
}
|
||||
|
||||
public static void callback_SurfaceViewController_onTouch(int event, float x, float y) {
|
||||
switch (event) {
|
||||
case ACTION_DOWN:
|
||||
@@ -110,7 +86,7 @@ public class UIKit {
|
||||
CallbackBridge.mouseY = y;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ACTION_MOVE:
|
||||
if (GLFW.mGLFWIsGrabbing) {
|
||||
CallbackBridge.mouseX += x - CallbackBridge.mouseLastX;
|
||||
@@ -136,7 +112,7 @@ public class UIKit {
|
||||
String str = MCOptionUtils.get("guiScale");
|
||||
guiScale = (str == null ? 0 :Integer.parseInt(str));
|
||||
|
||||
int scale = Math.max(Math.min(GLFW.mGLFWWindowWidth / 320, GLFW.mGLFWWindowHeight / 240), 1);
|
||||
int scale = Math.max(Math.min(Tools.mGLFWWindowWidth / 320, Tools.mGLFWWindowHeight / 240), 1);
|
||||
if(scale < guiScale || guiScale == 0){
|
||||
guiScale = scale;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.nio.*;
|
||||
|
||||
import javax.annotation.*;
|
||||
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
|
||||
import org.lwjgl.*;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.system.*;
|
||||
@@ -484,7 +486,6 @@ public class GLFW
|
||||
/* volatile */ public static GLFWWindowRefreshCallback mGLFWWindowRefreshCallback;
|
||||
/* volatile */ public static GLFWWindowSizeCallback mGLFWWindowSizeCallback;
|
||||
|
||||
volatile public static int mGLFWWindowWidth, mGLFWWindowHeight;
|
||||
volatile public static double mGLFWCursorX, mGLFWCursorY, mGLFWCursorLastX, mGLFWCursorLastY;
|
||||
|
||||
private static GLFWGammaRamp mGLFWGammaRamp;
|
||||
@@ -499,23 +500,26 @@ public class GLFW
|
||||
public static boolean mGLFWIsGrabbing, mGLFWIsInputReady, mGLFWIsUseStackQueue = false;
|
||||
public static final byte[] keyDownBuffer = new byte[317];
|
||||
public static long mainContext = 0;
|
||||
static {
|
||||
try {
|
||||
static {
|
||||
try {
|
||||
System.load(System.getenv("BUNDLE_PATH") + "/PojavLauncher");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Minecraft triggers a glfwPollEvents() on splash screen, so update window size there.
|
||||
CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE, mGLFWWindowWidth, mGLFWWindowHeight, 0, 0);
|
||||
CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_WINDOW_SIZE, mGLFWWindowWidth, mGLFWWindowHeight, 0, 0);
|
||||
|
||||
mGLFWErrorCallback = GLFWErrorCallback.createPrint();
|
||||
mGLFWKeyCodes = new ArrayMap<>();
|
||||
// Minecraft triggers a glfwPollEvents() on splash screen, so update window size there.
|
||||
// TODO objc-rewrite: commented out for testing only
|
||||
//CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight, 0, 0);
|
||||
//CallbackBridge.receiveCallback(CallbackBridge.EVENT_TYPE_WINDOW_SIZE, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight, 0, 0);
|
||||
|
||||
mGLFWErrorCallback = GLFWErrorCallback.createPrint();
|
||||
mGLFWKeyCodes = new ArrayMap<>();
|
||||
|
||||
mGLFWWindowMap = new ArrayMap<>();
|
||||
|
||||
mGLFWVideoMode = new GLFWVidMode(ByteBuffer.allocateDirect(GLFWVidMode.SIZEOF));
|
||||
internalChangeMonitorSize(Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight);
|
||||
|
||||
/*
|
||||
memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.REDBITS, 8);
|
||||
memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.GREENBITS, 8);
|
||||
@@ -593,10 +597,10 @@ public class GLFW
|
||||
}
|
||||
|
||||
public static void internalChangeMonitorSize(int width, int height) {
|
||||
mGLFWWindowWidth = width;
|
||||
mGLFWWindowHeight = height;
|
||||
memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.WIDTH, mGLFWWindowWidth);
|
||||
memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.HEIGHT, mGLFWWindowHeight);
|
||||
Tools.mGLFWWindowWidth = width;
|
||||
Tools.mGLFWWindowHeight = height;
|
||||
memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.WIDTH, Tools.mGLFWWindowWidth);
|
||||
memPutInt(mGLFWVideoMode.address() + (long) mGLFWVideoMode.HEIGHT, Tools.mGLFWWindowHeight);
|
||||
}
|
||||
|
||||
public static GLFWWindowProperties internalGetWindow(long window) {
|
||||
@@ -671,7 +675,7 @@ public class GLFW
|
||||
|
||||
/*
|
||||
try {
|
||||
mGLFWFramebufferSizeCallback.invoke(window, mGLFWWindowWidth, mGLFWWindowHeight);
|
||||
mGLFWFramebufferSizeCallback.invoke(window, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight);
|
||||
} catch (Throwable th) {}
|
||||
*/
|
||||
|
||||
@@ -781,7 +785,7 @@ public class GLFW
|
||||
mGLFWWindowSizeCallback = GLFWWindowSizeCallback.createSafe(nglfwSetWindowSizeCallback(window, memAddressSafe(cbfun)));
|
||||
|
||||
try {
|
||||
mGLFWWindowSizeCallback.invoke(window, mGLFWWindowWidth, mGLFWWindowHeight);
|
||||
mGLFWWindowSizeCallback.invoke(window, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
return lastCallback;
|
||||
@@ -855,8 +859,8 @@ public class GLFW
|
||||
|
||||
xpos.put(0);
|
||||
ypos.put(0);
|
||||
width.put(mGLFWWindowWidth);
|
||||
height.put(mGLFWWindowHeight);
|
||||
width.put(Tools.mGLFWWindowWidth);
|
||||
height.put(Tools.mGLFWWindowHeight);
|
||||
}
|
||||
|
||||
@NativeType("GLFWmonitor *")
|
||||
@@ -1101,11 +1105,11 @@ public class GLFW
|
||||
case CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE:
|
||||
case CallbackBridge.EVENT_TYPE_WINDOW_SIZE:
|
||||
internalChangeMonitorSize((int)dataArr[1], (int)dataArr[2]);
|
||||
glfwSetWindowSize(ptr, mGLFWWindowWidth, mGLFWWindowHeight);
|
||||
glfwSetWindowSize(ptr, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight);
|
||||
if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE && mGLFWFramebufferSizeCallback != null) {
|
||||
mGLFWFramebufferSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight);
|
||||
mGLFWFramebufferSizeCallback.invoke(ptr, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight);
|
||||
} else if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_WINDOW_SIZE && mGLFWWindowSizeCallback != null) {
|
||||
mGLFWWindowSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight);
|
||||
mGLFWWindowSizeCallback.invoke(ptr, Tools.mGLFWWindowWidth, Tools.mGLFWWindowHeight);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1303,8 +1307,8 @@ return false;
|
||||
|
||||
xpos[0] = 0;
|
||||
ypos[0] = 0;
|
||||
width[0] = mGLFWWindowWidth;
|
||||
height[0] = mGLFWWindowHeight;
|
||||
width[0] = Tools.mGLFWWindowWidth;
|
||||
height[0] = Tools.mGLFWWindowHeight;
|
||||
}
|
||||
|
||||
/** Array version of: {@link #glfwGetMonitorPhysicalSize GetMonitorPhysicalSize} */
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package org.lwjgl.glfw;
|
||||
|
||||
import java.util.*;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
|
||||
public class GLFWWindowProperties {
|
||||
public int width = GLFW.mGLFWWindowWidth;
|
||||
public int height = GLFW.mGLFWWindowHeight;
|
||||
public int width = Tools.mGLFWWindowWidth;
|
||||
public int height = Tools.mGLFWWindowHeight;
|
||||
public float x, y;
|
||||
public CharSequence title;
|
||||
public boolean shouldClose, isInitialSizeCalled, isCursorEntered;
|
||||
|
||||
Reference in new issue
Block a user