wineandroid: Forward native window setSwapInterval() calls to the desktop process.
[wine.git] / dlls / wineandroid.drv / device.c
blob344e0c38bc567310479ebcdee18c5c18811e68aa
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <sys/ioctl.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winternl.h"
38 #include "winioctl.h"
39 #include "ddk/wdm.h"
40 #include "android.h"
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;
48 static HANDLE thread;
49 static JNIEnv *jni_env;
51 #define ANDROIDCONTROLTYPE ((ULONG)'A')
52 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
54 enum android_ioctl
56 IOCTL_CREATE_WINDOW,
57 IOCTL_DESTROY_WINDOW,
58 IOCTL_WINDOW_POS_CHANGED,
59 IOCTL_QUERY,
60 IOCTL_PERFORM,
61 IOCTL_SET_SWAP_INT,
62 NB_IOCTLS
65 /* data about the native window in the context of the Java process */
66 struct native_win_data
68 struct ANativeWindow *parent;
69 HWND hwnd;
70 int api;
71 int buffer_format;
72 int swap_interval;
75 /* wrapper for a native window in the context of the client (non-Java) process */
76 struct native_win_wrapper
78 struct ANativeWindow win;
79 HWND hwnd;
80 LONG ref;
83 struct ioctl_header
85 int hwnd;
88 struct ioctl_android_create_window
90 struct ioctl_header hdr;
91 int parent;
94 struct ioctl_android_destroy_window
96 struct ioctl_header hdr;
99 struct ioctl_android_window_pos_changed
101 struct ioctl_header hdr;
102 RECT window_rect;
103 RECT client_rect;
104 RECT visible_rect;
105 int style;
106 int flags;
107 int after;
108 int owner;
111 struct ioctl_android_query
113 struct ioctl_header hdr;
114 int what;
115 int value;
118 struct ioctl_android_perform
120 struct ioctl_header hdr;
121 int operation;
122 int args[4];
125 struct ioctl_android_set_swap_interval
127 struct ioctl_header hdr;
128 int interval;
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 ); }
140 #else
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 )
149 return LOWORD(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 );
158 return NULL;
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];
185 if (data)
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;
191 data->hwnd = hwnd;
192 data->api = NATIVE_WINDOW_API_CPU;
193 data->buffer_format = PF_BGRA_8888;
194 data_map[idx] = data;
195 return 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 );
208 return;
211 release_native_window( data );
212 data->parent = win;
213 if (win)
215 wrap_java_call();
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 );
219 unwrap_java_call();
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 )
232 switch (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;
247 default:
248 FIXME( "unmapped error %d\n", err );
249 return STATUS_UNSUCCESSFUL;
253 static int status_to_android_error( NTSTATUS status )
255 switch (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;
271 default:
272 FIXME( "unmapped status %08x\n", status );
273 return -EINVAL;
277 static jobject load_java_method( jmethodID *method, const char *name, const char *args )
279 jobject object = wine_get_java_object();
281 if (!*method)
283 jclass class;
285 wrap_java_call();
286 class = (*jni_env)->GetObjectClass( jni_env, object );
287 *method = (*jni_env)->GetMethodID( jni_env, class, name, args );
288 unwrap_java_call();
289 if (!*method)
291 FIXME( "method %s not found\n", name );
292 return NULL;
295 return object;
298 static void create_desktop_window( HWND hwnd )
300 static jmethodID method;
301 jobject object;
303 if (!(object = load_java_method( &method, "createDesktopWindow", "(I)V" ))) return;
305 wrap_java_call();
306 (*jni_env)->CallVoidMethod( jni_env, object, method, HandleToLong( hwnd ));
307 unwrap_java_call();
310 static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
312 static jmethodID method;
313 jobject object;
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;
327 wrap_java_call();
328 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, pid );
329 unwrap_java_call();
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;
336 jobject object;
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;
348 wrap_java_call();
349 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
350 unwrap_java_call();
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;
358 jobject object;
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;
370 wrap_java_call();
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 );
375 unwrap_java_call();
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;
384 int ret;
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 );
393 wrap_java_call();
394 ret = parent->query( parent, res->what, &res->value );
395 unwrap_java_call();
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;
404 int ret = -ENOENT;
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:
414 wrap_java_call();
415 ret = parent->perform( parent, res->operation, res->args[0] );
416 unwrap_java_call();
417 if (!ret) win_data->buffer_format = res->args[0];
418 break;
419 case NATIVE_WINDOW_API_CONNECT:
420 wrap_java_call();
421 ret = parent->perform( parent, res->operation, res->args[0] );
422 unwrap_java_call();
423 if (!ret) win_data->api = res->args[0];
424 break;
425 case NATIVE_WINDOW_API_DISCONNECT:
426 wrap_java_call();
427 ret = parent->perform( parent, res->operation, res->args[0] );
428 unwrap_java_call();
429 if (!ret) win_data->api = 0;
430 break;
431 case NATIVE_WINDOW_SET_USAGE:
432 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
433 case NATIVE_WINDOW_SET_SCALING_MODE:
434 wrap_java_call();
435 ret = parent->perform( parent, res->operation, res->args[0] );
436 unwrap_java_call();
437 break;
438 case NATIVE_WINDOW_SET_BUFFER_COUNT:
439 wrap_java_call();
440 ret = parent->perform( parent, res->operation, (size_t)res->args[0] );
441 unwrap_java_call();
442 break;
443 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
444 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
445 wrap_java_call();
446 ret = parent->perform( parent, res->operation, res->args[0], res->args[1] );
447 unwrap_java_call();
448 break;
449 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
450 wrap_java_call();
451 ret = parent->perform( parent, res->operation, res->args[0], res->args[1], res->args[2] );
452 unwrap_java_call();
453 break;
454 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
455 wrap_java_call();
456 ret = parent->perform( parent, res->operation, res->args[0] | ((int64_t)res->args[1] << 32) );
457 unwrap_java_call();
458 break;
459 case NATIVE_WINDOW_CONNECT:
460 case NATIVE_WINDOW_DISCONNECT:
461 case NATIVE_WINDOW_UNLOCK_AND_POST:
462 wrap_java_call();
463 ret = parent->perform( parent, res->operation );
464 unwrap_java_call();
465 break;
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];
473 wrap_java_call();
474 ret = parent->perform( parent, res->operation, &rect );
475 unwrap_java_call();
476 break;
478 case NATIVE_WINDOW_LOCK:
479 default:
480 FIXME( "unsupported perform op %d\n", res->operation );
481 break;
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;
491 int ret;
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;
499 wrap_java_call();
500 ret = parent->setSwapInterval( parent, res->interval );
501 unwrap_java_call();
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;
536 else
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;
552 NTSTATUS status;
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;
569 NTSTATUS status;
570 JavaVM *java_vm;
571 DWORD ret;
573 TRACE( "starting process %x\n", GetCurrentProcessId() );
575 if (!(java_vm = wine_get_java_vm())) return 0; /* not running under Java */
577 #ifdef __i386__
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 );
583 #else
584 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
585 #endif
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 );
593 return 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 );
602 return ret;
605 void start_android_device(void)
607 HANDLE handles[2];
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;
624 NTSTATUS status;
626 if (!device)
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" );
639 ExitProcess( 1 );
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 )
659 return 0;
662 static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
664 return 0;
667 static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
669 return 0;
672 static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer )
674 return 0;
677 static int cancelBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
679 return 0;
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 )
689 return 0;
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 );
708 int ret;
710 query.hdr.hwnd = HandleToLong( win->hwnd );
711 query.what = what;
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;
715 return ret;
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;
730 va_list args;
732 perf.hdr.hwnd = HandleToLong( win->hwnd );
733 perf.operation = operation;
734 memset( perf.args, 0, sizeof(perf.args) );
736 va_start( args, operation );
737 switch (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] );
747 break;
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] );
751 break;
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] );
757 break;
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] );
764 break;
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] );
774 break;
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] );
782 break;
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] );
789 break;
790 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP:
791 default:
792 FIXME( "unsupported perform hwnd %p op %d %s\n", win->hwnd, operation,
793 operation < sizeof(names)/sizeof(names[0]) ? names[operation] : "???" );
794 break;
796 va_end( args );
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;
822 win->ref = 1;
823 win->hwnd = hwnd;
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 );
830 return &win->win;
833 struct ANativeWindow *grab_ioctl_window( struct ANativeWindow *window )
835 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
836 InterlockedIncrement( &win->ref );
837 return window;
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;
869 req.style = style;
870 req.flags = flags;
871 req.after = HandleToLong( after );
872 req.owner = HandleToLong( owner );
873 return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL );