wineandroid: Add a JNI callback to store the native window we got from the TextureView.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2017-06-02 11:37:16 +02:00
parent 7124a7d90c
commit 9a134711e6
5 changed files with 166 additions and 2 deletions

View File

@ -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 );
}
}

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <jni.h>
#include <android/log.h>
#include <android/native_window_jni.h>
#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 );

View File

@ -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;
}

View File

@ -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

View File

@ -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 );
}