From 3794838b76a008b8f6474b646feba3bac79c64f1 Mon Sep 17 00:00:00 2001 From: Twaik Yont Date: Fri, 3 Feb 2023 16:07:22 +0200 Subject: [PATCH] Cursor is not visible here. Replacing rendering with GL with blitting to Surface. --- .../java/com/termux/x11/LorieService.java | 78 +++- .../java/com/termux/x11/MainActivity.java | 10 +- app/src/main/jni/lorie/Android.mk | 4 +- app/src/main/jni/lorie/android.cpp | 347 ++++++++++++++++++ .../jni/lorie/backend/android/android_app.cpp | 305 --------------- app/src/main/jni/lorie/compositor.cpp | 191 +++++----- .../jni/lorie/include/lorie_compositor.hpp | 116 +++--- .../jni/lorie/include/lorie_egl_helper.hpp | 27 -- .../main/jni/lorie/include/lorie_renderer.hpp | 73 ---- app/src/main/jni/lorie/lorie_egl_helper.cpp | 181 --------- .../main/jni/lorie/lorie_wayland_server.cpp | 3 +- .../main/jni/lorie/lorie_wayland_server.hpp | 8 +- app/src/main/jni/lorie/renderer.cpp | 266 -------------- app/src/main/jni/lorie/utils/log.cpp | 12 +- app/src/main/res/layout/main_activity.xml | 5 + 15 files changed, 608 insertions(+), 1018 deletions(-) create mode 100644 app/src/main/jni/lorie/android.cpp delete mode 100644 app/src/main/jni/lorie/backend/android/android_app.cpp delete mode 100644 app/src/main/jni/lorie/include/lorie_egl_helper.hpp delete mode 100644 app/src/main/jni/lorie/include/lorie_renderer.hpp delete mode 100644 app/src/main/jni/lorie/lorie_egl_helper.cpp delete mode 100644 app/src/main/jni/lorie/renderer.cpp diff --git a/app/src/main/java/com/termux/x11/LorieService.java b/app/src/main/java/com/termux/x11/LorieService.java index 4a35026..05ef931 100644 --- a/app/src/main/java/com/termux/x11/LorieService.java +++ b/app/src/main/java/com/termux/x11/LorieService.java @@ -13,6 +13,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.Rect; import android.net.Uri; @@ -41,7 +42,10 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; +import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; import com.termux.x11.utils.KeyboardUtils; @@ -52,7 +56,7 @@ import java.io.InputStream; @SuppressWarnings({"ConstantConditions", "SameParameterValue", "SdCardPath"}) @SuppressLint({"ClickableViewAccessibility", "StaticFieldLeak"}) -public class LorieService extends Service { +public class LorieService extends Service implements View.OnApplyWindowInsetsListener { static final String LAUNCHED_BY_COMPATION = "com.termux.x11.launched_by_companion"; static final String ACTION_STOP_SERVICE = "com.termux.x11.service_stop"; static final String ACTION_START_FROM_ACTIVITY = "com.termux.x11.start_from_activity"; @@ -205,13 +209,12 @@ public class LorieService extends Service { int mode = Integer.parseInt(preferences.getString("touchMode", "3")); instance.mTP.setMode(mode); - if (preferences.getBoolean("showAdditionalKbd", true)) { - act.getWindow().getDecorView().setOnApplyWindowInsetsListener(act); + act.getWindow().getDecorView().setOnApplyWindowInsetsListener(act); + + if (preferences.getBoolean("showAdditionalKbd", true)) act.kbd.setVisibility(View.VISIBLE); - } else { - act.getWindow().getDecorView().setOnApplyWindowInsetsListener(null); + else act.kbd.setVisibility(View.GONE); - } Log.e("LorieService", "Preferences changed"); } @@ -295,7 +298,7 @@ public class LorieService extends Service { return instance; } - void setListeners(@NonNull SurfaceView view) { + void setListeners(@NonNull SurfaceView view, @NonNull SurfaceView cursor) { Context a = view.getRootView().findViewById(android.R.id.content).getContext(); if (!(a instanceof MainActivity)) { Log.e("LorieService", "Context is not an activity!!!"); @@ -308,7 +311,7 @@ public class LorieService extends Service { view.requestFocus(); listener.svc = this; - listener.setAsListenerTo(view); + listener.setAsListenerTo(view, cursor); mTP = new TouchParser(view, listener); onPreferencesChanged(); @@ -328,13 +331,24 @@ public class LorieService extends Service { LorieService svc; @SuppressLint("WrongConstant") - private void setAsListenerTo(SurfaceView view) { + private void setAsListenerTo(SurfaceView view, SurfaceView cursor) { view.getHolder().addCallback(this); view.setOnTouchListener(this); view.setOnHoverListener(this); view.setOnGenericMotionListener(this); view.setOnKeyListener(this); surfaceChanged(view.getHolder(), PixelFormat.UNKNOWN, view.getWidth(), view.getHeight()); + + cursor.getHolder().addCallback(new SurfaceHolder.Callback() { + @Override public void surfaceCreated(@NonNull SurfaceHolder holder) {} + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + svc.cursorChanged(holder.getSurface()); + } + @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + svc.cursorChanged(null); + } + }); } public void onPointerButton(int button, int state) { @@ -436,8 +450,10 @@ public class LorieService extends Service { @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { DisplayMetrics dm = new DisplayMetrics(); + Rect r = new Rect(); int mmWidth, mmHeight; act.getWindowManager().getDefaultDisplay().getMetrics(dm); + act.getWindow().getDecorView().getWindowVisibleDisplayFrame(r); if (act.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { mmWidth = (int) Math.round((width * 25.4) / dm.xdpi); @@ -447,11 +463,14 @@ public class LorieService extends Service { mmHeight = (int) Math.round((height * 25.4) / dm.xdpi); } - svc.windowChanged(holder.getSurface(), width, height, mmWidth, mmHeight); + svc.windowChanged(holder.getSurface(), r.right, r.bottom, mmWidth, mmHeight); } @Override public void surfaceCreated(SurfaceHolder holder) {} - @Override public void surfaceDestroyed(SurfaceHolder holder) {} + @SuppressLint("WrongConstant") + @Override public void surfaceDestroyed(SurfaceHolder holder) { + surfaceChanged(holder, PixelFormat.UNKNOWN, 0, 0); + } } @@ -490,12 +509,47 @@ public class LorieService extends Service { }; } + @SuppressLint("WrongConstant") + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + SurfaceView c = v.getRootView().findViewById(R.id.lorieView); + SurfaceHolder h = (c != null) ? c.getHolder() : null; + if (h != null) + listener.surfaceChanged(h, PixelFormat.UNKNOWN, 0, 0); + return insets; + } + @SuppressWarnings("unused") // It is used in native code void setRendererVisibility(boolean visible) { - act.runOnUiThread(()-> act.findViewById(visible ? R.id.lorieView : R.id.stub).bringToFront()); + act.runOnUiThread(()-> act.findViewById(R.id.stub).setVisibility(visible?View.GONE:View.VISIBLE)); } + @SuppressWarnings("unused") + // It is used in native code + void setCursorVisibility(boolean visible) { + act.runOnUiThread(()-> act.findViewById(R.id.cursorView).setVisibility(visible?View.VISIBLE:View.GONE)); + } + + @SuppressWarnings("unused") + // It is used in native code + void setCursorRect(int x, int y, int w, int h) { + act.runOnUiThread(()-> { + Log.d("POSITIONER", "pointing cursor: " + x + " " + y + " " + w + " " + h); + SurfaceView v = act.findViewById(R.id.cursorView); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(w*10, h*10); + params.leftMargin = x; + params.topMargin = y; + + v.setLayoutParams(params); + v.setVisibility(View.VISIBLE); + v.setZOrderOnTop(true); + v.bringToFront(); + FrameLayout frm = act.findViewById(R.id.frame); + }); + } + + private native void cursorChanged(Surface surface); private native void windowChanged(Surface surface, int width, int height, int mmWidth, int mmHeight); private native void touchDown(int id, float x, float y); private native void touchMotion(int id, float x, float y); diff --git a/app/src/main/java/com/termux/x11/MainActivity.java b/app/src/main/java/com/termux/x11/MainActivity.java index e6a7f4b..6930ccd 100644 --- a/app/src/main/java/com/termux/x11/MainActivity.java +++ b/app/src/main/java/com/termux/x11/MainActivity.java @@ -11,6 +11,7 @@ import android.preference.PreferenceManager; import android.util.Log; import android.view.KeyEvent; import android.view.PointerIcon; +import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.Window; @@ -131,8 +132,9 @@ public class MainActivity extends AppCompatActivity implements View.OnApplyWindo public void onLorieServiceStart(LorieService instance) { SurfaceView lorieView = findViewById(R.id.lorieView); + SurfaceView cursorView = findViewById(R.id.cursorView); - instance.setListeners(lorieView); + instance.setListeners(lorieView, cursorView); kbd.reload(keys, lorieView, LorieService.getOnKeyListener()); } @@ -187,13 +189,15 @@ public class MainActivity extends AppCompatActivity implements View.OnApplyWindo @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - if (kbd != null) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(LorieService.getInstance()); + if (preferences.getBoolean("showAdditionalKbd", true) && kbd != null) { Rect r = new Rect(); getWindow().getDecorView().getWindowVisibleDisplayFrame(r); boolean isSoftKbdVisible = Objects.requireNonNull(ViewCompat.getRootWindowInsets(kbd)).isVisible(WindowInsetsCompat.Type.ime()); kbd.setVisibility(isSoftKbdVisible ? View.VISIBLE : View.GONE); kbd.setY(r.bottom - kbd.getHeight()); } - return insets; + + return LorieService.getInstance().onApplyWindowInsets(v, insets); } } diff --git a/app/src/main/jni/lorie/Android.mk b/app/src/main/jni/lorie/Android.mk index e89fafe..7243647 100644 --- a/app/src/main/jni/lorie/Android.mk +++ b/app/src/main/jni/lorie/Android.mk @@ -5,12 +5,10 @@ include $(CLEAR_VARS) LOCAL_MODULE := lorie LOCAL_SRC_FILES := \ compositor.cpp \ - lorie_egl_helper.cpp \ lorie_message_queue.cpp \ - renderer.cpp \ utils/log.cpp \ + android.cpp \ \ - backend/android/android_app.cpp \ backend/android/utils.c \ lorie_wayland_server.cpp \ $(wildcard $(WAYLAND_GENERATED)/*.cpp) diff --git a/app/src/main/jni/lorie/android.cpp b/app/src/main/jni/lorie/android.cpp new file mode 100644 index 0000000..3e4ca7b --- /dev/null +++ b/app/src/main/jni/lorie/android.cpp @@ -0,0 +1,347 @@ +#include +#include "lorie_compositor.hpp" +#include +#include +#include +#include +#include +#include "ashmem.h" +#include + +#include +#include +#include +#include + +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#define unused __attribute__((__unused__)) +#define always_inline __attribute__((always_inline)) inline + +JavaVM *vm{}; + +jfieldID lorie_compositor::compositor_field_id{}; + +lorie_compositor::lorie_compositor(jobject thiz): lorie_compositor() { + this->thiz = thiz; + self = std::thread([=, this]{ + vm->AttachCurrentThread(&env, nullptr); + compositor_field_id = env->GetFieldID(env->GetObjectClass(thiz), "compositor", "J"); + set_renderer_visibility_id = env->GetMethodID(env->GetObjectClass(thiz), "setRendererVisibility", "(Z)V"); + set_cursor_visibility_id = env->GetMethodID(env->GetObjectClass(thiz), "setCursorVisibility", "(Z)V"); + set_cursor_rect_id =env->GetMethodID( env->GetObjectClass(thiz), "setCursorRect", "(IIII)V"); + + set_renderer_visibility = [=](bool visible) { + env->CallVoidMethod(thiz, set_renderer_visibility_id, visible); + }; + + set_cursor_visibility = [=](bool visible) { + env->CallVoidMethod(thiz, set_cursor_visibility_id, visible); + if (!visible) + set_cursor_position = [=](int, int) {}; + else + set_cursor_position = [=](int x, int y) { + auto b = cursor.sfc ? any_cast(cursor.sfc->user_data())->buffer : nullptr; + int sx = x - cursor.hotspot_x; + int sy = y - cursor.hotspot_y; + int w = b ? b->shm_width() : 0; + int h = b ? b->shm_width() : 0; + env->CallVoidMethod(thiz, set_cursor_rect_id, sx, sy, w, h); + }; + }; + + run(); + + vm->DetachCurrentThread(); + env = nullptr; + }); +} + +void lorie_compositor::get_keymap(int *fd, int *size) { // NOLINT(readability-convert-member-functions-to-static) + int keymap_fd = open("/data/data/com.termux.x11/files/en_us.xkbmap", O_RDONLY); + struct stat s = {}; + fstat(keymap_fd, &s); + *size = s.st_size; // NOLINT(cppcoreguidelines-narrowing-conversions) + *fd = keymap_fd; +} + +// For some reason both static_cast and reinterpret_cast returning 0 when casting b.bits. +static always_inline uint32_t* cast(void* p) { union { void* a; uint32_t* b; } c {p}; return c.b; } // NOLINT(cppcoreguidelines-pro-type-member-init) + +static always_inline void blit_exact(EGLNativeWindowType win, const uint32_t* src, int width, int height) { + if (width == 0 || height == 0) { + width = ANativeWindow_getWidth(win); + height = ANativeWindow_getHeight(win); + } + ARect bounds{ 0, 0, width, height }; + ANativeWindow_Buffer b{}; + + ANativeWindow_acquire(win); + auto ret = ANativeWindow_setBuffersGeometry(win, width, height, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM); + if (ret != 0) { + LOGE("Failed to set buffers geometry (%d)", ret); + return; + } + + ret = ANativeWindow_lock(win, &b, &bounds); + if (ret != 0) { + LOGE("Failed to lock"); + return; + } + + uint32_t* dst = cast(b.bits); + if (src) { + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + //uint32_t* d = &dst[b.stride*i + j]; + uint32_t s = src[width * i + j]; + // Cast BGRA to RGBA + dst[b.stride * i + j] = ((s & 0x0000FF) << 16) | (s & 0x00FF00) | ((s & 0xFF0000) >> 16); + } + } + } else + memset(dst, 0, b.stride*b.height); + + ret = ANativeWindow_unlockAndPost(win); + if (ret != 0) { + LOGE("Failed to post"); + return; + } + + ANativeWindow_release(win); +} + +void lorie_compositor::blit(EGLNativeWindowType win, wayland::surface_t* sfc) { + if (!win) + return; + + auto buffer = sfc ? any_cast(sfc->user_data())->buffer : nullptr; + if (buffer) + blit_exact(win, cast(buffer->shm_data()), buffer->shm_width(), buffer->shm_height()); + else + blit_exact(win, nullptr, 0, 0); +} + +template struct wrapper_impl; +template +struct wrapper_impl { + // Be careful and do passing jobjects here!!! + [[maybe_unused]] static always_inline R execute(JNIEnv* env, jobject obj, A... args) { + auto native = lorie_compositor::compositor_field_id ? reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)) : nullptr; + if (native != nullptr) + return (native->*f)(args...); + return static_cast(defaultValue); + } + + [[maybe_unused]] static always_inline void queue(JNIEnv* env, jobject obj, A... args) { + auto native = lorie_compositor::compositor_field_id ? reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)) : nullptr; + if (native != nullptr) + native->post([=]{ (native->*f)(args...); }); + } +}; +template +auto execute = wrapper_impl::execute; +template +auto queue = wrapper_impl::queue; + +[[maybe_unused]] static always_inline lorie_compositor* get(JNIEnv* env, jobject obj) { + return lorie_compositor::compositor_field_id ? + reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)) : + nullptr; +} + +/////////////////////////////////////////////////////////// + +#define JNI_DECLARE_INNER(package, classname, methodname ) \ + Java_ ## package ## _ ## classname ## _ ## methodname +#define JNI_DECLARE(classname, methodname) \ + JNI_DECLARE_INNER(com_termux_x11, classname, methodname) + +extern "C" JNIEXPORT jlong JNICALL +JNI_DECLARE(LorieService, createLorieThread)(JNIEnv *env, jobject thiz) { +#if 0 + // It is needed to redirect stderr to logcat + setenv("WAYLAND_DEBUG", "1", 1); + new std::thread([]{ + FILE *fp; + int p[2]; + size_t read, len; + char* line = nullptr; + pipe(p); + fp = fdopen(p[0], "r"); + + dup2(p[1], 2); + while ((read = getline(&line, &len, fp)) != -1) { + __android_log_write(ANDROID_LOG_VERBOSE, "WAYLAND_STDERR", line); + } + }); +#endif + return (jlong) new lorie_compositor(env->NewGlobalRef(thiz)); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, passWaylandFD)(JNIEnv *env, jobject thiz, jint fd) { + LOGI("JNI: got fd %d", fd); + execute<&lorie_compositor::add_socket_fd>(env, thiz, fd); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, terminate)(JNIEnv *env, jobject obj) { + auto b = reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)); + b->terminate(); + b->self.join(); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, cursorChanged)(JNIEnv *env, jobject thiz, jobject surface) { + EGLNativeWindowType win = surface?ANativeWindow_fromSurface(env, surface):nullptr; + auto c = get(env, thiz); + c->post([=]{ c->cursor.win = win; }); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, windowChanged)(JNIEnv *env, jobject thiz, jobject surface, jint width, jint height, jint mm_width, jint mm_height) { + EGLNativeWindowType win = surface?ANativeWindow_fromSurface(env, surface):nullptr; + queue<&lorie_compositor::output_resize>(env, thiz, win, width, height, mm_width, mm_height); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, touchDown)(JNIEnv *env, jobject thiz, jint id, jfloat x, jfloat y) { + queue<&lorie_compositor::touch_down>(env, thiz, static_cast(id), static_cast(x), static_cast(y)); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, touchMotion)(JNIEnv *env, jobject thiz, jint id, jfloat x, jfloat y) { + queue<&lorie_compositor::touch_motion>(env, thiz, static_cast(id), static_cast(x), static_cast(y)); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, touchUp)(JNIEnv *env, jobject thiz, jint id) { + queue<&lorie_compositor::touch_up>(env, thiz, id); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, touchFrame)(JNIEnv *env, jobject thiz) { + queue<&lorie_compositor::touch_frame>(env, thiz); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, pointerMotion)(JNIEnv *env, jobject thiz, jint x, jint y) { + queue<&lorie_compositor::pointer_motion>(env, thiz, x, y); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, pointerScroll)(JNIEnv *env, jobject thiz, jint axis, jfloat value) { + queue<&lorie_compositor::pointer_scroll>(env, thiz, axis, value); +} + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, pointerButton)(JNIEnv *env, jobject thiz, jint button, jint type) { + queue<&lorie_compositor::pointer_button>(env, thiz, uint32_t(button), uint32_t(type)); +} + +extern "C" void get_character_data(char** layout, int *shift, int *ec, char *ch); +extern "C" void android_keycode_get_eventcode(int kc, int *ec, int *shift); + +extern "C" JNIEXPORT void JNICALL +JNI_DECLARE(LorieService, keyboardKey)(JNIEnv *env, jobject thiz, + jint type, jint key_code, jint jshift, jstring characters_) { + char *characters = nullptr; + + int event_code = 0; + int shift = jshift; + if (characters_ != nullptr) characters = (char*) env->GetStringUTFChars(characters_, nullptr); + if (key_code && !characters) { + android_keycode_get_eventcode(key_code, &event_code, &shift); + LOGE("kc: %d ec: %d", key_code, event_code); + } + if (!key_code && characters) { + char *layout = nullptr; + get_character_data(&layout, &shift, &event_code, characters); + } + LOGE("Keyboard input: keyCode: %d; eventCode: %d; characters: %s; shift: %d, type: %d", key_code, event_code, characters, shift, type); + + if (shift || jshift) + queue<&lorie_compositor::keyboard_key>(env, thiz, 42, wayland::keyboard_key_state::pressed); + + // For some reason Android do not send ACTION_DOWN for non-English characters + if (characters) + queue<&lorie_compositor::keyboard_key>(env, thiz, event_code, wayland::keyboard_key_state::pressed); + + queue<&lorie_compositor::keyboard_key>(env, thiz, event_code, wayland::keyboard_key_state(type)); + + if (shift || jshift) + queue<&lorie_compositor::keyboard_key>(env, thiz, 42, wayland::keyboard_key_state::released); + + if (characters_ != nullptr) env->ReleaseStringUTFChars(characters_, characters); +} + +static bool sameUid(int pid) { + char path[32] = {0}; + struct stat s = {0}; + sprintf(path, "/proc/%d", pid); + stat(path, &s); + return s.st_uid == getuid(); +} + +static void killAllLogcats() { + DIR* proc; + struct dirent* dir_elem; + char path[64] = {0}, link[64] = {0}; + pid_t pid, self = getpid(); + if ((proc = opendir("/proc")) == nullptr) { + LOGE("opendir: %s", strerror(errno)); + return; + } + + while((dir_elem = readdir(proc)) != nullptr) { + if (!(pid = (pid_t) atoi (dir_elem->d_name)) || pid == self || !sameUid(pid)) // NOLINT(cert-err34-c) + continue; + + memset(path, 0, sizeof(path)); + memset(link, 0, sizeof(link)); + sprintf(path, "/proc/%d/exe", pid); + if (readlink(path, link, sizeof(link)) < 0) { + LOGE("readlink %s: %s", path, strerror(errno)); + continue; + } + if (strstr(link, "/logcat") != nullptr) { + if (kill(pid, SIGKILL) < 0) { + LOGE("kill %d (%s): %s", pid, link, strerror); + } + } + } +} + +void fork(const std::function& f) { + switch(fork()) { + case -1: LOGE("fork: %s", strerror(errno)); return; + case 0: f(); return; + default: return; + } +} + +extern "C" JNIEXPORT void JNICALL +Java_com_termux_x11_LorieService_startLogcatForFd(unused JNIEnv *env, unused jclass clazz, jint fd) { + killAllLogcats(); + + LOGI("Starting logcat with output to given fd"); + fork([]() { + execl("/system/bin/logcat", "logcat", "-c", nullptr); + LOGE("exec logcat: %s", strerror(errno)); + }); + + fork([fd]() { + dup2(fd, 1); + dup2(fd, 2); + execl("/system/bin/logcat", "logcat", nullptr); + LOGE("exec logcat: %s", strerror(errno)); + }); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" +extern "C" jint JNI_OnLoad(JavaVM* vm, [[maybe_unused]] void* reserved) { + ::vm = vm; + return JNI_VERSION_1_6; +} +#pragma clang diagnostic pop \ No newline at end of file diff --git a/app/src/main/jni/lorie/backend/android/android_app.cpp b/app/src/main/jni/lorie/backend/android/android_app.cpp deleted file mode 100644 index 2275d4b..0000000 --- a/app/src/main/jni/lorie/backend/android/android_app.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#pragma ide diagnostic ignored "hicpp-signed-bitwise" -#define unused __attribute__((__unused__)) - -class lorie_backend_android : public lorie_compositor { -public: - lorie_backend_android(JavaVM *env, jobject obj, jmethodID pId); - - void backend_init() override; - - void swap_buffers() override; - - void get_keymap(int *fd, int *size) override; - - void window_change_callback(EGLNativeWindowType win, uint32_t width, uint32_t height, - uint32_t physical_width, uint32_t physical_height); - - void passfd(int fd); - - void on_egl_init(); - - LorieEGLHelper helper; - - int keymap_fd = -1; - std::thread self; - - JavaVM *vm{}; - JNIEnv *env{}; - jobject thiz{}; - static jfieldID compositor_field_id; - jmethodID set_renderer_visibility_id{}; -}; - -jfieldID lorie_backend_android::compositor_field_id{}; - -lorie_backend_android::lorie_backend_android(JavaVM *vm, jobject obj, jmethodID mid) - : vm(vm), thiz(obj), set_renderer_visibility_id(mid), self(&lorie_compositor::start, this) {} - -void lorie_backend_android::on_egl_init() { - renderer.on_surface_create(); -} - -void lorie_backend_android::backend_init() { - if (!helper.init(EGL_DEFAULT_DISPLAY)) { - LOGE("Failed to initialize EGL context"); - } - - helper.onInit = [this](){ on_egl_init(); }; - - renderer.set_renderer_visibility = [=](bool visible) { - vm->AttachCurrentThread(&env, nullptr); - env->CallVoidMethod(thiz, set_renderer_visibility_id, visible); - vm->DetachCurrentThread(); - }; -} - -void lorie_backend_android::swap_buffers () { - helper.swap(); -} - -void lorie_backend_android::get_keymap(int *fd, int *size) { - if (keymap_fd != -1) - close(keymap_fd); - - keymap_fd = open("/data/data/com.termux.x11/files/en_us.xkbmap", O_RDONLY); - struct stat s = {}; - fstat(keymap_fd, &s); - *size = s.st_size; - *fd = keymap_fd; -} - -void lorie_backend_android::window_change_callback(EGLNativeWindowType win, uint32_t width, uint32_t height, uint32_t physical_width, uint32_t physical_height) { - LOGV("JNI: window is changed: %p %dx%d (%dmm x %dmm)", win, width, height, physical_width, physical_height); - helper.setWindow(win); - post([=, this]() { - output_resize(width, height, physical_width, physical_height); - }); -} - -void lorie_backend_android::passfd(int fd) { - LOGI("JNI: got fd %d", fd); - dpy.add_socket_fd(fd); -} - -template struct wrapper_impl; -template -struct wrapper_impl { - // Be careful and do passing jobjects here!!! - static inline R execute(JNIEnv* env, jobject obj, A... args) { - auto native = reinterpret_cast(env->GetLongField(obj, lorie_backend_android::compositor_field_id)); - if (native != nullptr) - return (native->*f)(args...); - return static_cast(defaultValue); - } - static inline void queue(JNIEnv* env, jobject obj, A... args) { - auto native = reinterpret_cast(env->GetLongField(obj, lorie_backend_android::compositor_field_id)); - if (native != nullptr) - native->post([=]{ (native->*f)(args...); }); - } -}; -template -auto execute = wrapper_impl::execute; -template -auto queue = wrapper_impl::queue; - -/////////////////////////////////////////////////////////// - -#define JNI_DECLARE_INNER(package, classname, methodname ) \ - Java_ ## package ## _ ## classname ## _ ## methodname -#define JNI_DECLARE(classname, methodname) \ - JNI_DECLARE_INNER(com_termux_x11, classname, methodname) - -extern "C" JNIEXPORT jlong JNICALL -JNI_DECLARE(LorieService, createLorieThread)(JNIEnv *env, jobject thiz) { -#if 0 - // It is needed to redirect stderr to logcat - setenv("WAYLAND_DEBUG", "1", 1); - new std::thread([]{ - FILE *fp; - int p[2]; - size_t read, len; - char* line = nullptr; - pipe(p); - fp = fdopen(p[0], "r"); - - dup2(p[1], 2); - while ((read = getline(&line, &len, fp)) != -1) { - __android_log_write(ANDROID_LOG_VERBOSE, "WAYLAND_STDERR", line); - } - }); -#endif - JavaVM* vm{}; - env->GetJavaVM(&vm); - lorie_backend_android::compositor_field_id = env->GetFieldID(env->GetObjectClass(thiz), "compositor", "J"); - jmethodID set_renderer_visibility_id = env->GetMethodID(env->GetObjectClass(thiz), "setRendererVisibility", "(Z)V"); - return (jlong) new lorie_backend_android(vm, env->NewGlobalRef(thiz), - set_renderer_visibility_id); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, passWaylandFD)(JNIEnv *env, jobject thiz, jint fd) { - execute<&lorie_backend_android::passfd>(env, thiz, fd); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, terminate)(JNIEnv *env, jobject obj) { - auto b = reinterpret_cast(env->GetLongField(obj, lorie_backend_android::compositor_field_id)); - b->terminate(); - b->self.join(); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, windowChanged)(JNIEnv *env, jobject thiz, jobject jsurface, jint width, jint height, jint mm_width, jint mm_height) { - EGLNativeWindowType win = ANativeWindow_fromSurface(env, jsurface); - queue<&lorie_backend_android::window_change_callback>(env, thiz, win, width, height, mm_width, mm_height); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, touchDown)(JNIEnv *env, jobject thiz, jint id, jfloat x, jfloat y) { - queue<&lorie_backend_android::touch_down>(env, thiz, static_cast(id), static_cast(x), static_cast(y)); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, touchMotion)(JNIEnv *env, jobject thiz, jint id, jfloat x, jfloat y) { - queue<&lorie_backend_android::touch_motion>(env, thiz, static_cast(id), static_cast(x), static_cast(y)); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, touchUp)(JNIEnv *env, jobject thiz, jint id) { - queue<&lorie_backend_android::touch_up>(env, thiz, id); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, touchFrame)(JNIEnv *env, jobject thiz) { - queue<&lorie_backend_android::touch_frame>(env, thiz); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, pointerMotion)(JNIEnv *env, jobject thiz, jint x, jint y) { - queue<&lorie_backend_android::pointer_motion>(env, thiz, static_cast(x), static_cast(y)); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, pointerScroll)(JNIEnv *env, jobject thiz, jint axis, jfloat value) { - queue<&lorie_backend_android::pointer_scroll>(env, thiz, static_cast(axis), value); -} - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, pointerButton)(JNIEnv *env, jobject thiz, jint button, jint type) { - queue<&lorie_backend_android::pointer_button>(env, thiz, static_cast(button), static_cast(type)); -} - -extern "C" void get_character_data(char** layout, int *shift, int *ec, char *ch); -extern "C" void android_keycode_get_eventcode(int kc, int *ec, int *shift); - -extern "C" JNIEXPORT void JNICALL -JNI_DECLARE(LorieService, keyboardKey)(JNIEnv *env, jobject thiz, - jint type, jint key_code, jint jshift, jstring characters_) { - char *characters = nullptr; - - int event_code = 0; - int shift = jshift; - if (characters_ != nullptr) characters = (char*) env->GetStringUTFChars(characters_, nullptr); - if (key_code && !characters) { - android_keycode_get_eventcode(key_code, &event_code, &shift); - LOGE("kc: %d ec: %d", key_code, event_code); - } - if (!key_code && characters) { - char *layout = nullptr; - get_character_data(&layout, &shift, &event_code, characters); - } - LOGE("Keyboard input: keyCode: %d; eventCode: %d; characters: %s; shift: %d, type: %d", key_code, event_code, characters, shift, type); - - if (shift || jshift) - queue<&lorie_backend_android::keyboard_key>(env, thiz, 42, wayland::keyboard_key_state::pressed); - - // For some reason Android do not send ACTION_DOWN for non-English characters - if (characters) - queue<&lorie_backend_android::keyboard_key>(env, thiz, event_code, wayland::keyboard_key_state::pressed); - - queue<&lorie_backend_android::keyboard_key>(env, thiz, event_code, wayland::keyboard_key_state(type)); - - if (shift || jshift) - queue<&lorie_backend_android::keyboard_key>(env, thiz, 42, wayland::keyboard_key_state::released); - - if (characters_ != nullptr) env->ReleaseStringUTFChars(characters_, characters); -} - -static bool sameUid(int pid) { - char path[32] = {0}; - struct stat s = {0}; - sprintf(path, "/proc/%d", pid); - stat(path, &s); - return s.st_uid == getuid(); -} - -static void killAllLogcats() { - DIR* proc; - struct dirent* dir_elem; - char path[64] = {0}, link[64] = {0}; - pid_t pid, self = getpid(); - if ((proc = opendir("/proc")) == nullptr) { - LOGE("opendir: %s", strerror(errno)); - return; - } - - while((dir_elem = readdir(proc)) != nullptr) { - if (!(pid = (pid_t) atoi (dir_elem->d_name)) || pid == self || !sameUid(pid)) // NOLINT(cert-err34-c) - continue; - - memset(path, 0, sizeof(path)); - memset(link, 0, sizeof(link)); - sprintf(path, "/proc/%d/exe", pid); - if (readlink(path, link, sizeof(link)) < 0) { - LOGE("readlink %s: %s", path, strerror(errno)); - continue; - } - if (strstr(link, "/logcat") != nullptr) { - if (kill(pid, SIGKILL) < 0) { - LOGE("kill %d (%s): %s", pid, link, strerror); - } - } - } -} - -void fork(const std::function& f) { - switch(fork()) { - case -1: LOGE("fork: %s", strerror(errno)); return; - case 0: f(); return; - default: return; - } -} - -extern "C" JNIEXPORT void JNICALL -Java_com_termux_x11_LorieService_startLogcatForFd(unused JNIEnv *env, unused jclass clazz, jint fd) { - killAllLogcats(); - - LOGI("Starting logcat with output to given fd"); - fork([]() { - execl("/system/bin/logcat", "logcat", "-c", nullptr); - LOGE("exec logcat: %s", strerror(errno)); - }); - - fork([fd]() { - dup2(fd, 1); - dup2(fd, 2); - execl("/system/bin/logcat", "logcat", nullptr); - LOGE("exec logcat: %s", strerror(errno)); - }); -} diff --git a/app/src/main/jni/lorie/compositor.cpp b/app/src/main/jni/lorie/compositor.cpp index c488804..8fbe7af 100644 --- a/app/src/main/jni/lorie/compositor.cpp +++ b/app/src/main/jni/lorie/compositor.cpp @@ -7,18 +7,27 @@ using namespace wayland; -lorie_compositor::lorie_compositor() : -display(dpy), -renderer(*this) { - dpy.on_client = [=](client_t* client) { +lorie_compositor::lorie_compositor() { + on_client = [=](client_t* client) { client->user_data() = new client_data; client->on_destroy = [=] { - if (toplevel && toplevel->client() == client) - renderer.set_toplevel(nullptr); + bool request_redraw{}; - if (cursor && cursor->client() == client) - renderer.set_cursor(nullptr, 0, 0); + if (screen.sfc && screen.sfc->client() == client) { + screen.sfc = nullptr; + request_redraw = true; + } + if (cursor.sfc && cursor.sfc->client() == client) { + screen.sfc = nullptr; + request_redraw = true; + } + + if (request_redraw) + redraw(true); + + if(!screen.sfc) + set_renderer_visibility(false); LOGI("Client destroyed"); }; }; @@ -32,8 +41,6 @@ renderer(*this) { auto data = new surface_data; surface->user_data() = data; surface->on_attach = [=](buffer_t* b, int32_t, int32_t) { - if (data->buffer) - data->buffer->release(); data->buffer = b; }; surface->on_damage = [=](int32_t, int32_t, int32_t, int32_t) { @@ -43,7 +50,8 @@ renderer(*this) { data->frame_callback = cb; }; surface->on_commit = [=] { - renderer.request_redraw(); + redraw(); + data->buffer->release(); data->frame_callback->done(resource_t::timestamp()); }; surface->on__destroy = [=] { @@ -57,14 +65,17 @@ renderer(*this) { auto data = any_cast(client->user_data()); - seat->on_get_pointer = [=](pointer_t* pointer) { + seat->on_get_pointer = [=, this](pointer_t* pointer) { LOGV("Client requested seat pointer"); data->pointer = pointer; - if (toplevel) - pointer->enter(next_serial(), toplevel, 0, 0); + if (screen.sfc) + pointer->enter(next_serial(), screen.sfc, 0, 0); pointer->on_set_cursor = [=](uint32_t, wayland::surface_t* sfc, int32_t x, int32_t y) { - renderer.set_cursor(sfc, (uint32_t) x, (uint32_t) y); + cursor.sfc = sfc; + cursor.hotspot_x = x; + cursor.hotspot_y = y; + if (sfc) any_cast(sfc->user_data())->damaged = true; }; @@ -89,8 +100,8 @@ renderer(*this) { wl_array keys{}; wl_array_init(&keys); - if (toplevel) - kbd->enter(next_serial(), toplevel, &keys); + if (screen.sfc) + kbd->enter(next_serial(), screen.sfc, &keys); kbd->on_release = [=] { kbd->destroy(); @@ -119,178 +130,178 @@ renderer(*this) { shell->on_set_toplevel = [=] () { wl_array keys{}; wl_array_init(&keys); - renderer.set_toplevel(sfc); + screen.sfc = sfc; + redraw(); + set_renderer_visibility(sfc != nullptr); + if (data->pointer) data->pointer->enter(next_serial(),sfc, 0, 0); if(data->kbd) data->kbd->enter(next_serial(), sfc, &keys); - shell->configure(shell_surface_resize::none, renderer.width, renderer.height); + auto buffer = sfc ? any_cast(sfc->user_data())->buffer : nullptr; + if (buffer) + shell->configure(shell_surface_resize::none, buffer->shm_width(), buffer->shm_height()); }; }; }; global_xdg_wm_base.on_bind = [=, this](client_t* client, xdg_wm_base_t* wm_base) { wm_base->on_get_xdg_surface = [=, this](xdg_surface_t* xdg_surface, surface_t* sfc) { xdg_surface->on_get_toplevel = [=, this](xdg_toplevel_t*) { - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); wl_array keys{}; wl_array_init(&keys); - renderer.set_toplevel(sfc); + screen.sfc = sfc; if (data->pointer) data->pointer->enter(next_serial(),sfc, 0, 0); if (data->kbd) data->kbd->enter(next_serial(), sfc, &keys); + redraw(); }; }; wm_base->on__destroy = [=]() { wm_base->destroy(); }; }; + + LogInit(); + LOGV("Starting compositor"); + wl_display_init_shm (*this); + add_fd_listener(queue.get_fd(), WL_EVENT_READABLE, [&](int, uint){ queue.run(); return 0; }); } -int proc(int fd, uint32_t mask, void *data) { - lorie_compositor *b = static_cast(data); - if (b == nullptr) {LOGF("b == nullptr"); return 0;} +void lorie_compositor::redraw(bool force) { + if (screen.win) { + auto data = screen.sfc ? any_cast(screen.sfc->user_data()) : nullptr; + bool damaged = (data && data->damaged) || force; + if (damaged) + blit(screen.win, screen.sfc); + } - b->queue.run(); - return 0; -}; - -void lorie_compositor::start() { - LogInit(); - LOGV("Starting compositor"); - wl_display_add_socket_auto(display); - - wl_event_loop_add_fd(wl_display_get_event_loop(display), queue.get_fd(), WL_EVENT_READABLE, &proc, this); - - wl_display_init_shm (display); - - backend_init(); - - wl_display_run(display); + if (cursor.win) { + auto data = cursor.sfc ? any_cast(cursor.sfc->user_data()) : nullptr; + bool damaged = (data && data->damaged) || force; + if (damaged) + blit(cursor.win, cursor.sfc); + } } void lorie_compositor::post(std::function f) { - queue.write(f); + queue.write(std::move(f)); } -void lorie_compositor::terminate() { - LOGI("JNI: requested termination"); - if (display != nullptr) - wl_display_terminate(display); -} - -void lorie_compositor::output_resize(int width, int height, uint32_t physical_width, uint32_t physical_height) { +void lorie_compositor::output_resize(EGLNativeWindowType win, int real_width, int real_height, int physical_width, int physical_height) { // Xwayland segfaults without that line - if (width == 0 || height == 0 || physical_width == 0 || physical_height == 0) return; - renderer.resize(width, height, physical_width, physical_height); - post([this]() { - renderer.request_redraw(); - }); + LOGV("JNI: window is changed: %p %dx%d (%dmm x %dmm)", win, real_width, real_height, physical_width, physical_height); + if (real_width == 0 || real_height == 0 || physical_width == 0 || physical_height == 0) return; + screen.real_width = real_width; + screen.real_height = real_height; + screen.physical_width = physical_width; + screen.physical_height = physical_height; + screen.win = win; + + if (screen.sfc) { + auto data = any_cast(screen.sfc->client()->user_data()); + report_mode(data->output); + } } void lorie_compositor::report_mode(wayland::output_t* output) const { - output->geometry(0, 0, renderer.physical_width, renderer.physical_height, output_subpixel::unknown, "Lorie", "none", output_transform::normal); + output->geometry(0, 0, screen.physical_width, screen.physical_height, output_subpixel::unknown, "Lorie", "none", output_transform::normal); output->scale(1.0); - output->mode(output_mode::current | output_mode::preferred, renderer.width, renderer.height, 60000); + output->mode(output_mode::current | output_mode::preferred, screen.real_width, screen.real_height, 60000); output->done(); } void lorie_compositor::touch_down(uint32_t id, uint32_t x, uint32_t y) { LOGV("JNI: touch down"); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); - data->touch->down(next_serial(), resource_t::timestamp(), toplevel, id, x, y); - renderer.set_cursor_visibility(false); + data->touch->down(next_serial(), resource_t::timestamp(), screen.sfc, id, x, y); + set_cursor_visibility(false); } void lorie_compositor::touch_motion(uint32_t id, uint32_t x, uint32_t y) { LOGV("JNI: touch motion"); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); data->touch->motion(resource_t::timestamp(), id, x, y); - renderer.set_cursor_visibility(false); + set_cursor_visibility(false); } void lorie_compositor::touch_up(uint32_t id) { LOGV("JNI: touch up"); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); data->touch->up(next_serial(), resource_t::timestamp(), id); - renderer.set_cursor_visibility(false); + set_cursor_visibility(false); } void lorie_compositor::touch_frame() { LOGV("JNI: touch frame"); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); data->touch->frame(); - renderer.set_cursor_visibility(false); + set_cursor_visibility(false); } -void lorie_compositor::pointer_motion(uint32_t x, uint32_t y) { +void lorie_compositor::pointer_motion(int x, int y) { LOGV("JNI: pointer motion %dx%d", x, y); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); - data->pointer->motion(resource_t::timestamp(), x, y); + data->pointer->motion(resource_t::timestamp(), double(x), double(y)); data->pointer->frame(); - renderer.set_cursor_visibility(true); - renderer.cursor_move(x, y); + set_cursor_visibility(true); + set_cursor_position(x, y); } -void lorie_compositor::pointer_scroll(uint32_t axis, float value) { +void lorie_compositor::pointer_scroll(int axis, float value) { LOGV("JNI: pointer scroll %d %f", axis, value); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); data->pointer->axis_discrete(pointer_axis(axis), (value >= 0) ? 1 : -1); data->pointer->axis(resource_t::timestamp(), pointer_axis(axis), value); data->pointer->frame(); - renderer.set_cursor_visibility(true); + set_cursor_visibility(true); } -void lorie_compositor::pointer_button(uint32_t button, uint32_t state) { +void lorie_compositor::pointer_button(int button, int state) { LOGV("JNI: pointer button %d type %d", button, state); - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); LOGI("pointer button: %d %d", button, state); data->pointer->button(next_serial(), resource_t::timestamp(), button, pointer_button_state(state)); data->pointer->frame(); - renderer.set_cursor_visibility(true); + set_cursor_visibility(true); } void lorie_compositor::keyboard_key(uint32_t key, keyboard_key_state state) { - if (!toplevel) + if (!screen.sfc) return; - auto data = any_cast(toplevel->client()->user_data()); + auto data = any_cast(screen.sfc->client()->user_data()); data->kbd->key (next_serial(), resource_t::timestamp(), key, keyboard_key_state(state)); } -uint32_t lorie_compositor::next_serial() const { - if (display == nullptr) return 0; - - return wl_display_next_serial(display); -} - #pragma clang diagnostic pop diff --git a/app/src/main/jni/lorie/include/lorie_compositor.hpp b/app/src/main/jni/lorie/include/lorie_compositor.hpp index a778f22..e6240bf 100644 --- a/app/src/main/jni/lorie/include/lorie_compositor.hpp +++ b/app/src/main/jni/lorie/include/lorie_compositor.hpp @@ -2,65 +2,91 @@ #include #include #include -#include #include #include "log.h" -class lorie_compositor { +#ifdef ANDROID +#include +#include +#include + +typedef ANativeWindow* EGLNativeWindowType; +#else +typedef void* EGLNativeWindowType; +#endif + +class lorie_compositor: public wayland::display_t { public: - lorie_compositor(); + lorie_compositor(); // compositor features - void start(); - void post(std::function f); + void start(); + void post(std::function f); + void redraw(bool force = false); - void terminate(); - void output_resize(int width, int height, uint32_t physical_width, uint32_t physical_height); - void report_mode(wayland::output_t* output) const; + void output_resize(EGLNativeWindowType win, int real_width, int real_height, int physical_width, int physical_height); + void report_mode(wayland::output_t* output) const; - void touch_down(uint32_t id, uint32_t x, uint32_t y); - void touch_motion(uint32_t id, uint32_t x, uint32_t y); - void touch_up(uint32_t id); - void touch_frame(); - void pointer_motion(uint32_t x, uint32_t y); // absolute values - void pointer_scroll(uint32_t axis, float value); - void pointer_button(uint32_t button, uint32_t state); - void keyboard_key(uint32_t key, wayland::keyboard_key_state state); + void touch_down(uint32_t id, uint32_t x, uint32_t y); + void touch_motion(uint32_t id, uint32_t x, uint32_t y); + void touch_up(uint32_t id); + void touch_frame(); + void pointer_motion(int x, int y); // absolute values + void pointer_scroll(int axis, float value); + void pointer_button(int button, int state); + void keyboard_key(uint32_t key, wayland::keyboard_key_state state); - struct client_data { - wayland::output_t* output{}; - wayland::pointer_t* pointer{}; - wayland::keyboard_t* kbd{}; - wayland::touch_t* touch{}; - }; + struct client_data { + wayland::output_t* output{}; + wayland::pointer_t* pointer{}; + wayland::keyboard_t* kbd{}; + wayland::touch_t* touch{}; + }; - struct surface_data { - uint32_t x{}, y{}; - bool damaged{}; - wayland::buffer_t *buffer{}; - wayland::callback_t *frame_callback{}; - }; + struct surface_data { + uint32_t x{}, y{}; + bool damaged{}; + wayland::buffer_t *buffer{}; + wayland::callback_t *frame_callback{}; + }; - lorie_renderer renderer; - - wayland::surface_t* toplevel{}; - wayland::surface_t* cursor{}; + struct { + int real_width, real_height; + int physical_width, physical_height; + wayland::surface_t* sfc; + EGLNativeWindowType win; + } screen{}; + struct { + int width, height; + int hotspot_x, hotspot_y; + int x, y; + wayland::surface_t* sfc; + EGLNativeWindowType win; + } cursor{}; + static void blit(EGLNativeWindowType win, wayland::surface_t* sfc); + std::function set_renderer_visibility = [](bool){}; + std::function set_cursor_visibility = [](bool){}; + std::function set_cursor_position = [](int, int){}; // backend features - virtual void backend_init() = 0; - virtual void swap_buffers() = 0; - virtual void get_keymap(int *fd, int *size) = 0; - virtual ~lorie_compositor() {}; + void get_keymap(int *fd, int *size); //private: - wayland::display_t dpy; - wayland::global_compositor_t global_compositor{dpy}; - wayland::global_seat_t global_seat{dpy}; - wayland::global_output_t global_output{dpy}; - wayland::global_shell_t global_shell{dpy}; - wayland::global_xdg_wm_base_t global_xdg_wm_base{dpy}; - struct wl_display *display = nullptr; + wayland::global_compositor_t global_compositor{this}; + wayland::global_seat_t global_seat{this}; + wayland::global_output_t global_output{this}; + wayland::global_shell_t global_shell{this}; + wayland::global_xdg_wm_base_t global_xdg_wm_base{this}; lorie_message_queue queue; -private: - uint32_t next_serial() const; + +#ifdef ANDROID + JNIEnv *env{}; + jobject thiz{}; + static jfieldID compositor_field_id; + jmethodID set_renderer_visibility_id{}; + jmethodID set_cursor_visibility_id{}; + jmethodID set_cursor_rect_id{}; + lorie_compositor(jobject thiz); + std::thread self; +#endif }; diff --git a/app/src/main/jni/lorie/include/lorie_egl_helper.hpp b/app/src/main/jni/lorie/include/lorie_egl_helper.hpp deleted file mode 100644 index d2e7bca..0000000 --- a/app/src/main/jni/lorie/include/lorie_egl_helper.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include - -#if defined(__ANDROID__) -#define EGL_NO_WINDOW nullptr -#else -#define EGL_NO_WINDOW 0 -#endif - -class LorieEGLHelper { -public: - EGLDisplay dpy = EGL_NO_DISPLAY; - EGLConfig cfg; - - EGLSurface sfc = EGL_NO_SURFACE; - EGLContext ctx = EGL_NO_CONTEXT; - EGLNativeWindowType win = EGL_NO_WINDOW; - - std::function onInit = nullptr; - std::function onUninit = nullptr; - - bool init(EGLNativeDisplayType display); - bool setWindow(EGLNativeWindowType window); - void swap(); - void uninit(); -}; diff --git a/app/src/main/jni/lorie/include/lorie_renderer.hpp b/app/src/main/jni/lorie/include/lorie_renderer.hpp deleted file mode 100644 index 65716c5..0000000 --- a/app/src/main/jni/lorie/include/lorie_renderer.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once -#include -#include - -class lorie_renderer; -class lorie_texture { -private: - lorie_renderer* r = nullptr; - bool damaged = false; -public: - lorie_texture(); - int width{}, height{}; - void *data{}; - void set_data(lorie_renderer* renderer, uint32_t width, uint32_t height, void *data); - void damage(int32_t x, int32_t y, int32_t width, int32_t height); - void uninit(); - void reinit(); - bool valid(); -private: - GLuint id = UINT_MAX; - void draw(float x0, float y0, float x1, float y1); - - friend class lorie_renderer; -}; - -class lorie_compositor; -class lorie_renderer { -public: - lorie_renderer(lorie_compositor& compositor); - void request_redraw(); - void on_surface_create(); - - uint32_t width = 1024; - uint32_t height = 600; - uint32_t physical_width = 270; - uint32_t physical_height = 158; - - bool cursor_visible = false; - - uint32_t hotspot_x{}, hotspot_y{}; - - void resize(int w, int h, uint32_t pw, uint32_t ph); - void cursor_move(uint32_t x, uint32_t y); - void set_cursor_visibility(bool visibility); - std::function set_renderer_visibility = [](bool){}; -private: - lorie_compositor& compositor; - - void set_toplevel(wayland::surface_t* surface); - void set_cursor(wayland::surface_t* surface, uint32_t hotspot_x, uint32_t hotspot_y); - - struct wl_event_source *idle = NULL; - void draw(GLuint id, float x0, float y0, float x1, float y1) const; - void draw_cursor(); - void redraw(); - GLuint g_texture_program = 0; - GLuint gv_pos = 0; - GLuint gv_coords = 0; - GLuint gv_texture_sampler_handle = 0; - - struct { - GLuint id; - GLsizei width, height; - inline void reset() { width = 0; height = 0; } - inline bool valid() { return width != 0 && height != 0; } - } toplevel_texture{}, cursor_texture{}; - - bool ready = false; - bool visible = false; - - friend class lorie_texture; - friend class lorie_compositor; -}; diff --git a/app/src/main/jni/lorie/lorie_egl_helper.cpp b/app/src/main/jni/lorie/lorie_egl_helper.cpp deleted file mode 100644 index 122f3f2..0000000 --- a/app/src/main/jni/lorie/lorie_egl_helper.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include -#include -#include - -static char* eglGetErrorText(int code) { - switch(eglGetError()) { -#define E(code, desc) case code: return (char*) desc; break; - case EGL_SUCCESS: return nullptr; // "No error" - E(EGL_NOT_INITIALIZED, "EGL not initialized or failed to initialize"); - E(EGL_BAD_ACCESS, "Resource inaccessible"); - E(EGL_BAD_ALLOC, "Cannot allocate resources"); - E(EGL_BAD_ATTRIBUTE, "Unrecognized attribute or attribute value"); - E(EGL_BAD_CONTEXT, "Invalid EGL context"); - E(EGL_BAD_CONFIG, "Invalid EGL frame buffer configuration"); - E(EGL_BAD_CURRENT_SURFACE, "Current surface is no longer valid"); - E(EGL_BAD_DISPLAY, "Invalid EGL display"); - E(EGL_BAD_SURFACE, "Invalid surface"); - E(EGL_BAD_MATCH, "Inconsistent arguments"); - E(EGL_BAD_PARAMETER, "Invalid argument"); - E(EGL_BAD_NATIVE_PIXMAP, "Invalid native pixmap"); - E(EGL_BAD_NATIVE_WINDOW, "Invalid native window"); - E(EGL_CONTEXT_LOST, "Context lost"); -#undef E - default: return (char*) "Unknown error"; - } -} - -#undef checkEGLError -void checkEGLError(int line) { - char *error = eglGetErrorText(eglGetError()); - if (error != nullptr) - LOGE("EGL: %s after %d", error, line); -} -#define checkEGLError() checkEGLError(__LINE__) - -bool LorieEGLHelper::init(EGLNativeDisplayType display) { - EGLint majorVersion, minorVersion; - - LOGV("Initializing EGL"); - dpy = eglGetDisplay(display); checkEGLError(); - if (dpy == EGL_NO_DISPLAY) { - LOGE("LorieEGLHelper::init : eglGetDisplay failed: %s", eglGetErrorText(eglGetError())); - return false; - } - - if (eglInitialize(dpy, &majorVersion, &minorVersion) != EGL_TRUE) { - LOGE("LorieEGLHelper::init : eglInitialize failed: %s", eglGetErrorText(eglGetError())); - return false; - } - - const EGLint configAttribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_NONE - }; - - EGLint numConfigs; - - if (eglChooseConfig(dpy, configAttribs, &cfg, 1, &numConfigs) != EGL_TRUE) { - LOGE("LorieEGLHelper::init : eglChooseConfig failed: %s", eglGetErrorText(eglGetError())); - return false; - } - - eglBindAPI(EGL_OPENGL_ES_API); - - const EGLint ctxattribs[] = { - EGL_CONTEXT_CLIENT_VERSION, - 2, // Request opengl ES2.0 - EGL_NONE - }; - - ctx = eglCreateContext(dpy, cfg, NULL, ctxattribs); - if (ctx == EGL_NO_CONTEXT) { - LOGE("LorieEGLHelper::init : eglCreateContext failed: %s", eglGetErrorText(eglGetError())); - return false; - } - - if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONFIG_KHR) != EGL_TRUE) { - LOGE("LorieEGLHelper::init : eglMakeCurrent failed: %s", eglGetErrorText(eglGetError())); - return false; - } - - return true; -} - -bool LorieEGLHelper::setWindow(EGLNativeWindowType window) { - LOGV("Trying to use window %p", window); - if (sfc != EGL_NO_SURFACE) { - if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) { - LOGE("LorieEGLHelper::setWindow : eglMakeCurrent (EGL_NO_SURFACE) failed: %s", eglGetErrorText(eglGetError())); - return false; - } - if (eglDestroySurface(dpy, sfc) != EGL_TRUE) { - LOGE("LorieEGLHelper::setWindow : eglDestoySurface failed: %s", eglGetErrorText(eglGetError())); - return false; - } - }; - - sfc = EGL_NO_SURFACE; - win = window; - - if (win == EGL_NO_WINDOW) { - if (onUninit != nullptr) onUninit(); - return true; - } - - sfc = eglCreateWindowSurface(dpy, cfg, win, NULL); - if (sfc == EGL_NO_SURFACE) { - LOGE("LorieEGLHelper::setWindow : eglCreateWindowSurface failed: %s", eglGetErrorText(eglGetError())); - if (onUninit != nullptr) onUninit(); - return false; - } - - if (eglMakeCurrent(dpy, sfc, sfc, ctx) != EGL_TRUE) { - LOGE("LorieEGLHelper::setWindow : eglMakeCurrent failed: %s", eglGetErrorText(eglGetError())); - if (onUninit != nullptr) onUninit(); - return false; - } - - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - - swap(); - - if (onInit != nullptr) - onInit(); - - return true; -} - -void LorieEGLHelper::swap() { - EGLint b = eglSwapBuffers(dpy, sfc); - if (b != EGL_TRUE) { - EGLint err = eglGetError(); - if (err == EGL_BAD_SURFACE) { - LOGE("eglSwapBuffers failed because of invalid surface. Regenerating surface."); - setWindow(win); - } else if (err == EGL_BAD_CONTEXT || err == EGL_CONTEXT_LOST) { - LOGE("eglSwapBuffers failed because of invalid context. Regenerating context."); - const EGLint ctxattribs[] = { - EGL_CONTEXT_CLIENT_VERSION, - 2, // Request opengl ES2.0 - EGL_NONE - }; - - ctx = eglCreateContext(dpy, cfg, NULL, ctxattribs); - if (ctx == EGL_NO_CONTEXT) { - LOGE("LorieEGLHelper::init : eglCreateContext failed: %s", eglGetErrorText(eglGetError())); - return; - } - } - } -} - -void LorieEGLHelper::uninit() { - if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) { - LOGE("LorieEGLHelper::uninit : eglMakeCurrent failed: %s", eglGetErrorText(eglGetError())); - return; - } - if (eglDestroyContext(dpy, ctx) != EGL_TRUE) { - LOGE("LorieEGLHelper::uninit : eglDestroyContext failed: %s", eglGetErrorText(eglGetError())); - return; - } - ctx = EGL_NO_CONTEXT; - - if (eglDestroySurface(dpy, sfc) != EGL_TRUE) { - LOGE("LorieEGLHelper::uninit : eglDestroySurface failed: %s", eglGetErrorText(eglGetError())); - return; - } - sfc = EGL_NO_SURFACE; - - if (eglTerminate(dpy) != EGL_TRUE) { - LOGE("LorieEGLHelper::uninit : eglTerminate failed: %s", eglGetErrorText(eglGetError())); - return; - } - dpy = EGL_NO_DISPLAY; -} diff --git a/app/src/main/jni/lorie/lorie_wayland_server.cpp b/app/src/main/jni/lorie/lorie_wayland_server.cpp index 9f53ac7..3726b45 100644 --- a/app/src/main/jni/lorie/lorie_wayland_server.cpp +++ b/app/src/main/jni/lorie/lorie_wayland_server.cpp @@ -61,6 +61,7 @@ void display_t::add_fd_listener(int fd, uint32_t mask, std::functionsource = wl_event_loop_add_fd(loop, fd, mask, fd_listener::fire, l); + wl_event_loop_add_destroy_listener(loop, l); } // It is wl_display_socket_add_fd version which drops server fd if it is faulty. @@ -96,7 +97,7 @@ void display_t::add_socket_fd(int fd) { client_fd = accept4(fd, (struct sockaddr *) &name, &length, SOCK_CLOEXEC); if (client_fd < 0) { LOGE("failed to accept: %s\n", strerror(errno)); - if (errno == EBADF || errno == ENOTSOCK) { + if (errno == EBADF || errno == ENOTSOCK || errno == EPERM) { l->destroy(l, nullptr); return 0; } diff --git a/app/src/main/jni/lorie/lorie_wayland_server.hpp b/app/src/main/jni/lorie/lorie_wayland_server.hpp index d3bd05b..88719c9 100644 --- a/app/src/main/jni/lorie/lorie_wayland_server.hpp +++ b/app/src/main/jni/lorie/lorie_wayland_server.hpp @@ -56,6 +56,10 @@ namespace wayland { inline void set_log_handler(wl_log_func_t f) { wl_log_set_handler_server(f); } + + inline uint32_t next_serial() { + return wl_display_next_serial(*this); + }; }; class client_t: public wl_listener { @@ -128,10 +132,6 @@ namespace wayland { inline client_t* client() { return m_client; } - - inline uint32_t next_serial() { - return wl_display_next_serial(display); - }; static inline resource_t* get(wl_resource* r) { return r == nullptr ? nullptr : static_cast(wl_resource_get_destroy_listener(r, &resource_destroyed)); diff --git a/app/src/main/jni/lorie/renderer.cpp b/app/src/main/jni/lorie/renderer.cpp deleted file mode 100644 index 70863ab..0000000 --- a/app/src/main/jni/lorie/renderer.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include -#include - -#include -#include - -using namespace wayland; - -static const char vertex_shader[] = R"( - attribute vec4 position; - attribute vec2 texCoords; - varying vec2 outTexCoords; - void main(void) { - outTexCoords = texCoords; - gl_Position = position; - } -)"; -static const char fragment_shader[] = R"( - precision mediump float; - varying vec2 outTexCoords; - uniform sampler2D texture; - void main(void) { - gl_FragColor = texture2D(texture, outTexCoords).bgra; - } -)"; - -static GLuint load_shader(GLenum shaderType, const char* pSource) { - GLuint shader = glCreateShader(shaderType); - if (shader) { - glShaderSource(shader, 1, &pSource, nullptr); - glCompileShader(shader); - GLint compiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLen = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen) { - char* buf = (char*) malloc(infoLen); - if (buf) { - glGetShaderInfoLog(shader, infoLen, nullptr, buf); - LOGE("Could not compile shader %d:\n%s\n", shaderType, buf); - free(buf); - } - glDeleteShader(shader); - shader = 0; - } - } - } - return shader; -} - -static GLuint create_program(const char* p_vertex_source, const char* p_fragment_source) { - GLuint vertexShader = load_shader(GL_VERTEX_SHADER, p_vertex_source); - if (!vertexShader) { - return 0; - } - - GLuint pixelShader = load_shader(GL_FRAGMENT_SHADER, p_fragment_source); - if (!pixelShader) { - return 0; - } - - GLuint program = glCreateProgram(); - if (program) { - glAttachShader(program, vertexShader); - glAttachShader(program, pixelShader); - glLinkProgram(program); - GLint linkStatus = GL_FALSE; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - if (linkStatus != GL_TRUE) { - GLint bufLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); - if (bufLength) { - char* buf = (char*) malloc(bufLength); - if (buf) { - glGetProgramInfoLog(program, bufLength, nullptr, buf); - LOGE("Could not link program:\n%s\n", buf); - free(buf); - } - } - glDeleteProgram(program); - program = 0; - } - } - return program; -} - -static inline lorie_compositor::surface_data* data(surface_t* sfc) { - return any_cast(sfc->user_data()); -} - -lorie_renderer::lorie_renderer(lorie_compositor& compositor) : compositor(compositor) {} - -void lorie_renderer::on_surface_create() { - LOGV("Initializing renderer (tid %d)", ::gettid()); - g_texture_program = create_program(vertex_shader, fragment_shader); - if (!g_texture_program) { - LOGE("GLESv2: Unable to create shader program"); - return; - } - gv_pos = (GLuint) glGetAttribLocation(g_texture_program, "position"); - gv_coords = (GLuint) glGetAttribLocation(g_texture_program, "texCoords"); - gv_texture_sampler_handle = (GLuint) glGetUniformLocation(g_texture_program, "texture"); - ready = true; - - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &toplevel_texture.id); - glGenTextures(1, &cursor_texture.id); - - redraw(); -} - -void lorie_renderer::request_redraw() { - //LOGV("Requesting redraw"); - if (idle) return; - - idle = wl_event_loop_add_idle( - wl_display_get_event_loop(compositor.display), - [](void* data) { reinterpret_cast(data)->redraw(); }, - this - ); -} - -void lorie_renderer::resize(int w, int h, uint32_t pw, uint32_t ph) { - LOGV("Resizing renderer to %dx%d (%dmm x %dmm)", w, h, pw, ph); - if (w == width && - h == height && - pw == physical_width && - ph == physical_height) return; - width = w; - height = h; - physical_width = pw; - physical_height = ph; - - glViewport(0, 0, w, h); - - if (compositor.toplevel) { - auto data = any_cast(compositor.toplevel->client()->user_data()); - compositor.report_mode(data->output); - } -} - -void lorie_renderer::cursor_move(uint32_t x, uint32_t y) { - if (compositor.cursor == nullptr) return; - - data(compositor.cursor)->x = x; - data(compositor.cursor)->y = y; - request_redraw(); -} - -void lorie_renderer::set_cursor_visibility(bool visibility) { - if (cursor_visible != visibility) - cursor_visible = visibility; -} - -void lorie_renderer::set_toplevel(surface_t* sfc) { - LOGV("Setting surface %p as toplevel", sfc); - compositor.toplevel = sfc; - request_redraw(); -} - -void lorie_renderer::set_cursor(surface_t* sfc, uint32_t hs_x, uint32_t hs_y) { - LOGV("Setting surface %p as cursor", sfc); - compositor.cursor = sfc; - this->hotspot_x = hs_x; - this->hotspot_y = hs_y; - - request_redraw(); -} - -void lorie_renderer::draw(GLuint id, float x0, float y0, float x1, float y1) const { - float coords[20] = { - x0, -y0, 0.f, 0.f, 0.f, - x1, -y0, 0.f, 1.f, 0.f, - x0, -y1, 0.f, 0.f, 1.f, - x1, -y1, 0.f, 1.f, 1.f, - }; - glActiveTexture(GL_TEXTURE0); - glUseProgram(g_texture_program); - glBindTexture(GL_TEXTURE_2D, id); - - glVertexAttribPointer(gv_pos, 3, GL_FLOAT, GL_FALSE, 20, coords); - glVertexAttribPointer(gv_coords, 2, GL_FLOAT, GL_FALSE, 20, &coords[3]); - glEnableVertexAttribArray(gv_pos); - glEnableVertexAttribArray(gv_coords); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -} - -void lorie_renderer::draw_cursor() { - if (compositor.cursor == nullptr) return; - - auto toplevel = compositor.toplevel ? data(compositor.toplevel) : nullptr; - auto cursor = compositor.cursor ? data(compositor.cursor) : nullptr; - - if (cursor && cursor->damaged && cursor->buffer && cursor->buffer->is_shm()) { - GLsizei w = cursor_texture.width = cursor->buffer->shm_width(); - GLsizei h = cursor_texture.height = cursor->buffer->shm_height(); - void* d = cursor->buffer->shm_data(); - glBindTexture(GL_TEXTURE_2D, cursor_texture.id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, d); - } - if (!cursor_texture.valid()) return; - - float x, y, w, h; - x = 2*(((float)(cursor->x-hotspot_x))/(float)toplevel_texture.width) - 1; - y = 2*(((float)(cursor->y-hotspot_y))/(float)toplevel_texture.height) - 1; - w = 2*((float)cursor_texture.width)/(float)toplevel_texture.width; - h = 2*((float)cursor_texture.height)/(float)toplevel_texture.height; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - draw(cursor_texture.id, x, y, x + w, y + h); - glDisable(GL_BLEND); -} - -void lorie_renderer::redraw() { - idle = nullptr; - if (!ready) return; - - if (compositor.toplevel && data(compositor.toplevel)) { - auto d = data(compositor.toplevel); - if (d->damaged && d->buffer && d->buffer->is_shm()) { - if (d->buffer->shm_width() != toplevel_texture.width || d->buffer->shm_width() != toplevel_texture.width) { - GLsizei w = toplevel_texture.width = d->buffer->shm_width(); - GLsizei h = toplevel_texture.height = d->buffer->shm_height(); - void* dd = d->buffer->shm_data(); - glBindTexture(GL_TEXTURE_2D, toplevel_texture.id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, dd); - } else { - glBindTexture(GL_TEXTURE_2D, toplevel_texture.id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, - toplevel_texture.width, toplevel_texture.height, GL_RGBA, GL_UNSIGNED_BYTE, d->buffer->shm_data()); - if (glGetError() == GL_INVALID_OPERATION) - /* For some reason if our activity goes to background it loses access - * to this texture. In this case it should be regenerated. */ - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toplevel_texture.width, toplevel_texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, d->buffer->shm_data()); - } - } - - draw(toplevel_texture.id, -1.0, -1.0, 1.0, 1.0); - - if (cursor_visible) - draw_cursor(); - if (!visible) - set_renderer_visibility(visible = true); - } else { - if (visible) - set_renderer_visibility(visible = false); - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - } - - compositor.swap_buffers(); -} diff --git a/app/src/main/jni/lorie/utils/log.cpp b/app/src/main/jni/lorie/utils/log.cpp index 9a6f1b0..8da74d3 100644 --- a/app/src/main/jni/lorie/utils/log.cpp +++ b/app/src/main/jni/lorie/utils/log.cpp @@ -17,9 +17,6 @@ static int enabled = 0; using namespace std; extern "C" { -#define COLORIZE "\033[0;32m" -#define COLOR_RESET "\033[0m" - extern void *blacklist[]; #define skip_blacklisted(f) for (int z=0; blacklist[z]!=NULL; z++) if (blacklist[z]==f) return; @@ -122,11 +119,11 @@ void LogInit(void) { LogMessageInternal(LOG_ERROR, "Logger mutex init failed\n"); return; } - + LOGD("Logging initialized"); } -static int level = -1; +static thread_local int level = -1; void print_func(void *func, int enter); @@ -150,13 +147,12 @@ __cyg_profile_func_exit (void *func, void *caller) { } void print_func(void *func, int enter) { - for (int i=0; i" : "<", status == 0 ? demangled : info.dli_sname, (level==2)?COLOR_RESET:""); + LOGP("%*c%s %s", level, ' ', enter ? ">" : "<", status == 0 ? demangled : info.dli_sname); free(demangled); } } @@ -168,7 +164,7 @@ void *blacklist[] = { #if defined(__ANDROID__) (void*) androidLogFn, #endif - (void*) LogInit, + (void*) LogInit, (void*) LogMessage, (void*) LogMessageInternal, (void*) __cyg_profile_func_enter, diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml index 7824b2e..4af66c5 100644 --- a/app/src/main/res/layout/main_activity.xml +++ b/app/src/main/res/layout/main_activity.xml @@ -10,6 +10,11 @@ android:layout_height="match_parent" android:id="@+id/frame"> + +