wineandroid: Allocate a native window wrapper in the client process for every window.
[wine.git] / dlls / wineandroid.drv / window.c
blob65b37d8ed6c22ec8a6df8486313096fd129a4f08
1 /*
2 * Window related functions
4 * Copyright 1993, 1994, 1995, 1996, 2001, 2013-2017 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
26 #include "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wingdi.h"
43 #include "winuser.h"
44 #include "wine/unicode.h"
46 #include "android.h"
47 #include "wine/server.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(android);
52 /* private window data */
53 struct android_win_data
55 HWND hwnd; /* hwnd that this private data belongs to */
56 HWND parent; /* parent hwnd for child windows */
57 RECT window_rect; /* USER window rectangle relative to parent */
58 RECT whole_rect; /* X window rectangle for the whole window relative to parent */
59 RECT client_rect; /* client area relative to parent */
60 ANativeWindow *window; /* native window wrapper that forwards calls to the desktop process */
63 #define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
65 static CRITICAL_SECTION win_data_section;
66 static CRITICAL_SECTION_DEBUG critsect_debug =
68 0, 0, &win_data_section,
69 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
70 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
72 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
74 static struct android_win_data *win_data_context[32768];
76 static inline int context_idx( HWND hwnd )
78 return LOWORD( hwnd ) >> 1;
82 /***********************************************************************
83 * alloc_win_data
85 static struct android_win_data *alloc_win_data( HWND hwnd )
87 struct android_win_data *data;
89 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
91 data->hwnd = hwnd;
92 data->window = create_ioctl_window( hwnd );
93 EnterCriticalSection( &win_data_section );
94 win_data_context[context_idx(hwnd)] = data;
96 return data;
100 /***********************************************************************
101 * free_win_data
103 static void free_win_data( struct android_win_data *data )
105 win_data_context[context_idx( data->hwnd )] = NULL;
106 LeaveCriticalSection( &win_data_section );
107 if (data->window) release_ioctl_window( data->window );
108 HeapFree( GetProcessHeap(), 0, data );
112 /***********************************************************************
113 * get_win_data
115 * Lock and return the data structure associated with a window.
117 static struct android_win_data *get_win_data( HWND hwnd )
119 struct android_win_data *data;
121 if (!hwnd) return NULL;
122 EnterCriticalSection( &win_data_section );
123 if ((data = win_data_context[context_idx(hwnd)]) && data->hwnd == hwnd) return data;
124 LeaveCriticalSection( &win_data_section );
125 return NULL;
129 /***********************************************************************
130 * release_win_data
132 * Release the data returned by get_win_data.
134 static void release_win_data( struct android_win_data *data )
136 if (data) LeaveCriticalSection( &win_data_section );
140 /* Handling of events coming from the Java side */
142 struct java_event
144 struct list entry;
145 union event_data data;
148 static struct list event_queue = LIST_INIT( event_queue );
149 static struct java_event *current_event;
150 static int event_pipe[2];
151 static DWORD desktop_tid;
153 /***********************************************************************
154 * send_event
156 int send_event( const union event_data *data )
158 int res;
160 if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
162 p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
163 return -1;
165 return 0;
169 /***********************************************************************
170 * desktop_changed
172 * JNI callback, runs in the context of the Java thread.
174 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
176 union event_data data;
178 memset( &data, 0, sizeof(data) );
179 data.type = DESKTOP_CHANGED;
180 data.desktop.width = width;
181 data.desktop.height = height;
182 p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
183 send_event( &data );
187 /***********************************************************************
188 * surface_changed
190 * JNI callback, runs in the context of the Java thread.
192 void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface )
194 union event_data data;
196 memset( &data, 0, sizeof(data) );
197 data.surface.hwnd = LongToHandle( win );
198 if (surface)
200 int width, height;
201 ANativeWindow *win = pANativeWindow_fromSurface( env, surface );
203 if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0;
204 if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0;
205 data.surface.window = win;
206 data.surface.width = width;
207 data.surface.height = height;
208 p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %ux%u",
209 data.surface.hwnd, width, height );
211 data.type = SURFACE_CHANGED;
212 send_event( &data );
216 /***********************************************************************
217 * init_event_queue
219 static void init_event_queue(void)
221 HANDLE handle;
222 int ret;
224 if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
226 ERR( "could not create data\n" );
227 ExitProcess(1);
229 if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
231 ERR( "Can't allocate handle for event fd\n" );
232 ExitProcess(1);
234 SERVER_START_REQ( set_queue_fd )
236 req->handle = wine_server_obj_handle( handle );
237 ret = wine_server_call( req );
239 SERVER_END_REQ;
240 if (ret)
242 ERR( "Can't store handle for event fd %x\n", ret );
243 ExitProcess(1);
245 CloseHandle( handle );
246 desktop_tid = GetCurrentThreadId();
250 /***********************************************************************
251 * pull_events
253 * Pull events from the event pipe and add them to the queue
255 static void pull_events(void)
257 struct java_event *event;
258 int res;
260 for (;;)
262 if (!(event = HeapAlloc( GetProcessHeap(), 0, sizeof(*event) ))) break;
264 res = read( event_pipe[0], &event->data, sizeof(event->data) );
265 if (res != sizeof(event->data)) break;
266 list_add_tail( &event_queue, &event->entry );
268 HeapFree( GetProcessHeap(), 0, event );
272 /***********************************************************************
273 * process_events
275 static int process_events( DWORD mask )
277 struct java_event *event, *next, *previous;
278 unsigned int count = 0;
280 assert( GetCurrentThreadId() == desktop_tid );
282 pull_events();
284 previous = current_event;
286 LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
288 switch (event->data.type)
290 case SURFACE_CHANGED:
291 break; /* always process it to unblock other threads */
292 default:
293 if (mask & QS_SENDMESSAGE) break;
294 continue; /* skip it */
297 /* remove it first, in case we process events recursively */
298 list_remove( &event->entry );
299 current_event = event;
301 switch (event->data.type)
303 case DESKTOP_CHANGED:
304 TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
305 screen_width = event->data.desktop.width;
306 screen_height = event->data.desktop.height;
307 init_monitors( screen_width, screen_height );
308 SetWindowPos( GetDesktopWindow(), 0, 0, 0, screen_width, screen_height,
309 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
310 break;
312 case SURFACE_CHANGED:
313 TRACE("SURFACE_CHANGED %p %p size %ux%u\n", event->data.surface.hwnd,
314 event->data.surface.window, event->data.surface.width, event->data.surface.height );
316 register_native_window( event->data.surface.hwnd, event->data.surface.window );
317 break;
319 default:
320 FIXME( "got event %u\n", event->data.type );
322 HeapFree( GetProcessHeap(), 0, event );
323 count++;
325 current_event = previous;
326 return count;
330 /***********************************************************************
331 * wait_events
333 static int wait_events( int timeout )
335 assert( GetCurrentThreadId() == desktop_tid );
337 for (;;)
339 struct pollfd pollfd;
340 int ret;
342 pollfd.fd = event_pipe[0];
343 pollfd.events = POLLIN | POLLHUP;
344 ret = poll( &pollfd, 1, timeout );
345 if (ret == -1 && errno == EINTR) continue;
346 if (ret && (pollfd.revents & (POLLHUP | POLLERR))) ret = -1;
347 return ret;
352 static WNDPROC desktop_orig_wndproc;
354 static LRESULT CALLBACK desktop_wndproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
356 switch (msg)
358 case WM_PARENTNOTIFY:
359 if (LOWORD(wp) == WM_DESTROY) destroy_ioctl_window( (HWND)lp );
360 break;
362 return desktop_orig_wndproc( hwnd, msg, wp, lp );
366 /***********************************************************************
367 * ANDROID_MsgWaitForMultipleObjectsEx
369 DWORD CDECL ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
370 DWORD timeout, DWORD mask, DWORD flags )
372 if (GetCurrentThreadId() == desktop_tid)
374 /* don't process nested events */
375 if (current_event) mask = 0;
376 if (process_events( mask )) return count - 1;
378 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
379 timeout, flags & MWMO_ALERTABLE );
382 /**********************************************************************
383 * ANDROID_CreateWindow
385 BOOL CDECL ANDROID_CreateWindow( HWND hwnd )
387 TRACE( "%p\n", hwnd );
389 if (hwnd == GetDesktopWindow())
391 struct android_win_data *data;
393 init_event_queue();
394 start_android_device();
395 desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC,
396 (LONG_PTR)desktop_wndproc_wrapper );
397 if (!(data = alloc_win_data( hwnd ))) return FALSE;
398 release_win_data( data );
400 return TRUE;
404 /***********************************************************************
405 * ANDROID_DestroyWindow
407 void CDECL ANDROID_DestroyWindow( HWND hwnd )
409 struct android_win_data *data;
411 if (!(data = get_win_data( hwnd ))) return;
413 free_win_data( data );
417 /***********************************************************************
418 * create_win_data
420 * Create a data window structure for an existing window.
422 static struct android_win_data *create_win_data( HWND hwnd, const RECT *window_rect,
423 const RECT *client_rect )
425 struct android_win_data *data;
426 HWND parent;
428 if (!(parent = GetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop or HWND_MESSAGE */
430 if (parent != GetDesktopWindow())
432 if (!(data = get_win_data( parent )) &&
433 !(data = create_win_data( parent, NULL, NULL )))
434 return NULL;
435 release_win_data( data );
438 if (!(data = alloc_win_data( hwnd ))) return NULL;
440 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
442 if (window_rect)
444 data->whole_rect = data->window_rect = *window_rect;
445 data->client_rect = *client_rect;
447 else
449 GetWindowRect( hwnd, &data->window_rect );
450 MapWindowPoints( 0, parent, (POINT *)&data->window_rect, 2 );
451 data->whole_rect = data->window_rect;
452 GetClientRect( hwnd, &data->client_rect );
453 MapWindowPoints( hwnd, parent, (POINT *)&data->client_rect, 2 );
454 ioctl_window_pos_changed( hwnd, &data->window_rect, &data->client_rect, &data->whole_rect,
455 GetWindowLongW( hwnd, GWL_STYLE ), SWP_NOACTIVATE,
456 GetWindow( hwnd, GW_HWNDPREV ), GetWindow( hwnd, GW_OWNER ));
458 return data;
462 /***********************************************************************
463 * ANDROID_WindowPosChanging
465 void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
466 const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
467 struct window_surface **surface )
469 struct android_win_data *data = get_win_data( hwnd );
471 TRACE( "win %p window %s client %s style %08x flags %08x\n",
472 hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
473 GetWindowLongW( hwnd, GWL_STYLE ), swp_flags );
475 if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return;
477 *visible_rect = *window_rect;
479 release_win_data( data );
483 /***********************************************************************
484 * ANDROID_WindowPosChanged
486 void CDECL ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
487 const RECT *window_rect, const RECT *client_rect,
488 const RECT *visible_rect, const RECT *valid_rects,
489 struct window_surface *surface )
491 struct android_win_data *data;
492 DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
493 HWND owner = 0;
495 if (!(data = get_win_data( hwnd ))) return;
497 data->window_rect = *window_rect;
498 data->whole_rect = *visible_rect;
499 data->client_rect = *client_rect;
501 if (!data->parent) owner = GetWindow( hwnd, GW_OWNER );
502 release_win_data( data );
504 TRACE( "win %p window %s client %s style %08x owner %p flags %08x\n", hwnd,
505 wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), new_style, owner, swp_flags );
507 ioctl_window_pos_changed( hwnd, window_rect, client_rect, visible_rect,
508 new_style, swp_flags, insert_after, owner );
512 /***********************************************************************
513 * ANDROID_create_desktop
515 BOOL CDECL ANDROID_create_desktop( UINT width, UINT height )
517 /* wait until we receive the surface changed event */
518 while (!screen_width)
520 if (wait_events( 2000 ) != 1)
522 ERR( "wait timed out\n" );
523 break;
525 process_events( QS_ALLINPUT );
527 return TRUE;