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/server.h"
42 #include "wine/library.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(android
);
48 #define SYNC_IOC_WAIT _IOW('>', 0, __s32)
51 extern NTSTATUS CDECL
wine_ntoskrnl_main_loop( HANDLE stop_event
);
52 static HANDLE stop_event
;
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)
64 IOCTL_WINDOW_POS_CHANGED
,
65 IOCTL_SET_WINDOW_PARENT
,
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
;
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
];
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
;
110 /* wrapper for a native buffer in the context of the client (non-Java) process */
111 struct native_buffer_wrapper
113 struct ANativeWindowBuffer buffer
;
118 union native_handle_buffer native_handle
;
126 struct ioctl_android_create_window
128 struct ioctl_header hdr
;
132 struct ioctl_android_destroy_window
134 struct ioctl_header hdr
;
137 struct ioctl_android_window_pos_changed
139 struct ioctl_header hdr
;
149 struct ioctl_android_dequeueBuffer
151 struct ioctl_header hdr
;
159 union native_handle_buffer native_handle
;
162 struct ioctl_android_queueBuffer
164 struct ioctl_header hdr
;
168 struct ioctl_android_cancelBuffer
170 struct ioctl_header hdr
;
174 struct ioctl_android_query
176 struct ioctl_header hdr
;
181 struct ioctl_android_perform
183 struct ioctl_header hdr
;
188 struct ioctl_android_set_swap_interval
190 struct ioctl_header hdr
;
194 struct ioctl_android_set_window_parent
196 struct ioctl_header hdr
;
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
); }
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
)
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
);
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
);
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
);
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
] );
277 if (mapping
) /* only duplicate the mapping handle */
280 if (!DuplicateHandle( GetCurrentProcess(), mapping
, client
, &ret
,
281 DUPLICATE_SAME_ACCESS
, FALSE
, DUP_HANDLE_CLOSE_SOURCE
))
283 dest
->handle
.numFds
= 0;
284 dest
->handle
.numInts
= 1;
285 dest
->handle
.data
[0] = HandleToLong( ret
);
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
) );
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
] );
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
;
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
) );
322 static void close_native_handle( native_handle_t
*handle
)
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
)
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
)
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
;
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
);
381 TRACE( "%p %p %p -> %d\n", win
->hwnd
, win
->parent
, buffer
, i
);
384 insert_buffer_lru( win
, 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
);
395 return win
->buffers
[id
];
398 static void release_native_window( struct native_win_data
*data
)
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
];
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
;
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;
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
);
456 release_native_window( data
);
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
);
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
)
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
;
500 FIXME( "unmapped error %d\n", err
);
501 return STATUS_UNSUCCESSFUL
;
505 static int status_to_android_error( NTSTATUS 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
;
524 FIXME( "unmapped status %08x\n", status
);
529 static jobject
load_java_method( jmethodID
*method
, const char *name
, const char *args
)
531 jobject object
= wine_get_java_object();
538 class = (*jni_env
)->GetObjectClass( jni_env
, object
);
539 *method
= (*jni_env
)->GetMethodID( jni_env
, class, name
, args
);
543 FIXME( "method %s not found\n", name
);
550 static void create_desktop_window( HWND hwnd
)
552 static jmethodID method
;
555 if (!(object
= load_java_method( &method
, "createDesktopWindow", "(I)V" ))) return;
558 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, HandleToLong( hwnd
));
562 static NTSTATUS
createWindow_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
564 static jmethodID method
;
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
;
580 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->parent
, pid
);
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
;
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
;
601 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
);
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
;
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
;
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
);
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
);
649 ret
= parent
->dequeueBuffer( parent
, &buffer
, &fence
);
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
);
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
;
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
);
693 ret
= parent
->cancelBuffer( parent
, buffer
, -1 );
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
;
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
])
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
);
725 ret
= parent
->queueBuffer( parent
, buffer
, -1 );
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
;
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
);
745 ret
= parent
->query( parent
, res
->what
, &res
->value
);
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
;
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
:
766 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
768 if (!ret
) win_data
->buffer_format
= res
->args
[0];
770 case NATIVE_WINDOW_API_CONNECT
:
772 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
774 if (!ret
) win_data
->api
= res
->args
[0];
776 case NATIVE_WINDOW_API_DISCONNECT
:
778 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
780 if (!ret
) win_data
->api
= 0;
782 case NATIVE_WINDOW_SET_USAGE
:
783 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
:
784 case NATIVE_WINDOW_SET_SCALING_MODE
:
786 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
789 case NATIVE_WINDOW_SET_BUFFER_COUNT
:
791 ret
= parent
->perform( parent
, res
->operation
, (size_t)res
->args
[0] );
794 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
:
795 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS
:
797 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0], res
->args
[1] );
800 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
:
802 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0], res
->args
[1], res
->args
[2] );
805 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
:
807 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] | ((int64_t)res
->args
[1] << 32) );
810 case NATIVE_WINDOW_CONNECT
:
811 case NATIVE_WINDOW_DISCONNECT
:
812 case NATIVE_WINDOW_UNLOCK_AND_POST
:
814 ret
= parent
->perform( parent
, res
->operation
);
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];
825 ret
= parent
->perform( parent
, res
->operation
, &rect
);
829 case NATIVE_WINDOW_LOCK
:
831 FIXME( "unsupported perform op %d\n", res
->operation
);
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
;
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
;
851 ret
= parent
->setSwapInterval( parent
, res
->interval
);
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
;
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
;
873 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->parent
, pid
);
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
;
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
;
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
;
965 TRACE( "starting process %x\n", GetCurrentProcessId() );
967 if (!(java_vm
= wine_get_java_vm())) return 0; /* not running under Java */
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
);
976 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
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
);
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
);
997 void start_android_device(void)
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
;
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" );
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
),
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
);
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
;
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
;
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
);
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
);
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
);
1199 query
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
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
;
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
;
1221 perf
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1222 perf
.operation
= operation
;
1223 memset( perf
.args
, 0, sizeof(perf
.args
) );
1225 va_start( args
, 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] );
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] );
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] );
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] );
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] );
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] );
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
);
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 );
1292 buffer_ret
->bits
= ((struct native_buffer_wrapper
*)buffer
)->bits
;
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
;
1305 bounds
->right
= buffer
->width
;
1306 bounds
->bottom
= buffer
->height
;
1310 TRACE( "hwnd %p %s bits %p ret %d %s\n", win
->hwnd
, names
[operation
], buffer_ret
->bits
, ret
, strerror(-ret
) );
1313 case NATIVE_WINDOW_UNLOCK_AND_POST
:
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
;
1323 TRACE( "hwnd %p %s ret %d\n", win
->hwnd
, names
[operation
], ret
);
1326 case NATIVE_WINDOW_CONNECT
:
1327 case NATIVE_WINDOW_DISCONNECT
:
1328 TRACE( "hwnd %p %s\n", win
->hwnd
, names
[operation
] );
1330 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP
:
1332 FIXME( "unsupported perform hwnd %p op %d %s\n", win
->hwnd
, operation
,
1333 operation
< sizeof(names
)/sizeof(names
[0]) ? names
[operation
] : "???" );
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
;
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
);
1373 struct ANativeWindow
*grab_ioctl_window( struct ANativeWindow
*window
)
1375 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1376 InterlockedIncrement( &win
->ref
);
1380 void release_ioctl_window( struct ANativeWindow
*window
)
1382 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
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
;
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
);