diff --git a/app/src/main/cpp/lorie/InitOutput.c b/app/src/main/cpp/lorie/InitOutput.c index b70eb0d4a..6df219dc2 100644 --- a/app/src/main/cpp/lorie/InitOutput.c +++ b/app/src/main/cpp/lorie/InitOutput.c @@ -106,6 +106,9 @@ typedef struct { uint8_t flip; uint32_t width, height; } root; + + JavaVM* vm; + JNIEnv* env; } lorieScreenInfo, *lorieScreenInfoPtr; ScreenPtr pScreenPtr; @@ -345,7 +348,7 @@ static void lorieUpdateBuffer(void) { pScreenPtr->ModifyPixmapHeader(pScreenPtr->devPrivate, d0.width, d0.height, 32, 32, d0.stride * 4, data0); - renderer_set_buffer(new); + renderer_set_buffer(pvfb->env, new); } if (old) { @@ -421,11 +424,11 @@ static void lorieTimerCallback(int fd, unused int r, void *arg) { ScreenPtr pScreen = (ScreenPtr) arg; loriePixmapUnlock(pScreen->GetScreenPixmap(pScreen)); - redrawn = renderer_redraw(pvfb->root.flip); + redrawn = renderer_redraw(pvfb->env, pvfb->root.flip); if (loriePixmapLock(pScreen->GetScreenPixmap(pScreen)) && redrawn) DamageEmpty(pvfb->damage); } else if (pvfb->cursorMoved) - renderer_redraw(pvfb->root.flip); + renderer_redraw(pvfb->env, pvfb->root.flip); pvfb->cursorMoved = FALSE; } @@ -659,13 +662,13 @@ CursorForDevice(DeviceIntPtr pDev) { } Bool lorieChangeWindow(unused ClientPtr pClient, void *closure) { - struct ANativeWindow* win = (struct ANativeWindow*) closure; - renderer_set_window(win, pvfb->root.buffer); + jobject surface = (jobject) closure; + renderer_set_window(pvfb->env, surface, pvfb->root.buffer); lorieSetCursor(NULL, NULL, CursorForDevice(GetMaster(lorieMouse, MASTER_POINTER)), -1, -1); if (pvfb->root.legacyDrawing) { renderer_update_root(pScreenPtr->width, pScreenPtr->height, ((PixmapPtr) pScreenPtr->devPrivate)->devPrivate.ptr); - renderer_redraw(pvfb->root.flip); + renderer_redraw(pvfb->env, pvfb->root.flip); } return TRUE; @@ -726,6 +729,11 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv) { } } +void lorieSetVM(JavaVM* vm) { + pvfb->vm = vm; + (*vm)->AttachCurrentThread(vm, &pvfb->env, NULL); +} + static GLboolean drawableSwapBuffers(unused ClientPtr client, unused __GLXdrawable * drawable) { return TRUE; } static void drawableCopySubBuffer(unused __GLXdrawable * basePrivate, unused int x, unused int y, unused int w, unused int h) {} static __GLXdrawable * createDrawable(unused ClientPtr client, __GLXscreen * screen, DrawablePtr pDraw, diff --git a/app/src/main/cpp/lorie/android.c b/app/src/main/cpp/lorie/android.c index 41176e9c7..0939a19a8 100644 --- a/app/src/main/cpp/lorie/android.c +++ b/app/src/main/cpp/lorie/android.c @@ -70,6 +70,7 @@ typedef union { } lorieEvent; static void* startServer(unused void* cookie) { + lorieSetVM((JavaVM*) cookie); char* envp[] = { NULL }; exit(dix_main(argc, (char**) argv, envp)); } @@ -77,6 +78,7 @@ static void* startServer(unused void* cookie) { JNIEXPORT jboolean JNICALL Java_com_termux_x11_CmdEntryPoint_start(JNIEnv *env, unused jclass cls, jobjectArray args) { pthread_t t; + JavaVM* vm = NULL; // execv's argv array is a bit incompatible with Java's String[], so we do some converting here... argc = (*env)->GetArrayLength(env, args) + 1; // Leading executable path argv = (char**) calloc(argc, sizeof(char*)); @@ -189,30 +191,15 @@ Java_com_termux_x11_CmdEntryPoint_start(JNIEnv *env, unused jclass cls, jobjectA return JNI_FALSE; } - pthread_create(&t, NULL, startServer, NULL); + (*env)->GetJavaVM(env, &vm); + + pthread_create(&t, NULL, startServer, vm); return JNI_TRUE; } JNIEXPORT void JNICALL Java_com_termux_x11_CmdEntryPoint_windowChanged(JNIEnv *env, unused jobject cls, jobject surface) { - static jobject cached = NULL; - ANativeWindow* win = surface ? ANativeWindow_fromSurface(env, surface) : NULL; - - if (cached) { - jmethodID release = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, cached), "release", "()V"); - if (release) - (*env)->CallVoidMethod(env, cached, release); - (*env)->DeleteGlobalRef(env, cached); - } - - if (surface) - cached = (*env)->NewGlobalRef(env, surface); - - if (win) - ANativeWindow_acquire(win); - log(DEBUG, "window change: %p", win); - - QueueWorkProc(lorieChangeWindow, NULL, win); + QueueWorkProc(lorieChangeWindow, NULL, surface ? (*env)->NewGlobalRef(env, surface) : NULL); } void handleLorieEvents(int fd, maybe_unused int ready, maybe_unused void *data) { @@ -221,7 +208,8 @@ void handleLorieEvents(int fd, maybe_unused int ready, maybe_unused void *data) valuator_mask_zero(&mask); if (ready & X_NOTIFY_ERROR) { - RemoveNotifyFd(fd); +// RemoveNotifyFd(fd); + InputThreadUnregisterDev(fd); close(fd); conn_fd = -1; lorieEnableClipboardSync(FALSE); @@ -322,7 +310,8 @@ void lorieSendClipboardData(const char* data) { } static Bool addFd(unused ClientPtr pClient, void *closure) { - SetNotifyFd((int) (int64_t) closure, handleLorieEvents, X_NOTIFY_READ, NULL); +// SetNotifyFd((int) (int64_t) closure, handleLorieEvents, X_NOTIFY_READ, NULL); + InputThreadRegisterDev((int) (int64_t) closure, handleLorieEvents, NULL); conn_fd = (int) (int64_t) closure; return TRUE; } @@ -365,7 +354,7 @@ Java_com_termux_x11_CmdEntryPoint_getLogcatOutput(JNIEnv *env, unused jobject cl } JNIEXPORT jboolean JNICALL -Java_com_termux_x11_CmdEntryPoint_connected(JNIEnv *env, jclass clazz) { +Java_com_termux_x11_CmdEntryPoint_connected(__unused JNIEnv *env, __unused jclass clazz) { return conn_fd != -1; } diff --git a/app/src/main/cpp/lorie/lorie.h b/app/src/main/cpp/lorie/lorie.h index 6450b46e3..9bb764ea8 100644 --- a/app/src/main/cpp/lorie/lorie.h +++ b/app/src/main/cpp/lorie/lorie.h @@ -4,6 +4,7 @@ #include "linux/input-event-codes.h" #define unused __attribute__((unused)) +void lorieSetVM(JavaVM* vm); Bool lorieChangeWindow(ClientPtr pClient, void *closure); void lorieConfigureNotify(int width, int height, int framerate); void lorieEnableClipboardSync(Bool enable); diff --git a/app/src/main/cpp/lorie/renderer.c b/app/src/main/cpp/lorie/renderer.c index d503ce59f..182e3e329 100644 --- a/app/src/main/cpp/lorie/renderer.c +++ b/app/src/main/cpp/lorie/renderer.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include "renderer.h" @@ -129,6 +129,7 @@ static EGLContext ctx = EGL_NO_CONTEXT; static EGLSurface sfc = EGL_NO_SURFACE; static EGLConfig cfg = 0; static EGLNativeWindowType win = 0; +static jobject surface = NULL; static AHardwareBuffer *buffer = NULL; static EGLImageKHR image = NULL; static int renderedFrames = 0; @@ -274,7 +275,7 @@ static void renderer_unset_buffer(void) { buffer = NULL; } -void renderer_set_buffer(AHardwareBuffer* buf) { +void renderer_set_buffer(JNIEnv* env, AHardwareBuffer* buf) { const EGLint imageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; EGLClientBuffer clientBuffer; AHardwareBuffer_Desc desc = {0}; @@ -331,12 +332,20 @@ void renderer_set_buffer(AHardwareBuffer* buf) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data); checkGlError(); } - renderer_redraw(flip); + renderer_redraw(env, flip); log("renderer_set_buffer %p %d %d", buffer, desc.width, desc.height); } -void renderer_set_window(EGLNativeWindowType window, AHardwareBuffer* new_buffer) { +void renderer_set_window(JNIEnv* env, jobject new_surface, AHardwareBuffer* new_buffer) { + EGLNativeWindowType window; + if (new_surface && surface && new_surface != surface && (*env)->IsSameObject(env, new_surface, surface)) { + (*env)->DeleteGlobalRef(env, new_surface); + return; + } + + window = new_surface ? ANativeWindow_fromSurface(env, new_surface) : NULL; + log("renderer_set_window %p %d %d", window, window ? ANativeWindow_getWidth(window) : 0, window ? ANativeWindow_getHeight(window) : 0); if (window && win == window) return; @@ -357,7 +366,20 @@ void renderer_set_window(EGLNativeWindowType window, AHardwareBuffer* new_buffer if (win) ANativeWindow_release(win); + + if (surface) { + jmethodID release = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, surface), "release", "()V"); + jmethodID destroy = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, surface), "destroy", "()V"); + if (release) + (*env)->CallVoidMethod(env, surface, release); + if (destroy) + (*env)->CallVoidMethod(env, surface, destroy); + + (*env)->DeleteGlobalRef(env, surface); + } + win = window; + surface = new_surface; if (!win) return; @@ -411,7 +433,7 @@ void renderer_set_window(EGLNativeWindowType window, AHardwareBuffer* new_buffer if (!new_buffer) { glClearColor(0.f, 0.f, 0.f, 0.0f); checkGlError(); glClear(GL_COLOR_BUFFER_BIT); checkGlError(); - } else renderer_set_buffer(new_buffer); + } else renderer_set_buffer(env, new_buffer); } void renderer_update_root(int w, int h, void* data) { @@ -469,7 +491,7 @@ int renderer_should_redraw(void) { return sfc != EGL_NO_SURFACE && eglGetCurrentContext() != EGL_NO_CONTEXT; } -int renderer_redraw(uint8_t flip) { +int renderer_redraw(JNIEnv* env, uint8_t flip) { int err = EGL_SUCCESS; if (!sfc || eglGetCurrentContext() == EGL_NO_CONTEXT) @@ -484,7 +506,7 @@ int renderer_redraw(uint8_t flip) { log("We've got %s so window is to be destroyed. " "Native window disconnected/abandoned, probably activity is destroyed or in background", eglErrorLabel(err)); - renderer_set_window(NULL, NULL); + renderer_set_window(env, NULL, NULL); return FALSE; } } diff --git a/app/src/main/cpp/lorie/renderer.h b/app/src/main/cpp/lorie/renderer.h index 86367c161..988d71118 100644 --- a/app/src/main/cpp/lorie/renderer.h +++ b/app/src/main/cpp/lorie/renderer.h @@ -1,4 +1,5 @@ #pragma once +#include #include #ifndef maybe_unused @@ -13,10 +14,10 @@ typedef void (*renderer_message_func_type) (int type, int verb, const char *form maybe_unused void renderer_message_func(renderer_message_func_type function); maybe_unused int renderer_init(int* legacy_drawing, uint8_t* flip); -maybe_unused void renderer_set_buffer(AHardwareBuffer* buffer); -maybe_unused void renderer_set_window(struct ANativeWindow* native_window, AHardwareBuffer* buffer); +maybe_unused void renderer_set_buffer(JNIEnv* env, AHardwareBuffer* buffer); +maybe_unused void renderer_set_window(JNIEnv* env, jobject surface, AHardwareBuffer* buffer); maybe_unused int renderer_should_redraw(void); -maybe_unused int renderer_redraw(uint8_t flip); +maybe_unused int renderer_redraw(JNIEnv* env, uint8_t flip); maybe_unused void renderer_print_fps(float millis); maybe_unused void renderer_update_root(int w, int h, void* data); diff --git a/app/src/main/java/com/termux/x11/MainActivity.java b/app/src/main/java/com/termux/x11/MainActivity.java index 037b470b2..8bc5f0903 100644 --- a/app/src/main/java/com/termux/x11/MainActivity.java +++ b/app/src/main/java/com/termux/x11/MainActivity.java @@ -222,7 +222,7 @@ public void swipeDown() { registerReceiver(receiver, new IntentFilter(ACTION_START) {{ addAction(ACTION_PREFERENCES_CHANGED); addAction(ACTION_STOP); - }}); + }}, SDK_INT >= VERSION_CODES.TIRAMISU ? RECEIVER_EXPORTED : 0); // Taken from Stackoverflow answer https://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible/7509285# FullscreenWorkaround.assistActivity(this);