mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-08-03 23:56:52 -04:00
Merge branch 'v3_openjdk' into feat/quick_settings
This commit is contained in:
commit
eb6b23c76e
@ -5,7 +5,7 @@
|
||||
[](https://github.com/PojavLauncherTeam/PojavLauncher/actions)
|
||||
[](https://github.com/PojavLauncherTeam/PojavLauncher/actions)
|
||||
[](https://crowdin.com/project/pojavlauncher)
|
||||
[](https://discord.com/invite/pojavlauncher-724163890803638273)
|
||||
[](https://discord.com/invite/aenk3EUvER)
|
||||
[](https://twitter.com/PLaunchTeam)
|
||||
|
||||
* From [Boardwalk](https://github.com/zhuowei/Boardwalk)'s ashes here comes PojavLauncher!
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
24
app_pojavlauncher/src/main/jni/ctxbridges/loader_dlopen.c
Normal file
24
app_pojavlauncher/src/main/jni/ctxbridges/loader_dlopen.c
Normal 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;
|
||||
}
|
10
app_pojavlauncher/src/main/jni/ctxbridges/loader_dlopen.h
Normal file
10
app_pojavlauncher/src/main/jni/ctxbridges/loader_dlopen.h
Normal 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
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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" />
|
||||
|
||||
<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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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 3–16 characters long, and must only contain latin letters, arabic numerals and underscores.</string>
|
||||
<string name="quick_setting_title">Quick settings</string>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user