From 47fc749018b405fcf4d20b074ebf7ddc3119ab0e Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Sat, 14 Dec 2024 23:33:29 +0100 Subject: [PATCH] implement WindowManager for composeUI popups currently everything is created as GtkPopover which is not ideal for toplevel windows, so print a warning in that case. --- meson.build | 1 + .../android_view_WindowManagerImpl.h | 37 +++++++++++++++ .../views/android_view_WindowManagerImpl.c | 45 +++++++++++++++++++ src/api-impl/android/view/WindowManager.java | 2 + .../android/view/WindowManagerImpl.java | 19 +++++++- 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/api-impl-jni/generated_headers/android_view_WindowManagerImpl.h create mode 100644 src/api-impl-jni/views/android_view_WindowManagerImpl.c diff --git a/meson.build b/meson.build index aba6f3b4..fce6a79b 100644 --- a/meson.build +++ b/meson.build @@ -128,6 +128,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/views/AndroidLayout.c', 'src/api-impl-jni/views/android_view_View.c', 'src/api-impl-jni/views/android_view_ViewGroup.c', + 'src/api-impl-jni/views/android_view_WindowManagerImpl.c', 'src/api-impl-jni/widgets/WrapperWidget.c', 'src/api-impl-jni/widgets/android_view_SurfaceView.c', 'src/api-impl-jni/widgets/android_webkit_WebView.c', diff --git a/src/api-impl-jni/generated_headers/android_view_WindowManagerImpl.h b/src/api-impl-jni/generated_headers/android_view_WindowManagerImpl.h new file mode 100644 index 00000000..f7a3d4de --- /dev/null +++ b/src/api-impl-jni/generated_headers/android_view_WindowManagerImpl.h @@ -0,0 +1,37 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class android_view_WindowManagerImpl */ + +#ifndef _Included_android_view_WindowManagerImpl +#define _Included_android_view_WindowManagerImpl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: android_view_WindowManagerImpl + * Method: native_addView + * Signature: (JIIIII)V + */ +JNIEXPORT void JNICALL Java_android_view_WindowManagerImpl_native_1addView + (JNIEnv *, jclass, jlong, jint, jint, jint, jint, jint); + +/* + * Class: android_view_WindowManagerImpl + * Method: native_updateViewLayout + * Signature: (JIIII)V + */ +JNIEXPORT void JNICALL Java_android_view_WindowManagerImpl_native_1updateViewLayout + (JNIEnv *, jclass, jlong, jint, jint, jint, jint); + +/* + * Class: android_view_WindowManagerImpl + * Method: native_removeView + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_view_WindowManagerImpl_native_1removeView + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/api-impl-jni/views/android_view_WindowManagerImpl.c b/src/api-impl-jni/views/android_view_WindowManagerImpl.c new file mode 100644 index 00000000..cae8e94b --- /dev/null +++ b/src/api-impl-jni/views/android_view_WindowManagerImpl.c @@ -0,0 +1,45 @@ +#include + +#include "../defines.h" +#include "gdk/gdk.h" +#include "glib-object.h" +#include "../generated_headers/android_view_WindowManagerImpl.h" + +#define FIRST_SUB_WINDOW 1000 +#define LAST_SUB_WINDOW 1999 + +extern GtkWindow *window; + +JNIEXPORT void JNICALL Java_android_view_WindowManagerImpl_native_1addView(JNIEnv *env, jclass clazz, jlong widget_ptr, jint type, jint x, jint y, jint width, jint height) +{ + GtkWidget *widget = _PTR(widget_ptr); + if (type < FIRST_SUB_WINDOW || type > LAST_SUB_WINDOW) { + // TODO: handle toplevel windows properly + printf("WARNING: non subwindow types not implemented properly in WindowManagerImpl\n"); + } + GtkPopover *popover = GTK_POPOVER(g_object_ref(gtk_popover_new())); + gtk_popover_set_child(popover, gtk_widget_get_parent(widget)); + printf("::: x=%d, y=%d, width=%d, height=%d\n", x, y, width, height); + gtk_popover_set_autohide(popover, FALSE); + gtk_popover_set_pointing_to(popover, &(GdkRectangle){.x=x, .y=y}); + gtk_widget_insert_before(GTK_WIDGET(popover), gtk_window_get_child(window), NULL); + gtk_popover_present(popover); + gtk_popover_popup(popover); + gtk_widget_queue_allocate(gtk_widget_get_parent(gtk_window_get_child(window))); +} + +JNIEXPORT void JNICALL Java_android_view_WindowManagerImpl_native_1updateViewLayout(JNIEnv *env, jclass clazz, jlong widget_ptr, jint x, jint y, jint width, jint height) +{ + GtkPopover *popover = GTK_POPOVER(gtk_widget_get_parent(gtk_widget_get_parent(gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr)))))); + printf("updateViewLayout::: x=%d, y=%d, width=%d, height=%d\n", x, y, width, height); + gtk_popover_set_pointing_to(popover, &(GdkRectangle){.x=x, .y=y}); +} + +JNIEXPORT void JNICALL Java_android_view_WindowManagerImpl_native_1removeView(JNIEnv *env, jclass clazz, jlong widget_ptr) +{ + GtkPopover *popover = GTK_POPOVER(gtk_widget_get_parent(gtk_widget_get_parent(gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr)))))); + gtk_popover_popdown(popover); + gtk_widget_unparent(GTK_WIDGET(popover)); + gtk_popover_set_child(popover, NULL); + g_object_unref(popover); +} diff --git a/src/api-impl/android/view/WindowManager.java b/src/api-impl/android/view/WindowManager.java index d1b0f808..a5b4859c 100644 --- a/src/api-impl/android/view/WindowManager.java +++ b/src/api-impl/android/view/WindowManager.java @@ -5,6 +5,8 @@ import android.os.IBinder; public interface WindowManager { public android.view.Display getDefaultDisplay(); + public void removeViewImmediate(View view); + public class LayoutParams extends ViewGroup.LayoutParams { public static final int FLAG_KEEP_SCREEN_ON = 0; public static final int FLAG_DIM_BEHIND = 2; diff --git a/src/api-impl/android/view/WindowManagerImpl.java b/src/api-impl/android/view/WindowManagerImpl.java index 624c82b8..912eb29f 100644 --- a/src/api-impl/android/view/WindowManagerImpl.java +++ b/src/api-impl/android/view/WindowManagerImpl.java @@ -8,16 +8,31 @@ public class WindowManagerImpl implements WindowManager, ViewManager { @Override public void addView(View view, android.view.ViewGroup.LayoutParams params) { System.out.println("WindowManagerImpl.addView(" + view + ", " + params + ") called"); + view.setLayoutParams(params); + view.onAttachedToWindow(); + WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams)params; + native_addView(view.widget, windowParams.type, windowParams.x, windowParams.y, params.width, params.height); } @Override public void updateViewLayout(View view, android.view.ViewGroup.LayoutParams params) { System.out.println("WindowManagerImpl.updateViewLayout(" + view + ", " + params + ") called"); + WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams)params; + view.setLayoutParams(params); + native_updateViewLayout(view.widget, windowParams.x, windowParams.y, params.width, params.height); } @Override public void removeView(View view) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'removeView'"); + native_removeView(view.widget); } + + @Override + public void removeViewImmediate(View view) { + removeView(view); + } + + private static native void native_addView(long widget, int type, int x, int y, int width, int height); + private static native void native_updateViewLayout(long widget, int x, int y, int width, int height); + private static native void native_removeView(long widget); }