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
27 #include "wine/port.h"
44 #include "wine/unicode.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 /***********************************************************************
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
))))
92 data
->window
= create_ioctl_window( hwnd
);
93 EnterCriticalSection( &win_data_section
);
94 win_data_context
[context_idx(hwnd
)] = data
;
100 /***********************************************************************
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 /***********************************************************************
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
);
129 /***********************************************************************
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 */
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 /***********************************************************************
156 int send_event( const union event_data
*data
)
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" );
169 /***********************************************************************
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
);
187 /***********************************************************************
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
);
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
;
216 /***********************************************************************
219 static void init_event_queue(void)
224 if (pipe2( event_pipe
, O_CLOEXEC
| O_NONBLOCK
) == -1)
226 ERR( "could not create data\n" );
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" );
234 SERVER_START_REQ( set_queue_fd
)
236 req
->handle
= wine_server_obj_handle( handle
);
237 ret
= wine_server_call( req
);
242 ERR( "Can't store handle for event fd %x\n", ret
);
245 CloseHandle( handle
);
246 desktop_tid
= GetCurrentThreadId();
250 /***********************************************************************
253 * Pull events from the event pipe and add them to the queue
255 static void pull_events(void)
257 struct java_event
*event
;
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 /***********************************************************************
275 static int process_events( DWORD mask
)
277 struct java_event
*event
, *next
, *previous
;
278 unsigned int count
= 0;
280 assert( GetCurrentThreadId() == desktop_tid
);
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 */
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
);
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
);
320 FIXME( "got event %u\n", event
->data
.type
);
322 HeapFree( GetProcessHeap(), 0, event
);
325 current_event
= previous
;
330 /***********************************************************************
333 static int wait_events( int timeout
)
335 assert( GetCurrentThreadId() == desktop_tid
);
339 struct pollfd pollfd
;
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;
352 static WNDPROC desktop_orig_wndproc
;
354 static LRESULT CALLBACK
desktop_wndproc_wrapper( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
358 case WM_PARENTNOTIFY
:
359 if (LOWORD(wp
) == WM_DESTROY
) destroy_ioctl_window( (HWND
)lp
);
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
;
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
);
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 /***********************************************************************
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
;
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
)))
435 release_win_data( data
);
438 if (!(data
= alloc_win_data( hwnd
))) return NULL
;
440 data
->parent
= (parent
== GetDesktopWindow()) ? 0 : parent
;
444 data
->whole_rect
= data
->window_rect
= *window_rect
;
445 data
->client_rect
= *client_rect
;
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
));
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
);
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" );
525 process_events( QS_ALLINPUT
);