windowscodecs: Implement IWICMetadataQueryReader::GetContainerFormat.
[wine.git] / dlls / wineandroid.drv / device.c
blob3829e69536947d3a393da25f3cff5b6e684edb69
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/server.h"
42 #include "wine/library.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(android);
47 #ifndef SYNC_IOC_WAIT
48 #define SYNC_IOC_WAIT _IOW('>', 0, __s32)
49 #endif
51 extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
52 static HANDLE stop_event;
53 static HANDLE thread;
54 static JNIEnv *jni_env;
55 static HWND capture_window;
57 #define ANDROIDCONTROLTYPE ((ULONG)'A')
58 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
60 enum android_ioctl
62 IOCTL_CREATE_WINDOW,
63 IOCTL_DESTROY_WINDOW,
64 IOCTL_WINDOW_POS_CHANGED,
65 IOCTL_SET_WINDOW_PARENT,
66 IOCTL_DEQUEUE_BUFFER,
67 IOCTL_QUEUE_BUFFER,
68 IOCTL_CANCEL_BUFFER,
69 IOCTL_QUERY,
70 IOCTL_PERFORM,
71 IOCTL_SET_SWAP_INT,
72 IOCTL_SET_CAPTURE,
73 NB_IOCTLS
76 #define NB_CACHED_BUFFERS 4
78 struct native_buffer_wrapper;
80 /* buffer for storing a variable-size native handle inside an ioctl structure */
81 union native_handle_buffer
83 native_handle_t handle;
84 int space[256];
87 /* data about the native window in the context of the Java process */
88 struct native_win_data
90 struct ANativeWindow *parent;
91 struct ANativeWindowBuffer *buffers[NB_CACHED_BUFFERS];
92 void *mappings[NB_CACHED_BUFFERS];
93 HWND hwnd;
94 int api;
95 int buffer_format;
96 int swap_interval;
97 int buffer_lru[NB_CACHED_BUFFERS];
100 /* wrapper for a native window in the context of the client (non-Java) process */
101 struct native_win_wrapper
103 struct ANativeWindow win;
104 struct native_buffer_wrapper *buffers[NB_CACHED_BUFFERS];
105 struct ANativeWindowBuffer *locked_buffer;
106 HWND hwnd;
107 LONG ref;
110 /* wrapper for a native buffer in the context of the client (non-Java) process */
111 struct native_buffer_wrapper
113 struct ANativeWindowBuffer buffer;
114 LONG ref;
115 HWND hwnd;
116 void *bits;
117 int buffer_id;
118 union native_handle_buffer native_handle;
121 struct ioctl_header
123 int hwnd;
126 struct ioctl_android_create_window
128 struct ioctl_header hdr;
129 int parent;
132 struct ioctl_android_destroy_window
134 struct ioctl_header hdr;
137 struct ioctl_android_window_pos_changed
139 struct ioctl_header hdr;
140 RECT window_rect;
141 RECT client_rect;
142 RECT visible_rect;
143 int style;
144 int flags;
145 int after;
146 int owner;
149 struct ioctl_android_dequeueBuffer
151 struct ioctl_header hdr;
152 int win32;
153 int width;
154 int height;
155 int stride;
156 int format;
157 int usage;
158 int buffer_id;
159 union native_handle_buffer native_handle;
162 struct ioctl_android_queueBuffer
164 struct ioctl_header hdr;
165 int buffer_id;
168 struct ioctl_android_cancelBuffer
170 struct ioctl_header hdr;
171 int buffer_id;
174 struct ioctl_android_query
176 struct ioctl_header hdr;
177 int what;
178 int value;
181 struct ioctl_android_perform
183 struct ioctl_header hdr;
184 int operation;
185 int args[4];
188 struct ioctl_android_set_swap_interval
190 struct ioctl_header hdr;
191 int interval;
194 struct ioctl_android_set_window_parent
196 struct ioctl_header hdr;
197 int parent;
200 struct ioctl_android_set_capture
202 struct ioctl_header hdr;
205 static inline BOOL is_in_desktop_process(void)
207 return thread != NULL;
210 static inline DWORD current_client_id(void)
212 return HandleToUlong( PsGetCurrentProcessId() );
215 static inline BOOL is_client_in_process(void)
217 return current_client_id() == GetCurrentProcessId();
220 #ifdef __i386__ /* the Java VM uses %fs for its own purposes, so we need to wrap the calls */
221 static WORD orig_fs, java_fs;
222 static inline void wrap_java_call(void) { wine_set_fs( java_fs ); }
223 static inline void unwrap_java_call(void) { wine_set_fs( orig_fs ); }
224 #else
225 static inline void wrap_java_call(void) { }
226 static inline void unwrap_java_call(void) { }
227 #endif /* __i386__ */
229 static struct native_win_data *data_map[65536];
231 static unsigned int data_map_idx( HWND hwnd )
233 return LOWORD(hwnd);
236 static struct native_win_data *get_native_win_data( HWND hwnd )
238 struct native_win_data *data = data_map[data_map_idx( hwnd )];
240 if (data && data->hwnd == hwnd) return data;
241 WARN( "unknown win %p\n", hwnd );
242 return NULL;
245 static struct native_win_data *get_ioctl_native_win_data( const struct ioctl_header *hdr )
247 return get_native_win_data( LongToHandle(hdr->hwnd) );
250 static void wait_fence_and_close( int fence )
252 __s32 timeout = 1000; /* FIXME: should be -1 for infinite timeout */
254 if (fence == -1) return;
255 ioctl( fence, SYNC_IOC_WAIT, &timeout );
256 close( fence );
259 static int duplicate_fd( HANDLE client, int fd )
261 HANDLE handle, ret = 0;
263 if (!wine_server_fd_to_handle( dup(fd), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
264 DuplicateHandle( GetCurrentProcess(), handle, client, &ret,
265 DUPLICATE_SAME_ACCESS, FALSE, DUP_HANDLE_CLOSE_SOURCE );
267 if (!ret) return -1;
268 return HandleToLong( ret );
271 static int map_native_handle( union native_handle_buffer *dest, const native_handle_t *src,
272 HANDLE mapping, HANDLE client )
274 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
275 int i;
277 if (mapping) /* only duplicate the mapping handle */
279 HANDLE ret = 0;
280 if (!DuplicateHandle( GetCurrentProcess(), mapping, client, &ret,
281 DUPLICATE_SAME_ACCESS, FALSE, DUP_HANDLE_CLOSE_SOURCE ))
282 return -ENOSPC;
283 dest->handle.numFds = 0;
284 dest->handle.numInts = 1;
285 dest->handle.data[0] = HandleToLong( ret );
286 return 0;
288 if (is_client_in_process()) /* transfer the actual handle pointer */
290 dest->handle.numFds = 0;
291 dest->handle.numInts = sizeof(src) / sizeof(int);
292 memcpy( dest->handle.data, &src, sizeof(src) );
293 return 0;
295 if (size > sizeof(*dest)) return -ENOSPC;
296 memcpy( dest, src, size );
297 /* transfer file descriptors to the client process */
298 for (i = 0; i < dest->handle.numFds; i++)
299 dest->handle.data[i] = duplicate_fd( client, src->data[i] );
300 return 0;
303 static native_handle_t *unmap_native_handle( const native_handle_t *src )
305 const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
306 native_handle_t *dest;
307 int i;
309 if (!is_in_desktop_process())
311 dest = HeapAlloc( GetProcessHeap(), 0, size );
312 memcpy( dest, src, size );
313 /* fetch file descriptors passed from the server process */
314 for (i = 0; i < dest->numFds; i++)
315 wine_server_handle_to_fd( LongToHandle(src->data[i]), GENERIC_READ | SYNCHRONIZE,
316 &dest->data[i], NULL );
318 else memcpy( &dest, src->data, sizeof(dest) );
319 return dest;
322 static void close_native_handle( native_handle_t *handle )
324 int i;
326 for (i = 0; i < handle->numFds; i++) close( handle->data[i] );
327 HeapFree( GetProcessHeap(), 0, handle );
330 /* insert a buffer index at the head of the LRU list */
331 static void insert_buffer_lru( struct native_win_data *win, int index )
333 unsigned int i;
335 for (i = 0; i < NB_CACHED_BUFFERS; i++)
337 if (win->buffer_lru[i] == index) break;
338 if (win->buffer_lru[i] == -1) break;
341 assert( i < NB_CACHED_BUFFERS );
342 memmove( win->buffer_lru + 1, win->buffer_lru, i * sizeof(win->buffer_lru[0]) );
343 win->buffer_lru[0] = index;
346 static int register_buffer( struct native_win_data *win, struct ANativeWindowBuffer *buffer,
347 HANDLE *mapping, int *is_new )
349 unsigned int i;
351 *is_new = 0;
352 for (i = 0; i < NB_CACHED_BUFFERS; i++)
354 if (win->buffers[i] == buffer) goto done;
355 if (!win->buffers[i]) break;
358 if (i == NB_CACHED_BUFFERS)
360 /* reuse the least recently used buffer */
361 i = win->buffer_lru[NB_CACHED_BUFFERS - 1];
362 assert( i < NB_CACHED_BUFFERS );
364 TRACE( "%p %p evicting buffer %p id %d from cache\n",
365 win->hwnd, win->parent, win->buffers[i], i );
366 win->buffers[i]->common.decRef( &win->buffers[i]->common );
367 if (win->mappings[i]) UnmapViewOfFile( win->mappings[i] );
370 win->buffers[i] = buffer;
371 win->mappings[i] = NULL;
373 if (mapping)
375 *mapping = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
376 buffer->stride * buffer->height * 4, NULL );
377 win->mappings[i] = MapViewOfFile( *mapping, FILE_MAP_READ, 0, 0, 0 );
379 buffer->common.incRef( &buffer->common );
380 *is_new = 1;
381 TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i );
383 done:
384 insert_buffer_lru( win, i );
385 return i;
388 static struct ANativeWindowBuffer *get_registered_buffer( struct native_win_data *win, int id )
390 if (id < 0 || id >= NB_CACHED_BUFFERS || !win->buffers[id])
392 ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent );
393 return NULL;
395 return win->buffers[id];
398 static void release_native_window( struct native_win_data *data )
400 unsigned int i;
402 if (data->parent) pANativeWindow_release( data->parent );
403 for (i = 0; i < NB_CACHED_BUFFERS; i++)
405 if (data->buffers[i]) data->buffers[i]->common.decRef( &data->buffers[i]->common );
406 if (data->mappings[i]) UnmapViewOfFile( data->mappings[i] );
407 data->buffer_lru[i] = -1;
409 memset( data->buffers, 0, sizeof(data->buffers) );
410 memset( data->mappings, 0, sizeof(data->mappings) );
413 static void free_native_win_data( struct native_win_data *data )
415 unsigned int idx = data_map_idx( data->hwnd );
417 InterlockedCompareExchangePointer( (void **)&capture_window, 0, data->hwnd );
418 release_native_window( data );
419 HeapFree( GetProcessHeap(), 0, data );
420 data_map[idx] = NULL;
423 static struct native_win_data *create_native_win_data( HWND hwnd )
425 unsigned int i, idx = data_map_idx( hwnd );
426 struct native_win_data *data = data_map[idx];
428 if (data)
430 WARN( "data for %p not freed correctly\n", data->hwnd );
431 free_native_win_data( data );
433 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return NULL;
434 data->hwnd = hwnd;
435 data->api = NATIVE_WINDOW_API_CPU;
436 data->buffer_format = PF_BGRA_8888;
437 data_map[idx] = data;
438 for (i = 0; i < NB_CACHED_BUFFERS; i++) data->buffer_lru[i] = -1;
439 return data;
442 static void CALLBACK register_native_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
444 HWND hwnd = (HWND)arg1;
445 struct ANativeWindow *win = (struct ANativeWindow *)arg2;
446 struct native_win_data *data = get_native_win_data( hwnd );
448 if (!data || data->parent == win)
450 if (win) pANativeWindow_release( win );
451 if (data && win) PostMessageW( hwnd, WM_ANDROID_REFRESH, 0, 0 );
452 TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win );
453 return;
456 release_native_window( data );
457 data->parent = win;
458 if (win)
460 wrap_java_call();
461 if (data->api) win->perform( win, NATIVE_WINDOW_API_CONNECT, data->api );
462 win->perform( win, NATIVE_WINDOW_SET_BUFFERS_FORMAT, data->buffer_format );
463 win->setSwapInterval( win, data->swap_interval );
464 unwrap_java_call();
465 PostMessageW( hwnd, WM_ANDROID_REFRESH, 0, 0 );
467 TRACE( "%p -> %p win %p\n", hwnd, data, win );
470 /* register a native window received from the Java side for use in ioctls */
471 void register_native_window( HWND hwnd, struct ANativeWindow *win )
473 NtQueueApcThread( thread, register_native_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, 0 );
476 /* get the capture window stored in the desktop process */
477 HWND get_capture_window(void)
479 return capture_window;
482 static NTSTATUS android_error_to_status( int err )
484 switch (err)
486 case 0: return STATUS_SUCCESS;
487 case -ENOMEM: return STATUS_NO_MEMORY;
488 case -ENOSYS: return STATUS_NOT_SUPPORTED;
489 case -EINVAL: return STATUS_INVALID_PARAMETER;
490 case -ENOENT: return STATUS_INVALID_HANDLE;
491 case -EPERM: return STATUS_ACCESS_DENIED;
492 case -ENODEV: return STATUS_NO_SUCH_DEVICE;
493 case -EEXIST: return STATUS_DUPLICATE_NAME;
494 case -EPIPE: return STATUS_PIPE_DISCONNECTED;
495 case -ENODATA: return STATUS_NO_MORE_FILES;
496 case -ETIMEDOUT: return STATUS_IO_TIMEOUT;
497 case -EBADMSG: return STATUS_INVALID_DEVICE_REQUEST;
498 case -EWOULDBLOCK: return STATUS_DEVICE_NOT_READY;
499 default:
500 FIXME( "unmapped error %d\n", err );
501 return STATUS_UNSUCCESSFUL;
505 static int status_to_android_error( NTSTATUS status )
507 switch (status)
509 case STATUS_SUCCESS: return 0;
510 case STATUS_NO_MEMORY: return -ENOMEM;
511 case STATUS_NOT_SUPPORTED: return -ENOSYS;
512 case STATUS_INVALID_PARAMETER: return -EINVAL;
513 case STATUS_BUFFER_OVERFLOW: return -EINVAL;
514 case STATUS_INVALID_HANDLE: return -ENOENT;
515 case STATUS_ACCESS_DENIED: return -EPERM;
516 case STATUS_NO_SUCH_DEVICE: return -ENODEV;
517 case STATUS_DUPLICATE_NAME: return -EEXIST;
518 case STATUS_PIPE_DISCONNECTED: return -EPIPE;
519 case STATUS_NO_MORE_FILES: return -ENODATA;
520 case STATUS_IO_TIMEOUT: return -ETIMEDOUT;
521 case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG;
522 case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK;
523 default:
524 FIXME( "unmapped status %08x\n", status );
525 return -EINVAL;
529 static jobject load_java_method( jmethodID *method, const char *name, const char *args )
531 jobject object = wine_get_java_object();
533 if (!*method)
535 jclass class;
537 wrap_java_call();
538 class = (*jni_env)->GetObjectClass( jni_env, object );
539 *method = (*jni_env)->GetMethodID( jni_env, class, name, args );
540 unwrap_java_call();
541 if (!*method)
543 FIXME( "method %s not found\n", name );
544 return NULL;
547 return object;
550 static void create_desktop_window( HWND hwnd )
552 static jmethodID method;
553 jobject object;
555 if (!(object = load_java_method( &method, "createDesktopWindow", "(I)V" ))) return;
557 wrap_java_call();
558 (*jni_env)->CallVoidMethod( jni_env, object, method, HandleToLong( hwnd ));
559 unwrap_java_call();
562 static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
564 static jmethodID method;
565 jobject object;
566 struct ioctl_android_create_window *res = data;
567 struct native_win_data *win_data;
568 DWORD pid = current_client_id();
570 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
572 if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd) )))
573 return STATUS_NO_MEMORY;
575 TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
577 if (!(object = load_java_method( &method, "createWindow", "(III)V" ))) return STATUS_NOT_SUPPORTED;
579 wrap_java_call();
580 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, pid );
581 unwrap_java_call();
582 return STATUS_SUCCESS;
585 static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
587 static jmethodID method;
588 jobject object;
589 struct ioctl_android_destroy_window *res = data;
590 struct native_win_data *win_data;
592 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
594 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
596 TRACE( "hwnd %08x\n", res->hdr.hwnd );
598 if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED;
600 wrap_java_call();
601 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
602 unwrap_java_call();
603 free_native_win_data( win_data );
604 return STATUS_SUCCESS;
607 static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
609 static jmethodID method;
610 jobject object;
611 struct ioctl_android_window_pos_changed *res = data;
613 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
615 TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
616 res->hdr.hwnd, wine_dbgstr_rect(&res->window_rect), wine_dbgstr_rect(&res->client_rect),
617 wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner );
619 if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
620 return STATUS_NOT_SUPPORTED;
622 wrap_java_call();
623 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style,
624 res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom,
625 res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom,
626 res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom );
627 unwrap_java_call();
628 return STATUS_SUCCESS;
631 static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
633 struct ANativeWindow *parent;
634 struct ioctl_android_dequeueBuffer *res = data;
635 struct native_win_data *win_data;
636 struct ANativeWindowBuffer *buffer;
637 int fence, ret, is_new;
639 if (out_size < sizeof( *res )) return STATUS_BUFFER_OVERFLOW;
641 if (in_size < offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
642 return STATUS_INVALID_PARAMETER;
644 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
645 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
647 *ret_size = offsetof( struct ioctl_android_dequeueBuffer, native_handle );
648 wrap_java_call();
649 ret = parent->dequeueBuffer( parent, &buffer, &fence );
650 unwrap_java_call();
651 if (!ret)
653 HANDLE mapping = 0;
655 TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence );
656 res->width = buffer->width;
657 res->height = buffer->height;
658 res->stride = buffer->stride;
659 res->format = buffer->format;
660 res->usage = buffer->usage;
661 res->buffer_id = register_buffer( win_data, buffer, res->win32 ? &mapping : NULL, &is_new );
662 if (is_new)
664 HANDLE process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, current_client_id() );
665 map_native_handle( &res->native_handle, buffer->handle, mapping, process );
666 CloseHandle( process );
667 *ret_size = sizeof( *res );
669 wait_fence_and_close( fence );
670 return STATUS_SUCCESS;
672 ERR( "%08x failed %d\n", res->hdr.hwnd, ret );
673 return android_error_to_status( ret );
676 static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
678 struct ioctl_android_cancelBuffer *res = data;
679 struct ANativeWindow *parent;
680 struct ANativeWindowBuffer *buffer;
681 struct native_win_data *win_data;
682 int ret;
684 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
686 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
687 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
689 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
691 TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer );
692 wrap_java_call();
693 ret = parent->cancelBuffer( parent, buffer, -1 );
694 unwrap_java_call();
695 return android_error_to_status( ret );
698 static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
700 struct ioctl_android_queueBuffer *res = data;
701 struct ANativeWindow *parent;
702 struct ANativeWindowBuffer *buffer;
703 struct native_win_data *win_data;
704 int ret;
706 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
708 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
709 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
711 if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
713 TRACE( "%08x buffer %p mapping %p\n", res->hdr.hwnd, buffer, win_data->mappings[res->buffer_id] );
714 if (win_data->mappings[res->buffer_id])
716 void *bits;
717 int ret = gralloc_module->lock( gralloc_module, buffer->handle,
718 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
719 0, 0, buffer->width, buffer->height, &bits );
720 if (ret) return android_error_to_status( ret );
721 memcpy( bits, win_data->mappings[res->buffer_id], buffer->stride * buffer->height * 4 );
722 gralloc_module->unlock( gralloc_module, buffer->handle );
724 wrap_java_call();
725 ret = parent->queueBuffer( parent, buffer, -1 );
726 unwrap_java_call();
727 return android_error_to_status( ret );
730 static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
732 struct ioctl_android_query *res = data;
733 struct ANativeWindow *parent;
734 struct native_win_data *win_data;
735 int ret;
737 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
738 if (out_size < sizeof(*res)) return STATUS_BUFFER_OVERFLOW;
740 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
741 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
743 *ret_size = sizeof( *res );
744 wrap_java_call();
745 ret = parent->query( parent, res->what, &res->value );
746 unwrap_java_call();
747 return android_error_to_status( ret );
750 static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
752 struct ioctl_android_perform *res = data;
753 struct ANativeWindow *parent;
754 struct native_win_data *win_data;
755 int ret = -ENOENT;
757 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
759 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
760 if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
762 switch (res->operation)
764 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
765 wrap_java_call();
766 ret = parent->perform( parent, res->operation, res->args[0] );
767 unwrap_java_call();
768 if (!ret) win_data->buffer_format = res->args[0];
769 break;
770 case NATIVE_WINDOW_API_CONNECT:
771 wrap_java_call();
772 ret = parent->perform( parent, res->operation, res->args[0] );
773 unwrap_java_call();
774 if (!ret) win_data->api = res->args[0];
775 break;
776 case NATIVE_WINDOW_API_DISCONNECT:
777 wrap_java_call();
778 ret = parent->perform( parent, res->operation, res->args[0] );
779 unwrap_java_call();
780 if (!ret) win_data->api = 0;
781 break;
782 case NATIVE_WINDOW_SET_USAGE:
783 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
784 case NATIVE_WINDOW_SET_SCALING_MODE:
785 wrap_java_call();
786 ret = parent->perform( parent, res->operation, res->args[0] );
787 unwrap_java_call();
788 break;
789 case NATIVE_WINDOW_SET_BUFFER_COUNT:
790 wrap_java_call();
791 ret = parent->perform( parent, res->operation, (size_t)res->args[0] );
792 unwrap_java_call();
793 break;
794 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
795 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
796 wrap_java_call();
797 ret = parent->perform( parent, res->operation, res->args[0], res->args[1] );
798 unwrap_java_call();
799 break;
800 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
801 wrap_java_call();
802 ret = parent->perform( parent, res->operation, res->args[0], res->args[1], res->args[2] );
803 unwrap_java_call();
804 break;
805 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
806 wrap_java_call();
807 ret = parent->perform( parent, res->operation, res->args[0] | ((int64_t)res->args[1] << 32) );
808 unwrap_java_call();
809 break;
810 case NATIVE_WINDOW_CONNECT:
811 case NATIVE_WINDOW_DISCONNECT:
812 case NATIVE_WINDOW_UNLOCK_AND_POST:
813 wrap_java_call();
814 ret = parent->perform( parent, res->operation );
815 unwrap_java_call();
816 break;
817 case NATIVE_WINDOW_SET_CROP:
819 android_native_rect_t rect;
820 rect.left = res->args[0];
821 rect.top = res->args[1];
822 rect.right = res->args[2];
823 rect.bottom = res->args[3];
824 wrap_java_call();
825 ret = parent->perform( parent, res->operation, &rect );
826 unwrap_java_call();
827 break;
829 case NATIVE_WINDOW_LOCK:
830 default:
831 FIXME( "unsupported perform op %d\n", res->operation );
832 break;
834 return android_error_to_status( ret );
837 static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
839 struct ioctl_android_set_swap_interval *res = data;
840 struct ANativeWindow *parent;
841 struct native_win_data *win_data;
842 int ret;
844 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
846 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
847 win_data->swap_interval = res->interval;
849 if (!(parent = win_data->parent)) return STATUS_SUCCESS;
850 wrap_java_call();
851 ret = parent->setSwapInterval( parent, res->interval );
852 unwrap_java_call();
853 return android_error_to_status( ret );
856 static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
858 static jmethodID method;
859 jobject object;
860 struct ioctl_android_set_window_parent *res = data;
861 struct native_win_data *win_data;
862 DWORD pid = current_client_id();
864 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
866 if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
868 TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
870 if (!(object = load_java_method( &method, "setParent", "(III)V" ))) return STATUS_NOT_SUPPORTED;
872 wrap_java_call();
873 (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, pid );
874 unwrap_java_call();
875 return STATUS_SUCCESS;
878 static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
880 struct ioctl_android_set_capture *res = data;
882 if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
884 if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return STATUS_INVALID_HANDLE;
886 TRACE( "hwnd %08x\n", res->hdr.hwnd );
888 InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd ));
889 return STATUS_SUCCESS;
892 typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
893 static const ioctl_func ioctl_funcs[] =
895 createWindow_ioctl, /* IOCTL_CREATE_WINDOW */
896 destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */
897 windowPosChanged_ioctl, /* IOCTL_WINDOW_POS_CHANGED */
898 setWindowParent_ioctl, /* IOCTL_SET_WINDOW_PARENT */
899 dequeueBuffer_ioctl, /* IOCTL_DEQUEUE_BUFFER */
900 queueBuffer_ioctl, /* IOCTL_QUEUE_BUFFER */
901 cancelBuffer_ioctl, /* IOCTL_CANCEL_BUFFER */
902 query_ioctl, /* IOCTL_QUERY */
903 perform_ioctl, /* IOCTL_PERFORM */
904 setSwapInterval_ioctl, /* IOCTL_SET_SWAP_INT */
905 setCapture_ioctl, /* IOCTL_SET_CAPTURE */
908 static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
910 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
911 DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2;
913 if (code < NB_IOCTLS)
915 struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer;
916 DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength;
917 ioctl_func func = ioctl_funcs[code];
919 if (in_size >= sizeof(*header))
921 irp->IoStatus.Information = 0;
922 irp->IoStatus.u.Status = func( irp->AssociatedIrp.SystemBuffer, in_size,
923 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
924 &irp->IoStatus.Information );
926 else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
928 else
930 FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
931 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
933 IoCompleteRequest( irp, IO_NO_INCREMENT );
934 return STATUS_SUCCESS;
937 static NTSTATUS CALLBACK init_android_driver( DRIVER_OBJECT *driver, UNICODE_STRING *name )
939 static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
940 static const WCHAR device_linkW[] = {'\\','?','?','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
942 UNICODE_STRING nameW, linkW;
943 DEVICE_OBJECT *device;
944 NTSTATUS status;
946 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctl_callback;
948 RtlInitUnicodeString( &nameW, device_nameW );
949 RtlInitUnicodeString( &linkW, device_linkW );
951 if ((status = IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ))) return status;
952 return IoCreateSymbolicLink( &linkW, &nameW );
955 static DWORD CALLBACK device_thread( void *arg )
957 static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
959 HANDLE start_event = arg;
960 UNICODE_STRING nameW;
961 NTSTATUS status;
962 JavaVM *java_vm;
963 DWORD ret;
965 TRACE( "starting process %x\n", GetCurrentProcessId() );
967 if (!(java_vm = wine_get_java_vm())) return 0; /* not running under Java */
969 #ifdef __i386__
970 orig_fs = wine_get_fs();
971 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
972 java_fs = wine_get_fs();
973 wine_set_fs( orig_fs );
974 if (java_fs != orig_fs) TRACE( "%%fs changed from %04x to %04x by Java VM\n", orig_fs, java_fs );
975 #else
976 (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
977 #endif
979 create_desktop_window( GetDesktopWindow() );
981 RtlInitUnicodeString( &nameW, driver_nameW );
982 if ((status = IoCreateDriver( &nameW, init_android_driver )))
984 FIXME( "failed to create driver error %x\n", status );
985 return status;
988 stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
989 SetEvent( start_event );
991 ret = wine_ntoskrnl_main_loop( stop_event );
993 (*java_vm)->DetachCurrentThread( java_vm );
994 return ret;
997 void start_android_device(void)
999 HANDLE handles[2];
1001 handles[0] = CreateEventW( NULL, TRUE, FALSE, NULL );
1002 handles[1] = thread = CreateThread( NULL, 0, device_thread, handles[0], 0, NULL );
1003 WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
1004 CloseHandle( handles[0] );
1008 /* Client-side ioctl support */
1011 static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size )
1013 static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1014 static HANDLE device;
1015 IO_STATUS_BLOCK iosb;
1016 NTSTATUS status;
1018 if (!device)
1020 HANDLE file = CreateFileW( deviceW, GENERIC_READ,
1021 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1022 if (file == INVALID_HANDLE_VALUE) return -ENOENT;
1023 if (InterlockedCompareExchangePointer( &device, file, NULL )) CloseHandle( file );
1026 status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code),
1027 in, in_size, out, out_size ? *out_size : 0 );
1028 if (status == STATUS_FILE_DELETED)
1030 WARN( "parent process is gone\n" );
1031 ExitProcess( 1 );
1033 if (out_size) *out_size = iosb.Information;
1034 return status_to_android_error( status );
1037 static void win_incRef( struct android_native_base_t *base )
1039 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1040 InterlockedIncrement( &win->ref );
1043 static void win_decRef( struct android_native_base_t *base )
1045 struct native_win_wrapper *win = (struct native_win_wrapper *)base;
1046 InterlockedDecrement( &win->ref );
1049 static void buffer_incRef( struct android_native_base_t *base )
1051 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1052 InterlockedIncrement( &buffer->ref );
1055 static void buffer_decRef( struct android_native_base_t *base )
1057 struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
1059 if (!InterlockedDecrement( &buffer->ref ))
1061 if (!is_in_desktop_process())
1063 if (gralloc_module) gralloc_module->unregisterBuffer( gralloc_module, buffer->buffer.handle );
1064 close_native_handle( (native_handle_t *)buffer->buffer.handle );
1066 if (buffer->bits) UnmapViewOfFile( buffer->bits );
1067 HeapFree( GetProcessHeap(), 0, buffer );
1071 static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer, int *fence )
1073 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1074 struct ioctl_android_dequeueBuffer res;
1075 DWORD size = sizeof(res);
1076 int ret, use_win32 = !gralloc_module;
1078 res.hdr.hwnd = HandleToLong( win->hwnd );
1079 res.win32 = use_win32;
1080 ret = android_ioctl( IOCTL_DEQUEUE_BUFFER,
1081 &res, offsetof( struct ioctl_android_dequeueBuffer, native_handle ),
1082 &res, &size );
1083 if (ret) return ret;
1085 /* if we received the native handle, this is a new buffer */
1086 if (size > offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
1088 struct native_buffer_wrapper *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buf) );
1090 buf->buffer.common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
1091 buf->buffer.common.version = sizeof( buf->buffer );
1092 buf->buffer.common.incRef = buffer_incRef;
1093 buf->buffer.common.decRef = buffer_decRef;
1094 buf->buffer.width = res.width;
1095 buf->buffer.height = res.height;
1096 buf->buffer.stride = res.stride;
1097 buf->buffer.format = res.format;
1098 buf->buffer.usage = res.usage;
1099 buf->buffer.handle = unmap_native_handle( &res.native_handle.handle );
1100 buf->ref = 1;
1101 buf->hwnd = win->hwnd;
1102 buf->buffer_id = res.buffer_id;
1103 if (win->buffers[res.buffer_id])
1104 win->buffers[res.buffer_id]->buffer.common.decRef(&win->buffers[res.buffer_id]->buffer.common);
1105 win->buffers[res.buffer_id] = buf;
1107 if (use_win32)
1109 HANDLE mapping = LongToHandle( res.native_handle.handle.data[0] );
1110 buf->bits = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
1111 CloseHandle( mapping );
1113 else if (!is_in_desktop_process())
1115 if ((ret = gralloc_module->registerBuffer( gralloc_module, buf->buffer.handle )) < 0)
1116 WARN( "hwnd %p, buffer %p failed to register %d %s\n", win->hwnd, &buf->buffer, ret, strerror(-ret) );
1120 *buffer = &win->buffers[res.buffer_id]->buffer;
1121 *fence = -1;
1123 TRACE( "hwnd %p, buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1124 win->hwnd, *buffer, res.width, res.height, res.stride, res.format, res.usage, *fence );
1125 return 0;
1128 static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1130 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1131 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1132 struct ioctl_android_cancelBuffer cancel;
1134 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1135 win->hwnd, buffer, buffer->width, buffer->height,
1136 buffer->stride, buffer->format, buffer->usage, fence );
1137 cancel.buffer_id = buf->buffer_id;
1138 cancel.hdr.hwnd = HandleToLong( win->hwnd );
1139 wait_fence_and_close( fence );
1140 return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL );
1143 static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
1145 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1146 struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
1147 struct ioctl_android_queueBuffer queue;
1149 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1150 win->hwnd, buffer, buffer->width, buffer->height,
1151 buffer->stride, buffer->format, buffer->usage, fence );
1152 queue.buffer_id = buf->buffer_id;
1153 queue.hdr.hwnd = HandleToLong( win->hwnd );
1154 wait_fence_and_close( fence );
1155 return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL );
1158 static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer )
1160 int fence, ret = dequeueBuffer( window, buffer, &fence );
1162 if (!ret) wait_fence_and_close( fence );
1163 return ret;
1166 static int cancelBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1168 return cancelBuffer( window, buffer, -1 );
1171 static int lockBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1173 return 0; /* nothing to do */
1176 static int queueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer )
1178 return queueBuffer( window, buffer, -1 );
1181 static int setSwapInterval( struct ANativeWindow *window, int interval )
1183 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1184 struct ioctl_android_set_swap_interval swap;
1186 TRACE( "hwnd %p interval %d\n", win->hwnd, interval );
1187 swap.hdr.hwnd = HandleToLong( win->hwnd );
1188 swap.interval = interval;
1189 return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL );
1192 static int query( const ANativeWindow *window, int what, int *value )
1194 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1195 struct ioctl_android_query query;
1196 DWORD size = sizeof( query );
1197 int ret;
1199 query.hdr.hwnd = HandleToLong( win->hwnd );
1200 query.what = what;
1201 ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size );
1202 TRACE( "hwnd %p what %d got %d -> %p\n", win->hwnd, what, query.value, value );
1203 if (!ret) *value = query.value;
1204 return ret;
1207 static int perform( ANativeWindow *window, int operation, ... )
1209 static const char * const names[] =
1211 "SET_USAGE", "CONNECT", "DISCONNECT", "SET_CROP", "SET_BUFFER_COUNT", "SET_BUFFERS_GEOMETRY",
1212 "SET_BUFFERS_TRANSFORM", "SET_BUFFERS_TIMESTAMP", "SET_BUFFERS_DIMENSIONS", "SET_BUFFERS_FORMAT",
1213 "SET_SCALING_MODE", "LOCK", "UNLOCK_AND_POST", "API_CONNECT", "API_DISCONNECT",
1214 "SET_BUFFERS_USER_DIMENSIONS", "SET_POST_TRANSFORM_CROP"
1217 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1218 struct ioctl_android_perform perf;
1219 va_list args;
1221 perf.hdr.hwnd = HandleToLong( win->hwnd );
1222 perf.operation = operation;
1223 memset( perf.args, 0, sizeof(perf.args) );
1225 va_start( args, operation );
1226 switch (operation)
1228 case NATIVE_WINDOW_SET_USAGE:
1229 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
1230 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
1231 case NATIVE_WINDOW_SET_SCALING_MODE:
1232 case NATIVE_WINDOW_API_CONNECT:
1233 case NATIVE_WINDOW_API_DISCONNECT:
1234 perf.args[0] = va_arg( args, int );
1235 TRACE( "hwnd %p %s arg %d\n", win->hwnd, names[operation], perf.args[0] );
1236 break;
1237 case NATIVE_WINDOW_SET_BUFFER_COUNT:
1238 perf.args[0] = va_arg( args, size_t );
1239 TRACE( "hwnd %p %s count %d\n", win->hwnd, names[operation], perf.args[0] );
1240 break;
1241 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
1242 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
1243 perf.args[0] = va_arg( args, int );
1244 perf.args[1] = va_arg( args, int );
1245 TRACE( "hwnd %p %s arg %dx%d\n", win->hwnd, names[operation], perf.args[0], perf.args[1] );
1246 break;
1247 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
1248 perf.args[0] = va_arg( args, int );
1249 perf.args[1] = va_arg( args, int );
1250 perf.args[2] = va_arg( args, int );
1251 TRACE( "hwnd %p %s arg %dx%d %d\n", win->hwnd, names[operation],
1252 perf.args[0], perf.args[1], perf.args[2] );
1253 break;
1254 case NATIVE_WINDOW_SET_CROP:
1256 android_native_rect_t *rect = va_arg( args, android_native_rect_t * );
1257 perf.args[0] = rect->left;
1258 perf.args[1] = rect->top;
1259 perf.args[2] = rect->right;
1260 perf.args[3] = rect->bottom;
1261 TRACE( "hwnd %p %s rect %d,%d-%d,%d\n", win->hwnd, names[operation],
1262 perf.args[0], perf.args[1], perf.args[2], perf.args[3] );
1263 break;
1265 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
1267 int64_t timestamp = va_arg( args, int64_t );
1268 perf.args[0] = timestamp;
1269 perf.args[1] = timestamp >> 32;
1270 TRACE( "hwnd %p %s arg %08x%08x\n", win->hwnd, names[operation], perf.args[1], perf.args[0] );
1271 break;
1273 case NATIVE_WINDOW_LOCK:
1275 struct ANativeWindowBuffer *buffer;
1276 struct ANativeWindow_Buffer *buffer_ret = va_arg( args, ANativeWindow_Buffer * );
1277 ARect *bounds = va_arg( args, ARect * );
1278 int ret = window->dequeueBuffer_DEPRECATED( window, &buffer );
1279 if (!ret)
1281 if (gralloc_module)
1283 if ((ret = gralloc_module->lock( gralloc_module, buffer->handle,
1284 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
1285 0, 0, buffer->width, buffer->height, &buffer_ret->bits )))
1287 WARN( "gralloc->lock %p failed %d %s\n", win->hwnd, ret, strerror(-ret) );
1288 window->cancelBuffer( window, buffer, -1 );
1291 else
1292 buffer_ret->bits = ((struct native_buffer_wrapper *)buffer)->bits;
1294 if (!ret)
1296 buffer_ret->width = buffer->width;
1297 buffer_ret->height = buffer->height;
1298 buffer_ret->stride = buffer->stride;
1299 buffer_ret->format = buffer->format;
1300 win->locked_buffer = buffer;
1301 if (bounds)
1303 bounds->left = 0;
1304 bounds->top = 0;
1305 bounds->right = buffer->width;
1306 bounds->bottom = buffer->height;
1309 va_end( args );
1310 TRACE( "hwnd %p %s bits %p ret %d %s\n", win->hwnd, names[operation], buffer_ret->bits, ret, strerror(-ret) );
1311 return ret;
1313 case NATIVE_WINDOW_UNLOCK_AND_POST:
1315 int ret = -EINVAL;
1316 if (win->locked_buffer)
1318 if (gralloc_module) gralloc_module->unlock( gralloc_module, win->locked_buffer->handle );
1319 ret = window->queueBuffer( window, win->locked_buffer, -1 );
1320 win->locked_buffer = NULL;
1322 va_end( args );
1323 TRACE( "hwnd %p %s ret %d\n", win->hwnd, names[operation], ret );
1324 return ret;
1326 case NATIVE_WINDOW_CONNECT:
1327 case NATIVE_WINDOW_DISCONNECT:
1328 TRACE( "hwnd %p %s\n", win->hwnd, names[operation] );
1329 break;
1330 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP:
1331 default:
1332 FIXME( "unsupported perform hwnd %p op %d %s\n", win->hwnd, operation,
1333 operation < sizeof(names)/sizeof(names[0]) ? names[operation] : "???" );
1334 break;
1336 va_end( args );
1337 return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL );
1340 struct ANativeWindow *create_ioctl_window( HWND hwnd )
1342 struct ioctl_android_create_window req;
1343 struct native_win_wrapper *win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*win) );
1344 HWND parent = GetAncestor( hwnd, GA_PARENT );
1346 if (!win) return NULL;
1348 win->win.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
1349 win->win.common.version = sizeof(ANativeWindow);
1350 win->win.common.incRef = win_incRef;
1351 win->win.common.decRef = win_decRef;
1352 win->win.setSwapInterval = setSwapInterval;
1353 win->win.dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
1354 win->win.lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
1355 win->win.queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
1356 win->win.query = query;
1357 win->win.perform = perform;
1358 win->win.cancelBuffer_DEPRECATED = cancelBuffer_DEPRECATED;
1359 win->win.dequeueBuffer = dequeueBuffer;
1360 win->win.queueBuffer = queueBuffer;
1361 win->win.cancelBuffer = cancelBuffer;
1362 win->ref = 1;
1363 win->hwnd = hwnd;
1364 TRACE( "-> %p %p\n", win, win->hwnd );
1366 req.hdr.hwnd = HandleToLong( hwnd );
1367 req.parent = parent == GetDesktopWindow() ? 0 : HandleToLong( parent );
1368 android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL );
1370 return &win->win;
1373 struct ANativeWindow *grab_ioctl_window( struct ANativeWindow *window )
1375 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1376 InterlockedIncrement( &win->ref );
1377 return window;
1380 void release_ioctl_window( struct ANativeWindow *window )
1382 struct native_win_wrapper *win = (struct native_win_wrapper *)window;
1383 unsigned int i;
1385 if (InterlockedDecrement( &win->ref ) > 0) return;
1387 TRACE( "%p %p\n", win, win->hwnd );
1388 for (i = 0; i < sizeof(win->buffers)/sizeof(win->buffers[0]); i++)
1389 if (win->buffers[i]) win->buffers[i]->buffer.common.decRef( &win->buffers[i]->buffer.common );
1391 destroy_ioctl_window( win->hwnd );
1392 HeapFree( GetProcessHeap(), 0, win );
1395 void destroy_ioctl_window( HWND hwnd )
1397 struct ioctl_android_destroy_window req;
1399 req.hdr.hwnd = HandleToLong( hwnd );
1400 android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL );
1403 int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const RECT *client_rect,
1404 const RECT *visible_rect, UINT style, UINT flags, HWND after, HWND owner )
1406 struct ioctl_android_window_pos_changed req;
1408 req.hdr.hwnd = HandleToLong( hwnd );
1409 req.window_rect = *window_rect;
1410 req.client_rect = *client_rect;
1411 req.visible_rect = *visible_rect;
1412 req.style = style;
1413 req.flags = flags;
1414 req.after = HandleToLong( after );
1415 req.owner = HandleToLong( owner );
1416 return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL );
1419 int ioctl_set_window_parent( HWND hwnd, HWND parent )
1421 struct ioctl_android_set_window_parent req;
1423 req.hdr.hwnd = HandleToLong( hwnd );
1424 req.parent = parent == GetDesktopWindow() ? 0 : HandleToLong( parent );
1425 return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL );
1428 int ioctl_set_capture( HWND hwnd )
1430 struct ioctl_android_set_capture req;
1432 req.hdr.hwnd = HandleToLong( hwnd );
1433 return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL );