2 * Android pseudo-device handling
4 * Copyright 2014-2017 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
28 #include <sys/ioctl.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
34 #define WIN32_NO_STATUS
41 #include "wine/library.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(android
);
46 extern NTSTATUS CDECL
wine_ntoskrnl_main_loop( HANDLE stop_event
);
47 static HANDLE stop_event
;
49 static JNIEnv
*jni_env
;
51 #define ANDROIDCONTROLTYPE ((ULONG)'A')
52 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
58 IOCTL_WINDOW_POS_CHANGED
,
65 /* data about the native window in the context of the Java process */
66 struct native_win_data
68 struct ANativeWindow
*parent
;
75 /* wrapper for a native window in the context of the client (non-Java) process */
76 struct native_win_wrapper
78 struct ANativeWindow win
;
88 struct ioctl_android_create_window
90 struct ioctl_header hdr
;
94 struct ioctl_android_destroy_window
96 struct ioctl_header hdr
;
99 struct ioctl_android_window_pos_changed
101 struct ioctl_header hdr
;
111 struct ioctl_android_query
113 struct ioctl_header hdr
;
118 struct ioctl_android_perform
120 struct ioctl_header hdr
;
125 struct ioctl_android_set_swap_interval
127 struct ioctl_header hdr
;
131 static inline DWORD
current_client_id(void)
133 return HandleToUlong( PsGetCurrentProcessId() );
136 #ifdef __i386__ /* the Java VM uses %fs for its own purposes, so we need to wrap the calls */
137 static WORD orig_fs
, java_fs
;
138 static inline void wrap_java_call(void) { wine_set_fs( java_fs
); }
139 static inline void unwrap_java_call(void) { wine_set_fs( orig_fs
); }
141 static inline void wrap_java_call(void) { }
142 static inline void unwrap_java_call(void) { }
143 #endif /* __i386__ */
145 static struct native_win_data
*data_map
[65536];
147 static unsigned int data_map_idx( HWND hwnd
)
152 static struct native_win_data
*get_native_win_data( HWND hwnd
)
154 struct native_win_data
*data
= data_map
[data_map_idx( hwnd
)];
156 if (data
&& data
->hwnd
== hwnd
) return data
;
157 WARN( "unknown win %p\n", hwnd
);
161 static struct native_win_data
*get_ioctl_native_win_data( const struct ioctl_header
*hdr
)
163 return get_native_win_data( LongToHandle(hdr
->hwnd
) );
166 static void release_native_window( struct native_win_data
*data
)
168 if (data
->parent
) pANativeWindow_release( data
->parent
);
171 static void free_native_win_data( struct native_win_data
*data
)
173 unsigned int idx
= data_map_idx( data
->hwnd
);
175 release_native_window( data
);
176 HeapFree( GetProcessHeap(), 0, data
);
177 data_map
[idx
] = NULL
;
180 static struct native_win_data
*create_native_win_data( HWND hwnd
)
182 unsigned int idx
= data_map_idx( hwnd
);
183 struct native_win_data
*data
= data_map
[idx
];
187 WARN( "data for %p not freed correctly\n", data
->hwnd
);
188 free_native_win_data( data
);
190 if (!(data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return NULL
;
192 data
->api
= NATIVE_WINDOW_API_CPU
;
193 data
->buffer_format
= PF_BGRA_8888
;
194 data_map
[idx
] = data
;
198 static void CALLBACK
register_native_window_callback( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG_PTR arg3
)
200 HWND hwnd
= (HWND
)arg1
;
201 struct ANativeWindow
*win
= (struct ANativeWindow
*)arg2
;
202 struct native_win_data
*data
= get_native_win_data( hwnd
);
204 if (!data
|| data
->parent
== win
)
206 if (win
) pANativeWindow_release( win
);
207 TRACE( "%p -> %p win %p (unchanged)\n", hwnd
, data
, win
);
211 release_native_window( data
);
216 if (data
->api
) win
->perform( win
, NATIVE_WINDOW_API_CONNECT
, data
->api
);
217 win
->perform( win
, NATIVE_WINDOW_SET_BUFFERS_FORMAT
, data
->buffer_format
);
218 win
->setSwapInterval( win
, data
->swap_interval
);
221 TRACE( "%p -> %p win %p\n", hwnd
, data
, win
);
224 /* register a native window received from the Java side for use in ioctls */
225 void register_native_window( HWND hwnd
, struct ANativeWindow
*win
)
227 NtQueueApcThread( thread
, register_native_window_callback
, (ULONG_PTR
)hwnd
, (ULONG_PTR
)win
, 0 );
230 static NTSTATUS
android_error_to_status( int err
)
234 case 0: return STATUS_SUCCESS
;
235 case -ENOMEM
: return STATUS_NO_MEMORY
;
236 case -ENOSYS
: return STATUS_NOT_SUPPORTED
;
237 case -EINVAL
: return STATUS_INVALID_PARAMETER
;
238 case -ENOENT
: return STATUS_INVALID_HANDLE
;
239 case -EPERM
: return STATUS_ACCESS_DENIED
;
240 case -ENODEV
: return STATUS_NO_SUCH_DEVICE
;
241 case -EEXIST
: return STATUS_DUPLICATE_NAME
;
242 case -EPIPE
: return STATUS_PIPE_DISCONNECTED
;
243 case -ENODATA
: return STATUS_NO_MORE_FILES
;
244 case -ETIMEDOUT
: return STATUS_IO_TIMEOUT
;
245 case -EBADMSG
: return STATUS_INVALID_DEVICE_REQUEST
;
246 case -EWOULDBLOCK
: return STATUS_DEVICE_NOT_READY
;
248 FIXME( "unmapped error %d\n", err
);
249 return STATUS_UNSUCCESSFUL
;
253 static int status_to_android_error( NTSTATUS status
)
257 case STATUS_SUCCESS
: return 0;
258 case STATUS_NO_MEMORY
: return -ENOMEM
;
259 case STATUS_NOT_SUPPORTED
: return -ENOSYS
;
260 case STATUS_INVALID_PARAMETER
: return -EINVAL
;
261 case STATUS_BUFFER_OVERFLOW
: return -EINVAL
;
262 case STATUS_INVALID_HANDLE
: return -ENOENT
;
263 case STATUS_ACCESS_DENIED
: return -EPERM
;
264 case STATUS_NO_SUCH_DEVICE
: return -ENODEV
;
265 case STATUS_DUPLICATE_NAME
: return -EEXIST
;
266 case STATUS_PIPE_DISCONNECTED
: return -EPIPE
;
267 case STATUS_NO_MORE_FILES
: return -ENODATA
;
268 case STATUS_IO_TIMEOUT
: return -ETIMEDOUT
;
269 case STATUS_INVALID_DEVICE_REQUEST
: return -EBADMSG
;
270 case STATUS_DEVICE_NOT_READY
: return -EWOULDBLOCK
;
272 FIXME( "unmapped status %08x\n", status
);
277 static jobject
load_java_method( jmethodID
*method
, const char *name
, const char *args
)
279 jobject object
= wine_get_java_object();
286 class = (*jni_env
)->GetObjectClass( jni_env
, object
);
287 *method
= (*jni_env
)->GetMethodID( jni_env
, class, name
, args
);
291 FIXME( "method %s not found\n", name
);
298 static void create_desktop_window( HWND hwnd
)
300 static jmethodID method
;
303 if (!(object
= load_java_method( &method
, "createDesktopWindow", "(I)V" ))) return;
306 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, HandleToLong( hwnd
));
310 static NTSTATUS
createWindow_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
312 static jmethodID method
;
314 struct ioctl_android_create_window
*res
= data
;
315 struct native_win_data
*win_data
;
316 DWORD pid
= current_client_id();
318 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
320 if (!(win_data
= create_native_win_data( LongToHandle(res
->hdr
.hwnd
) )))
321 return STATUS_NO_MEMORY
;
323 TRACE( "hwnd %08x parent %08x\n", res
->hdr
.hwnd
, res
->parent
);
325 if (!(object
= load_java_method( &method
, "createWindow", "(III)V" ))) return STATUS_NOT_SUPPORTED
;
328 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->parent
, pid
);
330 return STATUS_SUCCESS
;
333 static NTSTATUS
destroyWindow_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
335 static jmethodID method
;
337 struct ioctl_android_destroy_window
*res
= data
;
338 struct native_win_data
*win_data
;
340 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
342 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
344 TRACE( "hwnd %08x\n", res
->hdr
.hwnd
);
346 if (!(object
= load_java_method( &method
, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED
;
349 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
);
351 free_native_win_data( win_data
);
352 return STATUS_SUCCESS
;
355 static NTSTATUS
windowPosChanged_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
357 static jmethodID method
;
359 struct ioctl_android_window_pos_changed
*res
= data
;
361 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
363 TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
364 res
->hdr
.hwnd
, wine_dbgstr_rect(&res
->window_rect
), wine_dbgstr_rect(&res
->client_rect
),
365 wine_dbgstr_rect(&res
->visible_rect
), res
->style
, res
->flags
, res
->after
, res
->owner
);
367 if (!(object
= load_java_method( &method
, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
368 return STATUS_NOT_SUPPORTED
;
371 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->flags
, res
->after
, res
->owner
, res
->style
,
372 res
->window_rect
.left
, res
->window_rect
.top
, res
->window_rect
.right
, res
->window_rect
.bottom
,
373 res
->client_rect
.left
, res
->client_rect
.top
, res
->client_rect
.right
, res
->client_rect
.bottom
,
374 res
->visible_rect
.left
, res
->visible_rect
.top
, res
->visible_rect
.right
, res
->visible_rect
.bottom
);
376 return STATUS_SUCCESS
;
379 static NTSTATUS
query_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
381 struct ioctl_android_query
*res
= data
;
382 struct ANativeWindow
*parent
;
383 struct native_win_data
*win_data
;
386 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
387 if (out_size
< sizeof(*res
)) return STATUS_BUFFER_OVERFLOW
;
389 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
390 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
392 *ret_size
= sizeof( *res
);
394 ret
= parent
->query( parent
, res
->what
, &res
->value
);
396 return android_error_to_status( ret
);
399 static NTSTATUS
perform_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
401 struct ioctl_android_perform
*res
= data
;
402 struct ANativeWindow
*parent
;
403 struct native_win_data
*win_data
;
406 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
408 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
409 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
411 switch (res
->operation
)
413 case NATIVE_WINDOW_SET_BUFFERS_FORMAT
:
415 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
417 if (!ret
) win_data
->buffer_format
= res
->args
[0];
419 case NATIVE_WINDOW_API_CONNECT
:
421 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
423 if (!ret
) win_data
->api
= res
->args
[0];
425 case NATIVE_WINDOW_API_DISCONNECT
:
427 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
429 if (!ret
) win_data
->api
= 0;
431 case NATIVE_WINDOW_SET_USAGE
:
432 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
:
433 case NATIVE_WINDOW_SET_SCALING_MODE
:
435 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
438 case NATIVE_WINDOW_SET_BUFFER_COUNT
:
440 ret
= parent
->perform( parent
, res
->operation
, (size_t)res
->args
[0] );
443 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
:
444 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS
:
446 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0], res
->args
[1] );
449 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
:
451 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0], res
->args
[1], res
->args
[2] );
454 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
:
456 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] | ((int64_t)res
->args
[1] << 32) );
459 case NATIVE_WINDOW_CONNECT
:
460 case NATIVE_WINDOW_DISCONNECT
:
461 case NATIVE_WINDOW_UNLOCK_AND_POST
:
463 ret
= parent
->perform( parent
, res
->operation
);
466 case NATIVE_WINDOW_SET_CROP
:
468 android_native_rect_t rect
;
469 rect
.left
= res
->args
[0];
470 rect
.top
= res
->args
[1];
471 rect
.right
= res
->args
[2];
472 rect
.bottom
= res
->args
[3];
474 ret
= parent
->perform( parent
, res
->operation
, &rect
);
478 case NATIVE_WINDOW_LOCK
:
480 FIXME( "unsupported perform op %d\n", res
->operation
);
483 return android_error_to_status( ret
);
486 static NTSTATUS
setSwapInterval_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
488 struct ioctl_android_set_swap_interval
*res
= data
;
489 struct ANativeWindow
*parent
;
490 struct native_win_data
*win_data
;
493 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
495 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
496 win_data
->swap_interval
= res
->interval
;
498 if (!(parent
= win_data
->parent
)) return STATUS_SUCCESS
;
500 ret
= parent
->setSwapInterval( parent
, res
->interval
);
502 return android_error_to_status( ret
);
505 typedef NTSTATUS (*ioctl_func
)( void *in
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
);
506 static const ioctl_func ioctl_funcs
[] =
508 createWindow_ioctl
, /* IOCTL_CREATE_WINDOW */
509 destroyWindow_ioctl
, /* IOCTL_DESTROY_WINDOW */
510 windowPosChanged_ioctl
, /* IOCTL_WINDOW_POS_CHANGED */
511 query_ioctl
, /* IOCTL_QUERY */
512 perform_ioctl
, /* IOCTL_PERFORM */
513 setSwapInterval_ioctl
, /* IOCTL_SET_SWAP_INT */
516 static NTSTATUS WINAPI
ioctl_callback( DEVICE_OBJECT
*device
, IRP
*irp
)
518 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
519 DWORD code
= (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
- ANDROID_IOCTL(0)) >> 2;
521 if (code
< NB_IOCTLS
)
523 struct ioctl_header
*header
= irp
->AssociatedIrp
.SystemBuffer
;
524 DWORD in_size
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
525 ioctl_func func
= ioctl_funcs
[code
];
527 if (in_size
>= sizeof(*header
))
529 irp
->IoStatus
.Information
= 0;
530 irp
->IoStatus
.u
.Status
= func( irp
->AssociatedIrp
.SystemBuffer
, in_size
,
531 irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
,
532 &irp
->IoStatus
.Information
);
534 else irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
538 FIXME( "ioctl %x not supported\n", irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
539 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
541 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
542 return STATUS_SUCCESS
;
545 static NTSTATUS CALLBACK
init_android_driver( DRIVER_OBJECT
*driver
, UNICODE_STRING
*name
)
547 static const WCHAR device_nameW
[] = {'\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
548 static const WCHAR device_linkW
[] = {'\\','?','?','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
550 UNICODE_STRING nameW
, linkW
;
551 DEVICE_OBJECT
*device
;
554 driver
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ioctl_callback
;
556 RtlInitUnicodeString( &nameW
, device_nameW
);
557 RtlInitUnicodeString( &linkW
, device_linkW
);
559 if ((status
= IoCreateDevice( driver
, 0, &nameW
, 0, 0, FALSE
, &device
))) return status
;
560 return IoCreateSymbolicLink( &linkW
, &nameW
);
563 static DWORD CALLBACK
device_thread( void *arg
)
565 static const WCHAR driver_nameW
[] = {'\\','D','r','i','v','e','r','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
567 HANDLE start_event
= arg
;
568 UNICODE_STRING nameW
;
573 TRACE( "starting process %x\n", GetCurrentProcessId() );
575 if (!(java_vm
= wine_get_java_vm())) return 0; /* not running under Java */
578 orig_fs
= wine_get_fs();
579 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
580 java_fs
= wine_get_fs();
581 wine_set_fs( orig_fs
);
582 if (java_fs
!= orig_fs
) TRACE( "%%fs changed from %04x to %04x by Java VM\n", orig_fs
, java_fs
);
584 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
587 create_desktop_window( GetDesktopWindow() );
589 RtlInitUnicodeString( &nameW
, driver_nameW
);
590 if ((status
= IoCreateDriver( &nameW
, init_android_driver
)))
592 FIXME( "failed to create driver error %x\n", status
);
596 stop_event
= CreateEventW( NULL
, TRUE
, FALSE
, NULL
);
597 SetEvent( start_event
);
599 ret
= wine_ntoskrnl_main_loop( stop_event
);
601 (*java_vm
)->DetachCurrentThread( java_vm
);
605 void start_android_device(void)
609 handles
[0] = CreateEventW( NULL
, TRUE
, FALSE
, NULL
);
610 handles
[1] = thread
= CreateThread( NULL
, 0, device_thread
, handles
[0], 0, NULL
);
611 WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
);
612 CloseHandle( handles
[0] );
616 /* Client-side ioctl support */
619 static int android_ioctl( enum android_ioctl code
, void *in
, DWORD in_size
, void *out
, DWORD
*out_size
)
621 static const WCHAR deviceW
[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
622 static HANDLE device
;
623 IO_STATUS_BLOCK iosb
;
628 HANDLE file
= CreateFileW( deviceW
, GENERIC_READ
,
629 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, 0 );
630 if (file
== INVALID_HANDLE_VALUE
) return -ENOENT
;
631 if (InterlockedCompareExchangePointer( &device
, file
, NULL
)) CloseHandle( file
);
634 status
= NtDeviceIoControlFile( device
, NULL
, NULL
, NULL
, &iosb
, ANDROID_IOCTL(code
),
635 in
, in_size
, out
, out_size
? *out_size
: 0 );
636 if (status
== STATUS_FILE_DELETED
)
638 WARN( "parent process is gone\n" );
641 if (out_size
) *out_size
= iosb
.Information
;
642 return status_to_android_error( status
);
645 static void win_incRef( struct android_native_base_t
*base
)
647 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)base
;
648 InterlockedIncrement( &win
->ref
);
651 static void win_decRef( struct android_native_base_t
*base
)
653 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)base
;
654 InterlockedDecrement( &win
->ref
);
657 static int dequeueBuffer( struct ANativeWindow
*window
, struct ANativeWindowBuffer
**buffer
, int *fence
)
662 static int cancelBuffer( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
, int fence
)
667 static int queueBuffer( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
, int fence
)
672 static int dequeueBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
**buffer
)
677 static int cancelBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
)
682 static int lockBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
)
684 return 0; /* nothing to do */
687 static int queueBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
)
692 static int setSwapInterval( struct ANativeWindow
*window
, int interval
)
694 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
695 struct ioctl_android_set_swap_interval swap
;
697 TRACE( "hwnd %p interval %d\n", win
->hwnd
, interval
);
698 swap
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
699 swap
.interval
= interval
;
700 return android_ioctl( IOCTL_SET_SWAP_INT
, &swap
, sizeof(swap
), NULL
, NULL
);
703 static int query( const ANativeWindow
*window
, int what
, int *value
)
705 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
706 struct ioctl_android_query query
;
707 DWORD size
= sizeof( query
);
710 query
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
712 ret
= android_ioctl( IOCTL_QUERY
, &query
, sizeof(query
), &query
, &size
);
713 TRACE( "hwnd %p what %d got %d -> %p\n", win
->hwnd
, what
, query
.value
, value
);
714 if (!ret
) *value
= query
.value
;
718 static int perform( ANativeWindow
*window
, int operation
, ... )
720 static const char * const names
[] =
722 "SET_USAGE", "CONNECT", "DISCONNECT", "SET_CROP", "SET_BUFFER_COUNT", "SET_BUFFERS_GEOMETRY",
723 "SET_BUFFERS_TRANSFORM", "SET_BUFFERS_TIMESTAMP", "SET_BUFFERS_DIMENSIONS", "SET_BUFFERS_FORMAT",
724 "SET_SCALING_MODE", "LOCK", "UNLOCK_AND_POST", "API_CONNECT", "API_DISCONNECT",
725 "SET_BUFFERS_USER_DIMENSIONS", "SET_POST_TRANSFORM_CROP"
728 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
729 struct ioctl_android_perform perf
;
732 perf
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
733 perf
.operation
= operation
;
734 memset( perf
.args
, 0, sizeof(perf
.args
) );
736 va_start( args
, operation
);
739 case NATIVE_WINDOW_SET_USAGE
:
740 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
:
741 case NATIVE_WINDOW_SET_BUFFERS_FORMAT
:
742 case NATIVE_WINDOW_SET_SCALING_MODE
:
743 case NATIVE_WINDOW_API_CONNECT
:
744 case NATIVE_WINDOW_API_DISCONNECT
:
745 perf
.args
[0] = va_arg( args
, int );
746 TRACE( "hwnd %p %s arg %d\n", win
->hwnd
, names
[operation
], perf
.args
[0] );
748 case NATIVE_WINDOW_SET_BUFFER_COUNT
:
749 perf
.args
[0] = va_arg( args
, size_t );
750 TRACE( "hwnd %p %s count %d\n", win
->hwnd
, names
[operation
], perf
.args
[0] );
752 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
:
753 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS
:
754 perf
.args
[0] = va_arg( args
, int );
755 perf
.args
[1] = va_arg( args
, int );
756 TRACE( "hwnd %p %s arg %dx%d\n", win
->hwnd
, names
[operation
], perf
.args
[0], perf
.args
[1] );
758 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
:
759 perf
.args
[0] = va_arg( args
, int );
760 perf
.args
[1] = va_arg( args
, int );
761 perf
.args
[2] = va_arg( args
, int );
762 TRACE( "hwnd %p %s arg %dx%d %d\n", win
->hwnd
, names
[operation
],
763 perf
.args
[0], perf
.args
[1], perf
.args
[2] );
765 case NATIVE_WINDOW_SET_CROP
:
767 android_native_rect_t
*rect
= va_arg( args
, android_native_rect_t
* );
768 perf
.args
[0] = rect
->left
;
769 perf
.args
[1] = rect
->top
;
770 perf
.args
[2] = rect
->right
;
771 perf
.args
[3] = rect
->bottom
;
772 TRACE( "hwnd %p %s rect %d,%d-%d,%d\n", win
->hwnd
, names
[operation
],
773 perf
.args
[0], perf
.args
[1], perf
.args
[2], perf
.args
[3] );
776 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
:
778 int64_t timestamp
= va_arg( args
, int64_t );
779 perf
.args
[0] = timestamp
;
780 perf
.args
[1] = timestamp
>> 32;
781 TRACE( "hwnd %p %s arg %08x%08x\n", win
->hwnd
, names
[operation
], perf
.args
[1], perf
.args
[0] );
784 case NATIVE_WINDOW_LOCK
:
785 case NATIVE_WINDOW_UNLOCK_AND_POST
:
786 case NATIVE_WINDOW_CONNECT
:
787 case NATIVE_WINDOW_DISCONNECT
:
788 TRACE( "hwnd %p %s\n", win
->hwnd
, names
[operation
] );
790 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP
:
792 FIXME( "unsupported perform hwnd %p op %d %s\n", win
->hwnd
, operation
,
793 operation
< sizeof(names
)/sizeof(names
[0]) ? names
[operation
] : "???" );
797 return android_ioctl( IOCTL_PERFORM
, &perf
, sizeof(perf
), NULL
, NULL
);
800 struct ANativeWindow
*create_ioctl_window( HWND hwnd
)
802 struct ioctl_android_create_window req
;
803 struct native_win_wrapper
*win
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*win
) );
804 HWND parent
= GetAncestor( hwnd
, GA_PARENT
);
806 if (!win
) return NULL
;
808 win
->win
.common
.magic
= ANDROID_NATIVE_WINDOW_MAGIC
;
809 win
->win
.common
.version
= sizeof(ANativeWindow
);
810 win
->win
.common
.incRef
= win_incRef
;
811 win
->win
.common
.decRef
= win_decRef
;
812 win
->win
.setSwapInterval
= setSwapInterval
;
813 win
->win
.dequeueBuffer_DEPRECATED
= dequeueBuffer_DEPRECATED
;
814 win
->win
.lockBuffer_DEPRECATED
= lockBuffer_DEPRECATED
;
815 win
->win
.queueBuffer_DEPRECATED
= queueBuffer_DEPRECATED
;
816 win
->win
.query
= query
;
817 win
->win
.perform
= perform
;
818 win
->win
.cancelBuffer_DEPRECATED
= cancelBuffer_DEPRECATED
;
819 win
->win
.dequeueBuffer
= dequeueBuffer
;
820 win
->win
.queueBuffer
= queueBuffer
;
821 win
->win
.cancelBuffer
= cancelBuffer
;
824 TRACE( "-> %p %p\n", win
, win
->hwnd
);
826 req
.hdr
.hwnd
= HandleToLong( hwnd
);
827 req
.parent
= parent
== GetDesktopWindow() ? 0 : HandleToLong( parent
);
828 android_ioctl( IOCTL_CREATE_WINDOW
, &req
, sizeof(req
), NULL
, NULL
);
833 struct ANativeWindow
*grab_ioctl_window( struct ANativeWindow
*window
)
835 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
836 InterlockedIncrement( &win
->ref
);
840 void release_ioctl_window( struct ANativeWindow
*window
)
842 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
844 if (InterlockedDecrement( &win
->ref
) > 0) return;
846 TRACE( "%p %p\n", win
, win
->hwnd
);
848 destroy_ioctl_window( win
->hwnd
);
849 HeapFree( GetProcessHeap(), 0, win
);
852 void destroy_ioctl_window( HWND hwnd
)
854 struct ioctl_android_destroy_window req
;
856 req
.hdr
.hwnd
= HandleToLong( hwnd
);
857 android_ioctl( IOCTL_DESTROY_WINDOW
, &req
, sizeof(req
), NULL
, NULL
);
860 int ioctl_window_pos_changed( HWND hwnd
, const RECT
*window_rect
, const RECT
*client_rect
,
861 const RECT
*visible_rect
, UINT style
, UINT flags
, HWND after
, HWND owner
)
863 struct ioctl_android_window_pos_changed req
;
865 req
.hdr
.hwnd
= HandleToLong( hwnd
);
866 req
.window_rect
= *window_rect
;
867 req
.client_rect
= *client_rect
;
868 req
.visible_rect
= *visible_rect
;
871 req
.after
= HandleToLong( after
);
872 req
.owner
= HandleToLong( owner
);
873 return android_ioctl( IOCTL_WINDOW_POS_CHANGED
, &req
, sizeof(req
), NULL
, NULL
);