wineandroid: Add Java callbacks for creating and destroying a window.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
bcd99f5c37
commit
347699d773
|
@ -269,6 +269,35 @@ private final void copyAssetFiles()
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generic Wine window class
|
||||
//
|
||||
|
||||
private HashMap<Integer,WineWindow> win_map = new HashMap<Integer,WineWindow>();
|
||||
|
||||
protected class WineWindow extends Object
|
||||
{
|
||||
protected int hwnd;
|
||||
|
||||
public WineWindow( int w, WineWindow parent )
|
||||
{
|
||||
Log.i( LOGTAG, String.format( "create hwnd %08x", w ));
|
||||
hwnd = w;
|
||||
win_map.put( w, this );
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
Log.i( LOGTAG, String.format( "destroy hwnd %08x", hwnd ));
|
||||
win_map.remove( this );
|
||||
}
|
||||
|
||||
public int get_hwnd()
|
||||
{
|
||||
return hwnd;
|
||||
}
|
||||
}
|
||||
|
||||
// The top-level desktop view group
|
||||
|
||||
protected class TopView extends ViewGroup
|
||||
|
@ -297,6 +326,11 @@ protected void onLayout( boolean changed, int left, int top, int right, int bott
|
|||
|
||||
protected TopView top_view;
|
||||
|
||||
protected WineWindow get_window( int hwnd )
|
||||
{
|
||||
return win_map.get( hwnd );
|
||||
}
|
||||
|
||||
// Entry points for the device driver
|
||||
|
||||
public void create_desktop_window( int hwnd )
|
||||
|
@ -307,8 +341,30 @@ public void create_desktop_window( int hwnd )
|
|||
progress_dialog.dismiss();
|
||||
}
|
||||
|
||||
public void create_window( int hwnd, int parent, int pid )
|
||||
{
|
||||
WineWindow win = get_window( hwnd );
|
||||
if (win == null) win = new WineWindow( hwnd, get_window( parent ));
|
||||
}
|
||||
|
||||
public void destroy_window( int hwnd )
|
||||
{
|
||||
WineWindow win = get_window( hwnd );
|
||||
if (win != null) win.destroy();
|
||||
}
|
||||
|
||||
public void createDesktopWindow( final int hwnd )
|
||||
{
|
||||
runOnUiThread( new Runnable() { public void run() { create_desktop_window( hwnd ); }} );
|
||||
}
|
||||
|
||||
public void createWindow( final int hwnd, final int parent, final int pid )
|
||||
{
|
||||
runOnUiThread( new Runnable() { public void run() { create_window( hwnd, parent, pid ); }} );
|
||||
}
|
||||
|
||||
public void destroyWindow( final int hwnd )
|
||||
{
|
||||
runOnUiThread( new Runnable() { public void run() { destroy_window( hwnd ); }} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ DECL_FUNCPTR( __android_log_print );
|
|||
*/
|
||||
|
||||
extern void start_android_device(void) DECLSPEC_HIDDEN;
|
||||
extern void create_ioctl_window( HWND hwnd ) DECLSPEC_HIDDEN;
|
||||
extern void destroy_ioctl_window( HWND hwnd ) DECLSPEC_HIDDEN;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
|
|
@ -48,6 +48,38 @@ static HANDLE stop_event;
|
|||
static HANDLE thread;
|
||||
static JNIEnv *jni_env;
|
||||
|
||||
#define ANDROIDCONTROLTYPE ((ULONG)'A')
|
||||
#define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
enum android_ioctl
|
||||
{
|
||||
IOCTL_CREATE_WINDOW,
|
||||
IOCTL_DESTROY_WINDOW,
|
||||
NB_IOCTLS
|
||||
};
|
||||
|
||||
struct ioctl_header
|
||||
{
|
||||
int hwnd;
|
||||
};
|
||||
|
||||
struct ioctl_android_create_window
|
||||
{
|
||||
struct ioctl_header hdr;
|
||||
int parent;
|
||||
};
|
||||
|
||||
struct ioctl_android_destroy_window
|
||||
{
|
||||
struct ioctl_header hdr;
|
||||
};
|
||||
|
||||
|
||||
static inline DWORD current_client_id(void)
|
||||
{
|
||||
return HandleToUlong( PsGetCurrentProcessId() );
|
||||
}
|
||||
|
||||
#ifdef __i386__ /* the Java VM uses %fs for its own purposes, so we need to wrap the calls */
|
||||
static WORD orig_fs, java_fs;
|
||||
static inline void wrap_java_call(void) { wine_set_fs( java_fs ); }
|
||||
|
@ -57,6 +89,31 @@ static inline void wrap_java_call(void) { }
|
|||
static inline void unwrap_java_call(void) { }
|
||||
#endif /* __i386__ */
|
||||
|
||||
|
||||
static int status_to_android_error( NTSTATUS status )
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_SUCCESS: return 0;
|
||||
case STATUS_NO_MEMORY: return -ENOMEM;
|
||||
case STATUS_NOT_SUPPORTED: return -ENOSYS;
|
||||
case STATUS_INVALID_PARAMETER: return -EINVAL;
|
||||
case STATUS_BUFFER_OVERFLOW: return -EINVAL;
|
||||
case STATUS_INVALID_HANDLE: return -ENOENT;
|
||||
case STATUS_ACCESS_DENIED: return -EPERM;
|
||||
case STATUS_NO_SUCH_DEVICE: return -ENODEV;
|
||||
case STATUS_DUPLICATE_NAME: return -EEXIST;
|
||||
case STATUS_PIPE_DISCONNECTED: return -EPIPE;
|
||||
case STATUS_NO_MORE_FILES: return -ENODATA;
|
||||
case STATUS_IO_TIMEOUT: return -ETIMEDOUT;
|
||||
case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG;
|
||||
case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK;
|
||||
default:
|
||||
FIXME( "unmapped status %08x\n", status );
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static jobject load_java_method( jmethodID *method, const char *name, const char *args )
|
||||
{
|
||||
jobject object = wine_get_java_object();
|
||||
|
@ -90,13 +147,75 @@ static void create_desktop_window( HWND hwnd )
|
|||
unwrap_java_call();
|
||||
}
|
||||
|
||||
static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
|
||||
{
|
||||
static jmethodID method;
|
||||
jobject object;
|
||||
struct ioctl_android_create_window *res = data;
|
||||
DWORD pid = current_client_id();
|
||||
|
||||
if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
|
||||
|
||||
if (!(object = load_java_method( &method, "createWindow", "(III)V" ))) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
wrap_java_call();
|
||||
(*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, pid );
|
||||
unwrap_java_call();
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
|
||||
{
|
||||
static jmethodID method;
|
||||
jobject object;
|
||||
struct ioctl_android_destroy_window *res = data;
|
||||
|
||||
if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
TRACE( "hwnd %08x\n", res->hdr.hwnd );
|
||||
|
||||
if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
wrap_java_call();
|
||||
(*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
|
||||
unwrap_java_call();
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
|
||||
static const ioctl_func ioctl_funcs[] =
|
||||
{
|
||||
createWindow_ioctl, /* IOCTL_CREATE_WINDOW */
|
||||
destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */
|
||||
};
|
||||
|
||||
static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
|
||||
{
|
||||
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
|
||||
DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2;
|
||||
|
||||
if (code < NB_IOCTLS)
|
||||
{
|
||||
struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer;
|
||||
DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength;
|
||||
ioctl_func func = ioctl_funcs[code];
|
||||
|
||||
if (in_size >= sizeof(*header))
|
||||
{
|
||||
irp->IoStatus.Information = 0;
|
||||
irp->IoStatus.u.Status = func( irp->AssociatedIrp.SystemBuffer, in_size,
|
||||
irpsp->Parameters.DeviceIoControl.OutputBufferLength,
|
||||
&irp->IoStatus.Information );
|
||||
}
|
||||
else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
|
||||
irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
}
|
||||
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -170,3 +289,51 @@ void start_android_device(void)
|
|||
WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
|
||||
CloseHandle( handles[0] );
|
||||
}
|
||||
|
||||
|
||||
/* Client-side ioctl support */
|
||||
|
||||
|
||||
static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size )
|
||||
{
|
||||
static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
|
||||
static HANDLE device;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!device)
|
||||
{
|
||||
HANDLE file = CreateFileW( deviceW, GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (file == INVALID_HANDLE_VALUE) return -ENOENT;
|
||||
if (InterlockedCompareExchangePointer( &device, file, NULL )) CloseHandle( file );
|
||||
}
|
||||
|
||||
status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code),
|
||||
in, in_size, out, out_size ? *out_size : 0 );
|
||||
if (status == STATUS_FILE_DELETED)
|
||||
{
|
||||
WARN( "parent process is gone\n" );
|
||||
ExitProcess( 1 );
|
||||
}
|
||||
if (out_size) *out_size = iosb.Information;
|
||||
return status_to_android_error( status );
|
||||
}
|
||||
|
||||
void create_ioctl_window( HWND hwnd )
|
||||
{
|
||||
struct ioctl_android_create_window req;
|
||||
HWND parent = GetAncestor( hwnd, GA_PARENT );
|
||||
|
||||
req.hdr.hwnd = HandleToLong( hwnd );
|
||||
req.parent = parent == GetDesktopWindow() ? 0 : HandleToLong( parent );
|
||||
android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL );
|
||||
}
|
||||
|
||||
void destroy_ioctl_window( HWND hwnd )
|
||||
{
|
||||
struct ioctl_android_destroy_window req;
|
||||
|
||||
req.hdr.hwnd = HandleToLong( hwnd );
|
||||
android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL );
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ static struct android_win_data *alloc_win_data( HWND hwnd )
|
|||
if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
|
||||
{
|
||||
data->hwnd = hwnd;
|
||||
create_ioctl_window( hwnd );
|
||||
EnterCriticalSection( &win_data_section );
|
||||
win_data_context[context_idx(hwnd)] = data;
|
||||
}
|
||||
|
@ -102,6 +103,7 @@ static void free_win_data( struct android_win_data *data )
|
|||
{
|
||||
win_data_context[context_idx( data->hwnd )] = NULL;
|
||||
LeaveCriticalSection( &win_data_section );
|
||||
destroy_ioctl_window( data->hwnd );
|
||||
HeapFree( GetProcessHeap(), 0, data );
|
||||
}
|
||||
|
||||
|
@ -328,8 +330,13 @@ BOOL CDECL ANDROID_CreateWindow( HWND hwnd )
|
|||
|
||||
if (hwnd == GetDesktopWindow())
|
||||
{
|
||||
struct android_win_data *data;
|
||||
|
||||
init_event_queue();
|
||||
start_android_device();
|
||||
|
||||
if (!(data = alloc_win_data( hwnd ))) return FALSE;
|
||||
release_win_data( data );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue