Merge branch 'v3_openjdk' into feat/quick_settings

This commit is contained in:
Maksim Belov 2024-11-26 21:05:02 +03:00 committed by GitHub
commit eb6b23c76e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 325 additions and 149 deletions

View File

@ -5,7 +5,7 @@
[![Android CI](https://github.com/PojavLauncherTeam/PojavLauncher/workflows/Android%20CI/badge.svg)](https://github.com/PojavLauncherTeam/PojavLauncher/actions)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/PojavLauncherTeam/PojavLauncher)](https://github.com/PojavLauncherTeam/PojavLauncher/actions)
[![Crowdin](https://badges.crowdin.net/pojavlauncher/localized.svg)](https://crowdin.com/project/pojavlauncher)
[![Discord](https://img.shields.io/discord/724163890803638273.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.com/invite/pojavlauncher-724163890803638273)
[![Discord](https://img.shields.io/discord/724163890803638273.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.com/invite/aenk3EUvER)
[![Twitter Follow](https://img.shields.io/twitter/follow/plaunchteam?color=blue&style=flat-square)](https://twitter.com/PLaunchTeam)
* From [Boardwalk](https://github.com/zhuowei/Boardwalk)'s ashes here comes PojavLauncher!

View File

@ -442,38 +442,20 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
if(touchCharInput != null) touchCharInput.switchKeyboardState();
}
private static void setUri(Context context, String input, Intent intent) {
if(input.startsWith("file:")) {
int truncLength = 5;
if(input.startsWith("file://")) truncLength = 7;
input = input.substring(truncLength);
Log.i("MainActivity", input);
boolean isDirectory = new File(input).isDirectory();
if(isDirectory) {
intent.setType(DocumentsContract.Document.MIME_TYPE_DIR);
}else{
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(input);
if(extension != null) type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if(type == null) type = "*/*";
intent.setType(type);
}
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setData(DocumentsContract.buildDocumentUri(
context.getString(R.string.storageProviderAuthorities), input
));
return;
}
intent.setDataAndType(Uri.parse(input), "*/*");
}
public static void openLink(String link) {
Context ctx = touchpad.getContext(); // no more better way to obtain a context statically
((Activity)ctx).runOnUiThread(() -> {
try {
if(link.startsWith("file:")) {
int truncLength = 5;
if(link.startsWith("file://")) truncLength = 7;
String path = link.substring(truncLength);
Tools.openPath(ctx, new File(path), false);
}else {
Intent intent = new Intent(Intent.ACTION_VIEW);
setUri(ctx, link, intent);
intent.setDataAndType(Uri.parse(link), "*/*");
ctx.startActivity(intent);
}
} catch (Throwable th) {
Tools.showError(ctx, th);
}
@ -484,9 +466,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
Context ctx = touchpad.getContext(); // no more better way to obtain a context statically
((Activity)ctx).runOnUiThread(() -> {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(DocumentsContract.buildDocumentUri(ctx.getString(R.string.storageProviderAuthorities), path), "*/*");
ctx.startActivity(intent);
Tools.openPath(ctx, new File(path), false);
} catch (Throwable th) {
Tools.showError(ctx, th);
}

View File

@ -78,6 +78,7 @@ import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
import org.lwjgl.glfw.CallbackBridge;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -88,6 +89,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
@ -1192,17 +1194,55 @@ public final class Tools {
/** Triggers the share intent chooser, with the latestlog file attached to it */
public static void shareLog(Context context){
Uri contentUri = DocumentsContract.buildDocumentUri(context.getString(R.string.storageProviderAuthorities), Tools.DIR_GAME_HOME + "/latestlog.txt");
openPath(context, new File(Tools.DIR_GAME_HOME, "latestlog.txt"), true);
}
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shareIntent.setType("text/plain");
/**
* Determine the MIME type of a File.
* @param file The file to determine the type of
* @return the type, or the default value *slash* if cannot be determined
*/
public static String getMimeType(File file) {
if(file.isDirectory()) return DocumentsContract.Document.MIME_TYPE_DIR;
String mimeType = null;
try (FileInputStream fileInputStream = new FileInputStream(file)){
// Theoretically we don't even need the buffer since we don't care about the
// contents of the file after the guess, but mark-supported streams
// are a requirement of URLConnection.guessContentTypeFromStream()
try(BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) {
mimeType = URLConnection.guessContentTypeFromStream(bufferedInputStream);
}
}catch (IOException e) {
Log.w("FileMimeType", "Failed to determine MIME type by stream", e);
}
if(mimeType != null) return mimeType;
mimeType = URLConnection.guessContentTypeFromName(file.getName());
if(mimeType != null) return mimeType;
return "*/*";
}
Intent sendIntent = Intent.createChooser(shareIntent, "latestlog.txt");
context.startActivity(sendIntent);
/**
* Open the path specified by a File in a file explorer or in a relevant application.
* @param context the current Context
* @param file the File to open
* @param share whether to open a "Share" or an "Open" dialog.
*/
public static void openPath(Context context, File file, boolean share) {
Uri contentUri = DocumentsContract.buildDocumentUri(context.getString(R.string.storageProviderAuthorities), file.getAbsolutePath());
String mimeType = getMimeType(file);
Intent intent = new Intent();
if(share) {
intent.setAction(Intent.ACTION_SEND);
intent.setType(getMimeType(file));
intent.putExtra(Intent.EXTRA_STREAM, contentUri);
}else {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(contentUri, mimeType);
}
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooserIntent = Intent.createChooser(intent, file.getName());
context.startActivity(chooserIntent);
}
/** Mesure the textview height, given its current parameters */

View File

@ -1,5 +1,6 @@
package net.kdt.pojavlaunch.fragments;
import static net.kdt.pojavlaunch.Tools.openPath;
import static net.kdt.pojavlaunch.Tools.shareLog;
import android.content.Intent;
@ -20,7 +21,12 @@ import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.extra.ExtraConstants;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
import java.io.File;
public class MainMenuFragment extends Fragment {
public static final String TAG = "MainMenuFragment";
@ -38,6 +44,7 @@ public class MainMenuFragment extends Fragment {
Button mCustomControlButton = view.findViewById(R.id.custom_control_button);
Button mInstallJarButton = view.findViewById(R.id.install_jar_button);
Button mShareLogsButton = view.findViewById(R.id.share_logs_button);
Button mOpenDirectoryButton = view.findViewById(R.id.open_files_button);
ImageButton mEditProfileButton = view.findViewById(R.id.edit_profile_button);
Button mPlayButton = view.findViewById(R.id.play_button);
@ -57,12 +64,24 @@ public class MainMenuFragment extends Fragment {
mShareLogsButton.setOnClickListener((v) -> shareLog(requireContext()));
mOpenDirectoryButton.setOnClickListener((v)-> openPath(v.getContext(), getCurrentProfileDirectory(), false));
mNewsButton.setOnLongClickListener((v)->{
Tools.swapFragment(requireActivity(), GamepadMapperFragment.class, GamepadMapperFragment.TAG, null);
return true;
});
}
private File getCurrentProfileDirectory() {
String currentProfile = LauncherPreferences.DEFAULT_PREF.getString(LauncherPreferences.PREF_KEY_CURRENT_PROFILE, null);
if(!Tools.isValidString(currentProfile)) return new File(Tools.DIR_GAME_NEW);
LauncherProfiles.load();
MinecraftProfile profileObject = LauncherProfiles.mainProfileJson.profiles.get(currentProfile);
if(profileObject == null) return new File(Tools.DIR_GAME_NEW);
return Tools.getGameDirPath(profileObject);
}
@Override
public void onResume() {
super.onResume();

View File

@ -34,6 +34,7 @@ LOCAL_SHARED_LIBRARIES := bytehook
LOCAL_SRC_FILES := \
bigcoreaffinity.c \
egl_bridge.c \
ctxbridges/loader_dlopen.c \
ctxbridges/gl_bridge.c \
ctxbridges/osm_bridge.c \
ctxbridges/egl_loader.c \

View File

@ -5,6 +5,7 @@
#include <stdlib.h>
#include <dlfcn.h>
#include "egl_loader.h"
#include "loader_dlopen.h"
EGLBoolean (*eglMakeCurrent_p) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EGLBoolean (*eglDestroyContext_p) (EGLDisplay dpy, EGLContext ctx);
@ -24,28 +25,38 @@ EGLint (*eglGetError_p) (void);
EGLContext (*eglCreateContext_p) (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
EGLBoolean (*eglSwapInterval_p) (EGLDisplay dpy, EGLint interval);
EGLSurface (*eglGetCurrentSurface_p) (EGLint readdraw);
EGLBoolean (*eglQuerySurface_p)( EGLDisplay display,
EGLSurface surface,
EGLint attribute,
EGLint * value);
__eglMustCastToProperFunctionPointerType (*eglGetProcAddress_p) (const char *procname);
void dlsym_EGL() {
void* dl_handle = NULL;
if(getenv("POJAVEXEC_EGL")) dl_handle = dlopen(getenv("POJAVEXEC_EGL"), RTLD_LAZY);
if(dl_handle == NULL) dl_handle = dlopen("libEGL.so", RTLD_LAZY);
if(dl_handle == NULL) abort();
eglBindAPI_p = dlsym(dl_handle,"eglBindAPI");
eglChooseConfig_p = dlsym(dl_handle, "eglChooseConfig");
eglCreateContext_p = dlsym(dl_handle, "eglCreateContext");
eglCreatePbufferSurface_p = dlsym(dl_handle, "eglCreatePbufferSurface");
eglCreateWindowSurface_p = dlsym(dl_handle, "eglCreateWindowSurface");
eglDestroyContext_p = dlsym(dl_handle, "eglDestroyContext");
eglDestroySurface_p = dlsym(dl_handle, "eglDestroySurface");
eglGetConfigAttrib_p = dlsym(dl_handle, "eglGetConfigAttrib");
eglGetCurrentContext_p = dlsym(dl_handle, "eglGetCurrentContext");
eglGetDisplay_p = dlsym(dl_handle, "eglGetDisplay");
eglGetError_p = dlsym(dl_handle, "eglGetError");
eglInitialize_p = dlsym(dl_handle, "eglInitialize");
eglMakeCurrent_p = dlsym(dl_handle, "eglMakeCurrent");
eglSwapBuffers_p = dlsym(dl_handle, "eglSwapBuffers");
eglReleaseThread_p = dlsym(dl_handle, "eglReleaseThread");
eglSwapInterval_p = dlsym(dl_handle, "eglSwapInterval");
eglTerminate_p = dlsym(dl_handle, "eglTerminate");
eglGetCurrentSurface_p = dlsym(dl_handle,"eglGetCurrentSurface");
bool dlsym_EGL() {
void* dl_handle = loader_dlopen(getenv("POJAVEXEC_EGL"),"libEGL.so", RTLD_LOCAL|RTLD_LAZY);
if(dl_handle == NULL) return false;
eglGetProcAddress_p = dlsym(dl_handle, "eglGetProcAddress");
if(eglGetProcAddress_p == NULL) {
printf("%s\n", dlerror());
return false;
}
eglBindAPI_p = (void*) eglGetProcAddress_p("eglBindAPI");
eglChooseConfig_p = (void*) eglGetProcAddress_p("eglChooseConfig");
eglCreateContext_p = (void*) eglGetProcAddress_p("eglCreateContext");
eglCreatePbufferSurface_p = (void*) eglGetProcAddress_p("eglCreatePbufferSurface");
eglCreateWindowSurface_p = (void*) eglGetProcAddress_p("eglCreateWindowSurface");
eglDestroyContext_p = (void*) eglGetProcAddress_p("eglDestroyContext");
eglDestroySurface_p = (void*) eglGetProcAddress_p("eglDestroySurface");
eglGetConfigAttrib_p = (void*) eglGetProcAddress_p("eglGetConfigAttrib");
eglGetCurrentContext_p = (void*) eglGetProcAddress_p("eglGetCurrentContext");
eglGetDisplay_p = (void*) eglGetProcAddress_p("eglGetDisplay");
eglGetError_p = (void*) eglGetProcAddress_p("eglGetError");
eglInitialize_p = (void*) eglGetProcAddress_p("eglInitialize");
eglMakeCurrent_p = (void*) eglGetProcAddress_p("eglMakeCurrent");
eglSwapBuffers_p = (void*) eglGetProcAddress_p("eglSwapBuffers");
eglReleaseThread_p = (void*) eglGetProcAddress_p("eglReleaseThread");
eglSwapInterval_p = (void*) eglGetProcAddress_p("eglSwapInterval");
eglTerminate_p = (void*) eglGetProcAddress_p("eglTerminate");
eglGetCurrentSurface_p = (void*) eglGetProcAddress_p("eglGetCurrentSurface");
eglQuerySurface_p = (void*) eglGetProcAddress_p("eglQuerySurface");
return true;
}

View File

@ -2,6 +2,7 @@
// Created by maks on 21.09.2022.
//
#include <EGL/egl.h>
#include <stdbool.h>
#ifndef POJAVLAUNCHER_EGL_LOADER_H
#define POJAVLAUNCHER_EGL_LOADER_H
@ -23,7 +24,12 @@ extern EGLint (*eglGetError_p) (void);
extern EGLContext (*eglCreateContext_p) (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
extern EGLBoolean (*eglSwapInterval_p) (EGLDisplay dpy, EGLint interval);
extern EGLSurface (*eglGetCurrentSurface_p) (EGLint readdraw);
extern EGLBoolean (*eglQuerySurface_p)( EGLDisplay display,
EGLSurface surface,
EGLint attribute,
EGLint * value);
extern __eglMustCastToProperFunctionPointerType (*eglGetProcAddress_p) (const char *procname);
void dlsym_EGL();
bool dlsym_EGL();
#endif //POJAVLAUNCHER_EGL_LOADER_H

View File

@ -20,7 +20,7 @@ static __thread gl_render_window_t* currentBundle;
static EGLDisplay g_EglDisplay;
bool gl_init() {
dlsym_EGL();
if(!dlsym_EGL()) return false;
g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
if (g_EglDisplay == EGL_NO_DISPLAY) {
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s",
@ -39,6 +39,41 @@ gl_render_window_t* gl_get_current() {
return currentBundle;
}
static void gl4esi_get_display_dimensions(int* width, int* height) {
if(currentBundle == NULL) goto zero;
EGLSurface surface = currentBundle->surface;
// Fetch dimensions from the EGL surface - the most reliable way
EGLBoolean result_width = eglQuerySurface_p(g_EglDisplay, surface, EGL_WIDTH, width);
EGLBoolean result_height = eglQuerySurface_p(g_EglDisplay, surface, EGL_HEIGHT, height);
if(!result_width || !result_height) goto zero;
return;
zero:
// No idea what to do, but feeding gl4es incorrect or non-initialized dimensions may be
// a bad idea. Set to zero in case of errors.
*width = 0;
*height = 0;
}
static bool already_initialized = false;
static void gl_init_gl4es_internals() {
if(already_initialized) return;
already_initialized = true;
void* gl4es = dlopen("libgl4es_114.so", RTLD_NOLOAD);
if(gl4es == NULL) return;
void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height));
set_getmainfbsize = dlsym(gl4es, "set_getmainfbsize");
if(set_getmainfbsize == NULL) goto warn;
set_getmainfbsize(gl4esi_get_display_dimensions);
goto cleanup;
warn:
printf("gl4esinternals warning: gl4es was found but internals not initialized. expect rendering issues.\n");
cleanup:
// dlclose just decreases a ref counter, so this is fine
dlclose(gl4es);
}
gl_render_window_t* gl_init_context(gl_render_window_t *share) {
gl_render_window_t* bundle = malloc(sizeof(gl_render_window_t));
memset(bundle, 0, sizeof(gl_render_window_t));
@ -110,6 +145,11 @@ void gl_swap_surface(gl_render_window_t* bundle) {
}
void gl_make_current(gl_render_window_t* bundle) {
// Perform initialization here as the renderer may not be loaded when gl_init or gl_init_context is called.
// Yes, even though it is dlopened on MC startup by Pojav, due to linker namespacing weirdness
// on API 29/MIUI it may not be loaded at the point of the gl_init call in the current namespace.
gl_init_gl4es_internals();
if(bundle == NULL) {
if(eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
currentBundle = NULL;

View File

@ -0,0 +1,24 @@
//
// Created by maks on 26.10.2024.
//
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include <linux/limits.h>
void* loader_dlopen(char* primaryName, char* secondaryName, int flags) {
void* dl_handle;
if(primaryName == NULL) goto secondary;
dl_handle = dlopen(primaryName, flags);
if(dl_handle != NULL) return dl_handle;
if(secondaryName == NULL) goto dl_error;
secondary:
dl_handle = dlopen(secondaryName, flags);
if(dl_handle == NULL) goto dl_error;
return dl_handle;
dl_error:
printf("%s", dlerror());
return NULL;
}

View File

@ -0,0 +1,10 @@
//
// Created by maks on 26.10.2024.
//
#ifndef POJAVLAUNCHER_LOADER_DLOPEN_H
#define POJAVLAUNCHER_LOADER_DLOPEN_H
void* loader_dlopen(char* primaryName, char* secondaryName, int flags);
#endif //POJAVLAUNCHER_LOADER_DLOPEN_H

View File

@ -16,8 +16,8 @@ static char no_render_buffer[4];
void setNativeWindowSwapInterval(struct ANativeWindow* nativeWindow, int swapInterval);
bool osm_init() {
dlsym_OSMesa();
return true; // no more specific initialization required
if(!dlsym_OSMesa()) return false;
return true;
}
osm_render_window_t* osm_get_current() {

View File

@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "loader_dlopen.h"
#include "osmesa_loader.h"
GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum type,
@ -17,26 +18,25 @@ void (*glFinish_p) (void);
void (*glClearColor_p) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void (*glClear_p) (GLbitfield mask);
void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data);
void* (*OSMesaGetProcAddress_p)(const char* funcName);
void dlsym_OSMesa() {
char* main_path = NULL;
char* alt_path = NULL;
if(asprintf(&main_path, "%s/libOSMesa.so", getenv("POJAV_NATIVEDIR")) == -1 ||
asprintf(&alt_path, "%s/libOSMesa.so.8", getenv("POJAV_NATIVEDIR")) == -1) {
abort();
bool dlsym_OSMesa() {
void* dl_handle = loader_dlopen("libOSMesa.so.8", "libOSMesa.so", RTLD_LOCAL | RTLD_LAZY);
if(dl_handle == NULL) return false;
OSMesaGetProcAddress_p = dlsym(dl_handle, "OSMesaGetProcAddress");
if(OSMesaGetProcAddress_p == NULL) {
printf("%s\n", dlerror());
return false;
}
void* dl_handle = NULL;
dl_handle = dlopen(alt_path, RTLD_GLOBAL);
if(dl_handle == NULL) dl_handle = dlopen(main_path, RTLD_GLOBAL);
if(dl_handle == NULL) abort();
OSMesaMakeCurrent_p = dlsym(dl_handle, "OSMesaMakeCurrent");
OSMesaGetCurrentContext_p = dlsym(dl_handle,"OSMesaGetCurrentContext");
OSMesaCreateContext_p = dlsym(dl_handle, "OSMesaCreateContext");
OSMesaDestroyContext_p = dlsym(dl_handle, "OSMesaDestroyContext");
OSMesaPixelStore_p = dlsym(dl_handle,"OSMesaPixelStore");
glGetString_p = dlsym(dl_handle,"glGetString");
glClearColor_p = dlsym(dl_handle, "glClearColor");
glClear_p = dlsym(dl_handle,"glClear");
glFinish_p = dlsym(dl_handle,"glFinish");
glReadPixels_p = dlsym(dl_handle,"glReadPixels");
OSMesaMakeCurrent_p = OSMesaGetProcAddress_p("OSMesaMakeCurrent");
OSMesaGetCurrentContext_p = OSMesaGetProcAddress_p("OSMesaGetCurrentContext");
OSMesaCreateContext_p = OSMesaGetProcAddress_p("OSMesaCreateContext");
OSMesaDestroyContext_p = OSMesaGetProcAddress_p("OSMesaDestroyContext");
OSMesaPixelStore_p = OSMesaGetProcAddress_p("OSMesaPixelStore");
glGetString_p = OSMesaGetProcAddress_p("glGetString");
glClearColor_p = OSMesaGetProcAddress_p("glClearColor");
glClear_p = OSMesaGetProcAddress_p("glClear");
glFinish_p = OSMesaGetProcAddress_p("glFinish");
glReadPixels_p = OSMesaGetProcAddress_p("glReadPixels");
return true;
}

View File

@ -6,6 +6,7 @@
#define POJAVLAUNCHER_OSMESA_LOADER_H
#include <GL/osmesa.h>
#include <stdbool.h>
extern GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum type,
GLsizei width, GLsizei height);
@ -18,5 +19,7 @@ extern void (*glFinish_p) (void);
extern void (*glClearColor_p) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
extern void (*glClear_p) (GLbitfield mask);
extern void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data);
void dlsym_OSMesa();
extern void* (*OSMesaGetProcAddress_p)(const char* funcName);
bool dlsym_OSMesa();
#endif //POJAVLAUNCHER_OSMESA_LOADER_H

View File

@ -546,17 +546,38 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSetShowingWindow(__attribut
}
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint attrib, jint value) {
if (!pojav_environ->showingWindow || !pojav_environ->isUseStackQueueCall) {
// Check for stack queue no longer necessary here as the JVM crash's origin is resolved
if (!pojav_environ->showingWindow) {
// If the window is not shown, there is nothing to do yet.
// For Minecraft < 1.13, calling to JNI functions here crashes the JVM for some reason, therefore it is skipped for now.
return;
}
(*pojav_environ->runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod(
pojav_environ->runtimeJNIEnvPtr_JRE,
pojav_environ->vmGlfwClass, pojav_environ->method_glftSetWindowAttrib,
// We cannot use pojav_environ->runtimeJNIEnvPtr_JRE here because that environment is attached
// on the thread that loaded pojavexec (which is the thread that first references the GLFW class)
// But this method is only called from the Android UI thread
// Technically the better solution would be to have a permanently attached env pointer stored
// in environ for the Android UI thread but this is the only place that uses it
// (very rarely, only in lifecycle callbacks) so i dont care
JavaVM* jvm = pojav_environ->runtimeJavaVMPtr;
JNIEnv *jvm_env = NULL;
jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4);
if(env_result == JNI_EDETACHED) {
env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL);
}
if(env_result != JNI_OK) {
printf("input_bridge nativeSetWindowAttrib() JNI call failed: %i\n", env_result);
return;
}
(*jvm_env)->CallStaticVoidMethod(
jvm_env, pojav_environ->vmGlfwClass,
pojav_environ->method_glftSetWindowAttrib,
(jlong) pojav_environ->showingWindow, attrib, value
);
// Attaching every time is annoying, so stick the attachment to the Android GUI thread around
}
const static JNINativeMethod critical_fcns[] = {
{"nativeSetUseInputStackQueue", "(Z)V", critical_set_stackqueue},

View File

@ -14,7 +14,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@id/mc_version_spinner"
app:layout_constraintBottom_toTopOf="@id/_background_display_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@ -30,11 +30,8 @@
app:layout_constraintGuide_percent="0.5"/>
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/news_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@drawable/ic_menu_news"
android:text="@string/mcl_tab_wiki"
app:layout_constraintTop_toTopOf="parent"
@ -42,9 +39,7 @@
app:layout_constraintEnd_toStartOf="@id/social_divider"/>
<View
android:id="@+id/social_divider"
android:layout_width="@dimen/padding_tiny"
android:layout_height="0dp"
android:background="@color/divider"
style="@style/LauncherFragment_Divider"
android:layout_marginVertical="@dimen/padding_heavy"
app:layout_constraintTop_toTopOf="@id/news_button"
app:layout_constraintStart_toStartOf="@id/center_guideline"
@ -52,11 +47,8 @@
app:layout_constraintBottom_toBottomOf="@id/news_button"/>
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/discord_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@drawable/ic_discord"
android:text="@string/mcl_button_discord"
app:layout_constraintTop_toTopOf="parent"
@ -65,36 +57,37 @@
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/custom_control_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@drawable/ic_menu_custom_controls"
android:text="@string/mcl_option_customcontrol"
app:layout_constraintTop_toBottomOf="@id/news_button"/>
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/install_jar_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@drawable/ic_menu_install_jar"
android:text="@string/main_install_jar_file"
app:layout_constraintTop_toBottomOf="@id/custom_control_button"/>
app:layout_constraintTop_toBottomOf="@id/custom_control_button"
tools:layout_editor_absoluteX="0dp" />
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/share_logs_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@android:drawable/ic_menu_share"
android:text="@string/main_share_logs"
app:layout_constraintTop_toBottomOf="@id/install_jar_button"/>
app:layout_constraintTop_toBottomOf="@id/install_jar_button" />
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/open_files_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:drawableStart="@drawable/ic_folder"
android:text="@string/mcl_button_open_directory"
app:layout_constraintTop_toBottomOf="@id/share_logs_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -26,10 +26,8 @@
app:layout_constraintGuide_percent="0.5"/>
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/news_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="0dp"
android:layout_height="@dimen/_66sdp"
android:background="?android:attr/selectableItemBackground"
android:text="@string/mcl_tab_wiki"
android:drawableStart="@drawable/ic_menu_news"
app:layout_constraintTop_toTopOf="parent"
@ -37,9 +35,7 @@
app:layout_constraintEnd_toStartOf="@id/social_divider" />
<View
android:id="@+id/social_divider"
android:layout_width="@dimen/padding_tiny"
android:layout_height="0dp"
android:background="@color/divider"
style="@style/LauncherFragment_Divider"
android:layout_marginVertical="@dimen/padding_large"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="@id/center_guideline"
@ -47,10 +43,8 @@
app:layout_constraintBottom_toBottomOf="@id/news_button"/>
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/discord_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="0dp"
android:layout_height="@dimen/_66sdp"
android:background="?android:attr/selectableItemBackground"
android:text="@string/mcl_button_discord"
android:drawableStart="@drawable/ic_discord"
app:layout_constraintTop_toTopOf="parent"
@ -60,36 +54,35 @@
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/custom_control_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:layout_height="@dimen/_66sdp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@drawable/ic_menu_custom_controls"
android:text="@string/mcl_option_customcontrol"
app:layout_constraintTop_toBottomOf="@id/news_button"
/>
app:layout_constraintTop_toBottomOf="@id/news_button" />
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/install_jar_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:layout_height="@dimen/_66sdp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@drawable/ic_menu_install_jar"
android:text="@string/main_install_jar_file"
app:layout_constraintTop_toBottomOf="@id/custom_control_button"
/>
app:layout_constraintTop_toBottomOf="@id/custom_control_button" />
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/share_logs_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:layout_height="@dimen/_66sdp"
android:background="?android:attr/selectableItemBackground"
android:drawableStart="@android:drawable/ic_menu_share"
android:text="@string/main_share_logs"
app:layout_constraintTop_toBottomOf="@id/install_jar_button" />
app:layout_constraintTop_toBottomOf="@id/install_jar_button"
/>
<com.kdt.mcgui.LauncherMenuButton
android:id="@+id/open_files_button"
style="@style/LauncherMenuButton.Universal"
android:layout_width="match_parent"
android:drawableStart="@drawable/ic_folder"
android:text="@string/mcl_button_open_directory"
app:layout_constraintTop_toBottomOf="@id/share_logs_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -12,4 +12,11 @@
<item name="android:textSize">@dimen/_14ssp</item>
</style>
<style name="LauncherMenuButton.Universal" parent="LauncherMenuButton">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:layout_marginBottom">8dp</item>
</style>
</resources>

View File

@ -416,7 +416,8 @@
<string name="preference_remap_controller_title">Change controller key bindings</string>
<string name="preference_remap_controller_description">Allows you to modify the keyboard keys bound to each controller button</string>
<string name="mcl_button_discord">Discord</string>
<string name="discord_invite" translatable="false">https://discord.gg/pojavlauncher-724163890803638273</string>
<string name="mcl_button_open_directory">Open game directory</string>
<string name="discord_invite" translatable="false">https://discord.com/invite/aenk3EUvER</string>
<string name="local_login_bad_username_title">Unsuitable username</string>
<string name="local_login_bad_username_text">The username must be between 316 characters long, and must only contain latin letters, arabic numerals and underscores.</string>
<string name="quick_setting_title">Quick settings</string>

View File

@ -13,6 +13,19 @@
</style>
<style name="LauncherFragment_Divider">
<item name="android:layout_width">@dimen/padding_tiny</item>
<item name="android:layout_height">0dp</item>
<item name="android:background">@color/divider</item>
</style>
<style name="LauncherMenuButton" parent="Widget.AppCompat.Button">
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
<style name="LauncherMenuButton.Universal" parent="LauncherMenuButton">
<item name="android:layout_height">@dimen/_66sdp</item>
</style>
<style name="ThickDivider">
<item name="android:layout_width">match_parent</item>

View File

@ -508,6 +508,7 @@ public class GLFW
private static ArrayMap<Long, GLFWWindowProperties> mGLFWWindowMap;
public static boolean mGLFWIsInputReady;
private static boolean mGLFWInputPumping;
private static boolean mGLFWWindowVisibleOnCreation = true;
public static final ByteBuffer keyDownBuffer = ByteBuffer.allocateDirect(317);
public static final ByteBuffer mouseDownBuffer = ByteBuffer.allocateDirect(8);
@ -988,11 +989,15 @@ public class GLFW
win.height = mGLFWWindowHeight;
win.title = title;
win.windowAttribs.put(GLFW_HOVERED, 1);
win.windowAttribs.put(GLFW_VISIBLE, 1);
mGLFWWindowMap.put(ptr, win);
mainContext = ptr;
if(mGLFWWindowVisibleOnCreation || monitor != 0) {
// Show window by default if GLFW_VISIBLE hint is specified on creation or
// if the monitor is nonnull (fullscreen requested)
glfwShowWindow(ptr);
}
return ptr;
//Return our context
}
@ -1009,7 +1014,9 @@ public class GLFW
nglfwSetShowingWindow(mGLFWWindowMap.size() == 0 ? 0 : mGLFWWindowMap.keyAt(mGLFWWindowMap.size() - 1));
}
public static void glfwDefaultWindowHints() {}
public static void glfwDefaultWindowHints() {
mGLFWWindowVisibleOnCreation = true;
}
public static void glfwGetWindowSize(long window, IntBuffer width, IntBuffer height) {
if (width != null) width.put(internalGetWindow(window).width);
@ -1032,10 +1039,17 @@ public class GLFW
}
public static void glfwShowWindow(long window) {
GLFWWindowProperties win = internalGetWindow(window);
win.windowAttribs.put(GLFW_HOVERED, 1);
win.windowAttribs.put(GLFW_VISIBLE, 1);
nglfwSetShowingWindow(window);
}
public static void glfwWindowHint(int hint, int value) {
if (hint == GLFW_VISIBLE) {
mGLFWWindowVisibleOnCreation = value == GLFW_TRUE;
return;
}
long __functionAddress = Functions.SetWindowHint;
invokeV(hint, value, __functionAddress);
}