From 9a134711e6598081d5af55a3f02df625f669a036 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 2 Jun 2017 11:37:16 +0200 Subject: [PATCH] wineandroid: Add a JNI callback to store the native window we got from the TextureView. Signed-off-by: Alexandre Julliard --- dlls/wineandroid.drv/WineActivity.java | 2 + dlls/wineandroid.drv/android.h | 14 ++++ dlls/wineandroid.drv/device.c | 95 ++++++++++++++++++++++++++ dlls/wineandroid.drv/init.c | 12 +++- dlls/wineandroid.drv/window.c | 45 +++++++++++- 5 files changed, 166 insertions(+), 2 deletions(-) diff --git a/dlls/wineandroid.drv/WineActivity.java b/dlls/wineandroid.drv/WineActivity.java index 2eca5fc28d9..50ff0bfdec4 100644 --- a/dlls/wineandroid.drv/WineActivity.java +++ b/dlls/wineandroid.drv/WineActivity.java @@ -50,6 +50,7 @@ public class WineActivity extends Activity { private native String wine_init( String[] cmdline, String[] env ); public native void wine_desktop_changed( int width, int height ); + public native void wine_surface_changed( int hwnd, Surface surface ); private final String LOGTAG = "wine"; private ProgressDialog progress_dialog; @@ -346,6 +347,7 @@ public void set_surface( SurfaceTexture surftex ) if (surftex == null) window_surface = null; else if (window_surface == null) window_surface = new Surface( surftex ); Log.i( LOGTAG, String.format( "set window surface hwnd %08x %s", hwnd, window_surface )); + wine_surface_changed( hwnd, window_surface ); } } diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index fb8b67d60ea..f03671ae2ff 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "windef.h" #include "winbase.h" @@ -41,6 +42,8 @@ #define DECL_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN DECL_FUNCPTR( __android_log_print ); +DECL_FUNCPTR( ANativeWindow_fromSurface ); +DECL_FUNCPTR( ANativeWindow_release ); #undef DECL_FUNCPTR @@ -49,6 +52,7 @@ DECL_FUNCPTR( __android_log_print ); */ extern void start_android_device(void) DECLSPEC_HIDDEN; +extern void register_native_window( HWND hwnd, struct ANativeWindow *win ) DECLSPEC_HIDDEN; extern void create_ioctl_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void destroy_ioctl_window( HWND hwnd ) DECLSPEC_HIDDEN; extern int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const RECT *client_rect, @@ -69,10 +73,12 @@ extern void init_monitors( int width, int height ) DECLSPEC_HIDDEN; /* JNI entry points */ extern void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height ) DECLSPEC_HIDDEN; +extern void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface ) DECLSPEC_HIDDEN; enum event_type { DESKTOP_CHANGED, + SURFACE_CHANGED, }; union event_data @@ -84,6 +90,14 @@ union event_data unsigned int width; unsigned int height; } desktop; + struct + { + enum event_type type; + HWND hwnd; + ANativeWindow *window; + unsigned int width; + unsigned int height; + } surface; }; int send_event( const union event_data *data ); diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 1acb2435ef8..3dacd4828b2 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -59,6 +59,13 @@ enum android_ioctl NB_IOCTLS }; +/* data about the native window in the context of the Java process */ +struct native_win_data +{ + struct ANativeWindow *parent; + HWND hwnd; +}; + struct ioctl_header { int hwnd; @@ -101,6 +108,86 @@ static inline void wrap_java_call(void) { } static inline void unwrap_java_call(void) { } #endif /* __i386__ */ +static struct native_win_data *data_map[65536]; + +static unsigned int data_map_idx( HWND hwnd ) +{ + return LOWORD(hwnd); +} + +static struct native_win_data *get_native_win_data( HWND hwnd ) +{ + struct native_win_data *data = data_map[data_map_idx( hwnd )]; + + if (data && data->hwnd == hwnd) return data; + WARN( "unknown win %p\n", hwnd ); + return NULL; +} + +static struct native_win_data *get_ioctl_native_win_data( const struct ioctl_header *hdr ) +{ + return get_native_win_data( LongToHandle(hdr->hwnd) ); +} + +static void release_native_window( struct native_win_data *data ) +{ + if (data->parent) pANativeWindow_release( data->parent ); +} + +static void free_native_win_data( struct native_win_data *data ) +{ + unsigned int idx = data_map_idx( data->hwnd ); + + release_native_window( data ); + HeapFree( GetProcessHeap(), 0, data ); + data_map[idx] = NULL; +} + +static struct native_win_data *create_native_win_data( HWND hwnd ) +{ + unsigned int idx = data_map_idx( hwnd ); + struct native_win_data *data = data_map[idx]; + + if (data) + { + WARN( "data for %p not freed correctly\n", data->hwnd ); + free_native_win_data( data ); + } + if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return NULL; + data->hwnd = hwnd; + data_map[idx] = data; + return data; +} + +static void CALLBACK register_native_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 ) +{ + HWND hwnd = (HWND)arg1; + struct ANativeWindow *win = (struct ANativeWindow *)arg2; + struct native_win_data *data = get_native_win_data( hwnd ); + + if (!data || data->parent == win) + { + if (win) pANativeWindow_release( win ); + TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win ); + return; + } + + release_native_window( data ); + data->parent = win; + if (win) + { + wrap_java_call(); + win->perform( win, NATIVE_WINDOW_API_CONNECT, NATIVE_WINDOW_API_CPU ); + unwrap_java_call(); + } + TRACE( "%p -> %p win %p\n", hwnd, data, win ); +} + +/* register a native window received from the Java side for use in ioctls */ +void register_native_window( HWND hwnd, struct ANativeWindow *win ) +{ + NtQueueApcThread( thread, register_native_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, 0 ); +} static int status_to_android_error( NTSTATUS status ) { @@ -164,10 +251,14 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U static jmethodID method; jobject object; struct ioctl_android_create_window *res = data; + struct native_win_data *win_data; DWORD pid = current_client_id(); if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd) ))) + return STATUS_NO_MEMORY; + TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent ); if (!(object = load_java_method( &method, "createWindow", "(III)V" ))) return STATUS_NOT_SUPPORTED; @@ -183,9 +274,12 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, static jmethodID method; jobject object; struct ioctl_android_destroy_window *res = data; + struct native_win_data *win_data; if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; + TRACE( "hwnd %08x\n", res->hdr.hwnd ); if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; @@ -193,6 +287,7 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, wrap_java_call(); (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd ); unwrap_java_call(); + free_native_win_data( win_data ); return STATUS_SUCCESS; } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 406edf911d5..ecf32adca56 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -390,6 +390,7 @@ const struct gdi_dc_funcs * CDECL ANDROID_get_gdi_driver( unsigned int version ) static const JNINativeMethod methods[] = { { "wine_desktop_changed", "(II)V", desktop_changed }, + { "wine_surface_changed", "(ILandroid/view/Surface;)V", surface_changed }, }; #define DECL_FUNCPTR(f) typeof(f) * p##f = NULL @@ -399,18 +400,27 @@ static const JNINativeMethod methods[] = } while(0) DECL_FUNCPTR( __android_log_print ); +DECL_FUNCPTR( ANativeWindow_fromSurface ); +DECL_FUNCPTR( ANativeWindow_release ); static void load_android_libs(void) { - void *liblog; + void *libandroid, *liblog; char error[1024]; + if (!(libandroid = wine_dlopen( "libandroid.so", RTLD_GLOBAL, error, sizeof(error) ))) + { + ERR( "failed to load libandroid.so: %s\n", error ); + return; + } if (!(liblog = wine_dlopen( "liblog.so", RTLD_GLOBAL, error, sizeof(error) ))) { ERR( "failed to load liblog.so: %s\n", error ); return; } LOAD_FUNCPTR( liblog, __android_log_print ); + LOAD_FUNCPTR( libandroid, ANativeWindow_fromSurface ); + LOAD_FUNCPTR( libandroid, ANativeWindow_release ); } #undef DECL_FUNCPTR diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 437fa355108..49520ebb191 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -183,6 +183,35 @@ void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height ) } +/*********************************************************************** + * surface_changed + * + * JNI callback, runs in the context of the Java thread. + */ +void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface ) +{ + union event_data data; + + memset( &data, 0, sizeof(data) ); + data.surface.hwnd = LongToHandle( win ); + if (surface) + { + int width, height; + ANativeWindow *win = pANativeWindow_fromSurface( env, surface ); + + if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0; + if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0; + data.surface.window = win; + data.surface.width = width; + data.surface.height = height; + p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %ux%u", + data.surface.hwnd, width, height ); + } + data.type = SURFACE_CHANGED; + send_event( &data ); +} + + /*********************************************************************** * init_event_queue */ @@ -255,7 +284,14 @@ static int process_events( DWORD mask ) LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry ) { - if (!(mask & QS_SENDMESSAGE)) continue; /* skip it */ + switch (event->data.type) + { + case SURFACE_CHANGED: + break; /* always process it to unblock other threads */ + default: + if (mask & QS_SENDMESSAGE) break; + continue; /* skip it */ + } /* remove it first, in case we process events recursively */ list_remove( &event->entry ); @@ -272,6 +308,13 @@ static int process_events( DWORD mask ) SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW ); break; + case SURFACE_CHANGED: + TRACE("SURFACE_CHANGED %p %p size %ux%u\n", event->data.surface.hwnd, + event->data.surface.window, event->data.surface.width, event->data.surface.height ); + + register_native_window( event->data.surface.hwnd, event->data.surface.window ); + break; + default: FIXME( "got event %u\n", event->data.type ); }