server: Create the initial thread as a separate request.
[wine.git] / dlls / wineandroid.drv / window.c
blobaebe4c57b35214a945ed21b264665417a587a983
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 */
61 struct window_surface *surface;
64 #define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
66 static CRITICAL_SECTION win_data_section;
67 static CRITICAL_SECTION_DEBUG critsect_debug =
69 0, 0, &win_data_section,
70 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
71 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
73 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
75 static struct android_win_data *win_data_context[32768];
77 static inline int context_idx( HWND hwnd )
79 return LOWORD( hwnd ) >> 1;
82 static void set_surface_region( struct window_surface *window_surface, HRGN win_region );
84 /* only for use on sanitized BITMAPINFO structures */
85 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
87 if (info->bmiHeader.biCompression == BI_BITFIELDS)
88 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
89 if (coloruse == DIB_PAL_COLORS)
90 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
91 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
94 static inline int get_dib_stride( int width, int bpp )
96 return ((width * bpp + 31) >> 3) & ~3;
99 static inline int get_dib_image_size( const BITMAPINFO *info )
101 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
102 * abs( info->bmiHeader.biHeight );
106 /**********************************************************************
107 * get_win_monitor_dpi
109 static UINT get_win_monitor_dpi( HWND hwnd )
111 DPI_AWARENESS_CONTEXT context;
112 UINT ret;
114 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
115 ret = GetDpiForSystem(); /* FIXME: get monitor dpi */
116 SetThreadDpiAwarenessContext( context );
117 return ret;
121 /***********************************************************************
122 * alloc_win_data
124 static struct android_win_data *alloc_win_data( HWND hwnd )
126 struct android_win_data *data;
128 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
130 data->hwnd = hwnd;
131 data->window = create_ioctl_window( hwnd, FALSE,
132 (float)get_win_monitor_dpi( hwnd ) / GetDpiForWindow( hwnd ));
133 EnterCriticalSection( &win_data_section );
134 win_data_context[context_idx(hwnd)] = data;
136 return data;
140 /***********************************************************************
141 * free_win_data
143 static void free_win_data( struct android_win_data *data )
145 win_data_context[context_idx( data->hwnd )] = NULL;
146 LeaveCriticalSection( &win_data_section );
147 if (data->window) release_ioctl_window( data->window );
148 HeapFree( GetProcessHeap(), 0, data );
152 /***********************************************************************
153 * get_win_data
155 * Lock and return the data structure associated with a window.
157 static struct android_win_data *get_win_data( HWND hwnd )
159 struct android_win_data *data;
161 if (!hwnd) return NULL;
162 EnterCriticalSection( &win_data_section );
163 if ((data = win_data_context[context_idx(hwnd)]) && data->hwnd == hwnd) return data;
164 LeaveCriticalSection( &win_data_section );
165 return NULL;
169 /***********************************************************************
170 * release_win_data
172 * Release the data returned by get_win_data.
174 static void release_win_data( struct android_win_data *data )
176 if (data) LeaveCriticalSection( &win_data_section );
180 /***********************************************************************
181 * get_ioctl_window
183 static struct ANativeWindow *get_ioctl_window( HWND hwnd )
185 struct ANativeWindow *ret;
186 struct android_win_data *data = get_win_data( hwnd );
188 if (!data || !data->window) return NULL;
189 ret = grab_ioctl_window( data->window );
190 release_win_data( data );
191 return ret;
195 /* Handling of events coming from the Java side */
197 struct java_event
199 struct list entry;
200 union event_data data;
203 static struct list event_queue = LIST_INIT( event_queue );
204 static struct java_event *current_event;
205 static int event_pipe[2];
206 static DWORD desktop_tid;
208 /***********************************************************************
209 * send_event
211 int send_event( const union event_data *data )
213 int res;
215 if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
217 p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
218 return -1;
220 return 0;
224 /***********************************************************************
225 * desktop_changed
227 * JNI callback, runs in the context of the Java thread.
229 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
231 union event_data data;
233 memset( &data, 0, sizeof(data) );
234 data.type = DESKTOP_CHANGED;
235 data.desktop.width = width;
236 data.desktop.height = height;
237 p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
238 send_event( &data );
242 /***********************************************************************
243 * config_changed
245 * JNI callback, runs in the context of the Java thread.
247 void config_changed( JNIEnv *env, jobject obj, jint dpi )
249 union event_data data;
251 memset( &data, 0, sizeof(data) );
252 data.type = CONFIG_CHANGED;
253 data.cfg.dpi = dpi;
254 p__android_log_print( ANDROID_LOG_INFO, "wine", "config_changed: %u dpi", dpi );
255 send_event( &data );
259 /***********************************************************************
260 * surface_changed
262 * JNI callback, runs in the context of the Java thread.
264 void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jboolean client )
266 union event_data data;
268 memset( &data, 0, sizeof(data) );
269 data.surface.hwnd = LongToHandle( win );
270 data.surface.client = client;
271 if (surface)
273 int width, height;
274 ANativeWindow *win = pANativeWindow_fromSurface( env, surface );
276 if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0;
277 if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0;
278 data.surface.window = win;
279 data.surface.width = width;
280 data.surface.height = height;
281 p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %s %ux%u",
282 data.surface.hwnd, client ? "client" : "whole", width, height );
284 data.type = SURFACE_CHANGED;
285 send_event( &data );
289 /***********************************************************************
290 * motion_event
292 * JNI callback, runs in the context of the Java thread.
294 jboolean motion_event( JNIEnv *env, jobject obj, jint win, jint action, jint x, jint y, jint state, jint vscroll )
296 static LONG button_state;
297 union event_data data;
298 int prev_state;
300 int mask = action & AMOTION_EVENT_ACTION_MASK;
302 if (!( mask == AMOTION_EVENT_ACTION_DOWN ||
303 mask == AMOTION_EVENT_ACTION_UP ||
304 mask == AMOTION_EVENT_ACTION_CANCEL ||
305 mask == AMOTION_EVENT_ACTION_SCROLL ||
306 mask == AMOTION_EVENT_ACTION_MOVE ||
307 mask == AMOTION_EVENT_ACTION_HOVER_MOVE ||
308 mask == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
309 mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE ))
310 return JNI_FALSE;
312 /* make sure a subsequent AMOTION_EVENT_ACTION_UP is not treated as a touch event */
313 if (mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE) state |= 0x80000000;
315 prev_state = InterlockedExchange( &button_state, state );
317 data.type = MOTION_EVENT;
318 data.motion.hwnd = LongToHandle( win );
319 data.motion.input.type = INPUT_MOUSE;
320 data.motion.input.u.mi.dx = x;
321 data.motion.input.u.mi.dy = y;
322 data.motion.input.u.mi.mouseData = 0;
323 data.motion.input.u.mi.time = 0;
324 data.motion.input.u.mi.dwExtraInfo = 0;
325 data.motion.input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
326 switch (action & AMOTION_EVENT_ACTION_MASK)
328 case AMOTION_EVENT_ACTION_DOWN:
329 case AMOTION_EVENT_ACTION_BUTTON_PRESS:
330 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_PRIMARY)
331 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
332 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_SECONDARY)
333 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
334 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_TERTIARY)
335 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
336 if (!(state & ~prev_state)) /* touch event */
337 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
338 break;
339 case AMOTION_EVENT_ACTION_UP:
340 case AMOTION_EVENT_ACTION_CANCEL:
341 case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
342 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_PRIMARY)
343 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
344 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_SECONDARY)
345 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
346 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_TERTIARY)
347 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
348 if (!(prev_state & ~state)) /* touch event */
349 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
350 break;
351 case AMOTION_EVENT_ACTION_SCROLL:
352 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_WHEEL;
353 data.motion.input.u.mi.mouseData = vscroll < 0 ? -WHEEL_DELTA : WHEEL_DELTA;
354 break;
355 case AMOTION_EVENT_ACTION_MOVE:
356 case AMOTION_EVENT_ACTION_HOVER_MOVE:
357 break;
358 default:
359 return JNI_FALSE;
361 send_event( &data );
362 return JNI_TRUE;
366 /***********************************************************************
367 * init_event_queue
369 static void init_event_queue(void)
371 HANDLE handle;
372 int ret;
374 if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
376 ERR( "could not create data\n" );
377 ExitProcess(1);
379 if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
381 ERR( "Can't allocate handle for event fd\n" );
382 ExitProcess(1);
384 SERVER_START_REQ( set_queue_fd )
386 req->handle = wine_server_obj_handle( handle );
387 ret = wine_server_call( req );
389 SERVER_END_REQ;
390 if (ret)
392 ERR( "Can't store handle for event fd %x\n", ret );
393 ExitProcess(1);
395 CloseHandle( handle );
396 desktop_tid = GetCurrentThreadId();
400 /***********************************************************************
401 * pull_events
403 * Pull events from the event pipe and add them to the queue
405 static void pull_events(void)
407 struct java_event *event;
408 int res;
410 for (;;)
412 if (!(event = HeapAlloc( GetProcessHeap(), 0, sizeof(*event) ))) break;
414 res = read( event_pipe[0], &event->data, sizeof(event->data) );
415 if (res != sizeof(event->data)) break;
416 list_add_tail( &event_queue, &event->entry );
418 HeapFree( GetProcessHeap(), 0, event );
422 /***********************************************************************
423 * process_events
425 static int process_events( DWORD mask )
427 DPI_AWARENESS_CONTEXT context;
428 struct java_event *event, *next, *previous;
429 unsigned int count = 0;
431 assert( GetCurrentThreadId() == desktop_tid );
433 pull_events();
435 previous = current_event;
437 LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
439 switch (event->data.type)
441 case SURFACE_CHANGED:
442 break; /* always process it to unblock other threads */
443 case MOTION_EVENT:
444 if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|
445 MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_LEFTUP|
446 MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
448 if (mask & QS_MOUSEBUTTON) break;
450 else if (mask & QS_MOUSEMOVE) break;
451 continue; /* skip it */
452 case KEYBOARD_EVENT:
453 if (mask & QS_KEY) break;
454 continue; /* skip it */
455 default:
456 if (mask & QS_SENDMESSAGE) break;
457 continue; /* skip it */
460 /* remove it first, in case we process events recursively */
461 list_remove( &event->entry );
462 current_event = event;
464 switch (event->data.type)
466 case DESKTOP_CHANGED:
467 TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
468 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
469 screen_width = event->data.desktop.width;
470 screen_height = event->data.desktop.height;
471 init_monitors( screen_width, screen_height );
472 SetWindowPos( GetDesktopWindow(), 0, 0, 0, screen_width, screen_height,
473 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
474 SetThreadDpiAwarenessContext( context );
475 break;
477 case CONFIG_CHANGED:
478 TRACE( "CONFIG_CHANGED dpi %u\n", event->data.cfg.dpi );
479 set_screen_dpi( event->data.cfg.dpi );
480 break;
482 case SURFACE_CHANGED:
483 TRACE("SURFACE_CHANGED %p %p %s size %ux%u\n", event->data.surface.hwnd,
484 event->data.surface.window, event->data.surface.client ? "client" : "whole",
485 event->data.surface.width, event->data.surface.height );
487 register_native_window( event->data.surface.hwnd, event->data.surface.window, event->data.surface.client );
488 break;
490 case MOTION_EVENT:
492 HWND capture = get_capture_window();
494 if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_MIDDLEDOWN))
495 TRACE( "BUTTONDOWN pos %d,%d hwnd %p flags %x\n",
496 event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
497 event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
498 else if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTUP|MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
499 TRACE( "BUTTONUP pos %d,%d hwnd %p flags %x\n",
500 event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
501 event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
502 else
503 TRACE( "MOUSEMOVE pos %d,%d hwnd %p flags %x\n",
504 event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
505 event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
506 if (!capture && (event->data.motion.input.u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE))
508 RECT rect;
509 SetRect( &rect, event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
510 event->data.motion.input.u.mi.dx + 1, event->data.motion.input.u.mi.dy + 1 );
512 SERVER_START_REQ( update_window_zorder )
514 req->window = wine_server_user_handle( event->data.motion.hwnd );
515 req->rect.left = rect.left;
516 req->rect.top = rect.top;
517 req->rect.right = rect.right;
518 req->rect.bottom = rect.bottom;
519 wine_server_call( req );
521 SERVER_END_REQ;
523 __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input );
525 break;
527 case KEYBOARD_EVENT:
528 if (event->data.kbd.input.u.ki.dwFlags & KEYEVENTF_KEYUP)
529 TRACE("KEYUP hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
530 event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk,
531 event->data.kbd.input.u.ki.wScan );
532 else
533 TRACE("KEYDOWN hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
534 event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk,
535 event->data.kbd.input.u.ki.wScan );
536 update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state );
537 __wine_send_input( 0, &event->data.kbd.input );
538 break;
540 default:
541 FIXME( "got event %u\n", event->data.type );
543 HeapFree( GetProcessHeap(), 0, event );
544 count++;
545 /* next may have been removed by a recursive call, so reset it to the beginning of the list */
546 next = LIST_ENTRY( event_queue.next, struct java_event, entry );
548 current_event = previous;
549 return count;
553 /***********************************************************************
554 * wait_events
556 static int wait_events( int timeout )
558 assert( GetCurrentThreadId() == desktop_tid );
560 for (;;)
562 struct pollfd pollfd;
563 int ret;
565 pollfd.fd = event_pipe[0];
566 pollfd.events = POLLIN | POLLHUP;
567 ret = poll( &pollfd, 1, timeout );
568 if (ret == -1 && errno == EINTR) continue;
569 if (ret && (pollfd.revents & (POLLHUP | POLLERR))) ret = -1;
570 return ret;
575 /* Window surface support */
577 struct android_window_surface
579 struct window_surface header;
580 HWND hwnd;
581 ANativeWindow *window;
582 RECT bounds;
583 BOOL byteswap;
584 RGNDATA *region_data;
585 HRGN region;
586 BYTE alpha;
587 COLORREF color_key;
588 void *bits;
589 CRITICAL_SECTION crit;
590 BITMAPINFO info; /* variable size, must be last */
593 static struct android_window_surface *get_android_surface( struct window_surface *surface )
595 return (struct android_window_surface *)surface;
598 static inline void reset_bounds( RECT *bounds )
600 bounds->left = bounds->top = INT_MAX;
601 bounds->right = bounds->bottom = INT_MIN;
604 static inline void add_bounds_rect( RECT *bounds, const RECT *rect )
606 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
607 bounds->left = min( bounds->left, rect->left );
608 bounds->top = min( bounds->top, rect->top );
609 bounds->right = max( bounds->right, rect->right );
610 bounds->bottom = max( bounds->bottom, rect->bottom );
613 /* store the palette or color mask data in the bitmap info structure */
614 static void set_color_info( BITMAPINFO *info, BOOL has_alpha )
616 DWORD *colors = (DWORD *)info->bmiColors;
618 info->bmiHeader.biSize = sizeof(info->bmiHeader);
619 info->bmiHeader.biClrUsed = 0;
620 info->bmiHeader.biBitCount = 32;
621 if (has_alpha)
623 info->bmiHeader.biCompression = BI_RGB;
624 return;
626 info->bmiHeader.biCompression = BI_BITFIELDS;
627 colors[0] = 0xff0000;
628 colors[1] = 0x00ff00;
629 colors[2] = 0x0000ff;
632 /* apply the window region to a single line of the destination image. */
633 static void apply_line_region( DWORD *dst, int width, int x, int y, const RECT *rect, const RECT *end )
635 while (rect < end && rect->top <= y && width > 0)
637 if (rect->left > x)
639 memset( dst, 0, min( rect->left - x, width ) * sizeof(*dst) );
640 dst += rect->left - x;
641 width -= rect->left - x;
642 x = rect->left;
644 if (rect->right > x)
646 dst += rect->right - x;
647 width -= rect->right - x;
648 x = rect->right;
650 rect++;
652 if (width > 0) memset( dst, 0, width * sizeof(*dst) );
655 /***********************************************************************
656 * android_surface_lock
658 static void android_surface_lock( struct window_surface *window_surface )
660 struct android_window_surface *surface = get_android_surface( window_surface );
662 EnterCriticalSection( &surface->crit );
665 /***********************************************************************
666 * android_surface_unlock
668 static void android_surface_unlock( struct window_surface *window_surface )
670 struct android_window_surface *surface = get_android_surface( window_surface );
672 LeaveCriticalSection( &surface->crit );
675 /***********************************************************************
676 * android_surface_get_bitmap_info
678 static void *android_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
680 struct android_window_surface *surface = get_android_surface( window_surface );
682 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
683 return surface->bits;
686 /***********************************************************************
687 * android_surface_get_bounds
689 static RECT *android_surface_get_bounds( struct window_surface *window_surface )
691 struct android_window_surface *surface = get_android_surface( window_surface );
693 return &surface->bounds;
696 /***********************************************************************
697 * android_surface_set_region
699 static void android_surface_set_region( struct window_surface *window_surface, HRGN region )
701 struct android_window_surface *surface = get_android_surface( window_surface );
703 TRACE( "updating surface %p hwnd %p with %p\n", surface, surface->hwnd, region );
705 window_surface->funcs->lock( window_surface );
706 if (!region)
708 if (surface->region) DeleteObject( surface->region );
709 surface->region = 0;
711 else
713 if (!surface->region) surface->region = CreateRectRgn( 0, 0, 0, 0 );
714 CombineRgn( surface->region, region, 0, RGN_COPY );
716 window_surface->funcs->unlock( window_surface );
717 set_surface_region( &surface->header, (HRGN)1 );
720 /***********************************************************************
721 * android_surface_flush
723 static void android_surface_flush( struct window_surface *window_surface )
725 struct android_window_surface *surface = get_android_surface( window_surface );
726 ANativeWindow_Buffer buffer;
727 ARect rc;
728 RECT rect;
729 BOOL needs_flush;
731 window_surface->funcs->lock( window_surface );
732 SetRect( &rect, 0, 0, surface->header.rect.right - surface->header.rect.left,
733 surface->header.rect.bottom - surface->header.rect.top );
734 needs_flush = IntersectRect( &rect, &rect, &surface->bounds );
735 reset_bounds( &surface->bounds );
736 window_surface->funcs->unlock( window_surface );
737 if (!needs_flush) return;
739 TRACE( "flushing %p hwnd %p surface %s rect %s bits %p alpha %02x key %08x region %u rects\n",
740 surface, surface->hwnd, wine_dbgstr_rect( &surface->header.rect ),
741 wine_dbgstr_rect( &rect ), surface->bits, surface->alpha, surface->color_key,
742 surface->region_data ? surface->region_data->rdh.nCount : 0 );
744 rc.left = rect.left;
745 rc.top = rect.top;
746 rc.right = rect.right;
747 rc.bottom = rect.bottom;
749 if (!surface->window->perform( surface->window, NATIVE_WINDOW_LOCK, &buffer, &rc ))
751 const RECT *rgn_rect = NULL, *end = NULL;
752 unsigned int *src, *dst;
753 int x, y, width;
755 rect.left = rc.left;
756 rect.top = rc.top;
757 rect.right = rc.right;
758 rect.bottom = rc.bottom;
759 IntersectRect( &rect, &rect, &surface->header.rect );
761 if (surface->region_data)
763 rgn_rect = (RECT *)surface->region_data->Buffer;
764 end = rgn_rect + surface->region_data->rdh.nCount;
766 src = (unsigned int *)surface->bits
767 + (rect.top - surface->header.rect.top) * surface->info.bmiHeader.biWidth
768 + (rect.left - surface->header.rect.left);
769 dst = (unsigned int *)buffer.bits + rect.top * buffer.stride + rect.left;
770 width = min( rect.right - rect.left, buffer.stride );
772 for (y = rect.top; y < min( buffer.height, rect.bottom); y++)
774 if (surface->info.bmiHeader.biCompression == BI_RGB)
775 memcpy( dst, src, width * sizeof(*dst) );
776 else if (surface->alpha == 255)
777 for (x = 0; x < width; x++) dst[x] = src[x] | 0xff000000;
778 else
779 for (x = 0; x < width; x++)
780 dst[x] = ((surface->alpha << 24) |
781 (((BYTE)(src[x] >> 16) * surface->alpha / 255) << 16) |
782 (((BYTE)(src[x] >> 8) * surface->alpha / 255) << 8) |
783 (((BYTE)src[x] * surface->alpha / 255)));
785 if (surface->color_key != CLR_INVALID)
786 for (x = 0; x < width; x++) if ((src[x] & 0xffffff) == surface->color_key) dst[x] = 0;
788 if (rgn_rect)
790 while (rgn_rect < end && rgn_rect->bottom <= y) rgn_rect++;
791 apply_line_region( dst, width, rect.left, y, rgn_rect, end );
794 src += surface->info.bmiHeader.biWidth;
795 dst += buffer.stride;
797 surface->window->perform( surface->window, NATIVE_WINDOW_UNLOCK_AND_POST );
799 else TRACE( "Unable to lock surface %p window %p buffer %p\n",
800 surface, surface->hwnd, surface->window );
803 /***********************************************************************
804 * android_surface_destroy
806 static void android_surface_destroy( struct window_surface *window_surface )
808 struct android_window_surface *surface = get_android_surface( window_surface );
810 TRACE( "freeing %p bits %p\n", surface, surface->bits );
812 surface->crit.DebugInfo->Spare[0] = 0;
813 DeleteCriticalSection( &surface->crit );
814 HeapFree( GetProcessHeap(), 0, surface->region_data );
815 if (surface->region) DeleteObject( surface->region );
816 release_ioctl_window( surface->window );
817 HeapFree( GetProcessHeap(), 0, surface->bits );
818 HeapFree( GetProcessHeap(), 0, surface );
821 static const struct window_surface_funcs android_surface_funcs =
823 android_surface_lock,
824 android_surface_unlock,
825 android_surface_get_bitmap_info,
826 android_surface_get_bounds,
827 android_surface_set_region,
828 android_surface_flush,
829 android_surface_destroy
832 static BOOL is_argb_surface( struct window_surface *surface )
834 return surface && surface->funcs == &android_surface_funcs &&
835 get_android_surface( surface )->info.bmiHeader.biCompression == BI_RGB;
838 /***********************************************************************
839 * set_color_key
841 static void set_color_key( struct android_window_surface *surface, COLORREF key )
843 if (key == CLR_INVALID)
844 surface->color_key = CLR_INVALID;
845 else if (surface->info.bmiHeader.biBitCount <= 8)
846 surface->color_key = CLR_INVALID;
847 else if (key & (1 << 24)) /* PALETTEINDEX */
848 surface->color_key = 0;
849 else if (key >> 16 == 0x10ff) /* DIBINDEX */
850 surface->color_key = 0;
851 else if (surface->info.bmiHeader.biBitCount == 24)
852 surface->color_key = key;
853 else
854 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
857 /***********************************************************************
858 * set_surface_region
860 static void set_surface_region( struct window_surface *window_surface, HRGN win_region )
862 struct android_window_surface *surface = get_android_surface( window_surface );
863 struct android_win_data *win_data;
864 HRGN region = win_region;
865 RGNDATA *data = NULL;
866 DWORD size;
867 int offset_x, offset_y;
869 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
871 if (!(win_data = get_win_data( surface->hwnd ))) return;
872 offset_x = win_data->window_rect.left - win_data->whole_rect.left;
873 offset_y = win_data->window_rect.top - win_data->whole_rect.top;
874 release_win_data( win_data );
876 if (win_region == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
878 region = CreateRectRgn( 0, 0, win_data->window_rect.right - win_data->window_rect.left,
879 win_data->window_rect.bottom - win_data->window_rect.top );
880 if (GetWindowRgn( surface->hwnd, region ) == ERROR && !surface->region) goto done;
883 OffsetRgn( region, offset_x, offset_y );
884 if (surface->region) CombineRgn( region, region, surface->region, RGN_AND );
886 if (!(size = GetRegionData( region, 0, NULL ))) goto done;
887 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
889 if (!GetRegionData( region, size, data ))
891 HeapFree( GetProcessHeap(), 0, data );
892 data = NULL;
895 done:
896 window_surface->funcs->lock( window_surface );
897 HeapFree( GetProcessHeap(), 0, surface->region_data );
898 surface->region_data = data;
899 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
900 window_surface->funcs->unlock( window_surface );
901 if (region != win_region) DeleteObject( region );
904 /***********************************************************************
905 * create_surface
907 static struct window_surface *create_surface( HWND hwnd, const RECT *rect,
908 BYTE alpha, COLORREF color_key, BOOL src_alpha )
910 struct android_window_surface *surface;
911 int width = rect->right - rect->left, height = rect->bottom - rect->top;
913 surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
914 FIELD_OFFSET( struct android_window_surface, info.bmiColors[3] ));
915 if (!surface) return NULL;
916 set_color_info( &surface->info, src_alpha );
917 surface->info.bmiHeader.biWidth = width;
918 surface->info.bmiHeader.biHeight = -height; /* top-down */
919 surface->info.bmiHeader.biPlanes = 1;
920 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
922 InitializeCriticalSection( &surface->crit );
923 surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
925 surface->header.funcs = &android_surface_funcs;
926 surface->header.rect = *rect;
927 surface->header.ref = 1;
928 surface->hwnd = hwnd;
929 surface->window = get_ioctl_window( hwnd );
930 surface->alpha = alpha;
931 set_color_key( surface, color_key );
932 set_surface_region( &surface->header, (HRGN)1 );
933 reset_bounds( &surface->bounds );
935 if (!(surface->bits = HeapAlloc( GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage )))
936 goto failed;
938 TRACE( "created %p hwnd %p %s bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect),
939 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage );
941 return &surface->header;
943 failed:
944 android_surface_destroy( &surface->header );
945 return NULL;
948 /***********************************************************************
949 * set_surface_layered
951 static void set_surface_layered( struct window_surface *window_surface, BYTE alpha, COLORREF color_key )
953 struct android_window_surface *surface = get_android_surface( window_surface );
954 COLORREF prev_key;
955 BYTE prev_alpha;
957 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
959 window_surface->funcs->lock( window_surface );
960 prev_key = surface->color_key;
961 prev_alpha = surface->alpha;
962 surface->alpha = alpha;
963 set_color_key( surface, color_key );
964 if (alpha != prev_alpha || surface->color_key != prev_key) /* refresh */
965 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
966 window_surface->funcs->unlock( window_surface );
970 static WNDPROC desktop_orig_wndproc;
972 static LRESULT CALLBACK desktop_wndproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
974 switch (msg)
976 case WM_PARENTNOTIFY:
977 if (LOWORD(wp) == WM_DESTROY) destroy_ioctl_window( (HWND)lp, FALSE );
978 break;
980 return desktop_orig_wndproc( hwnd, msg, wp, lp );
984 /***********************************************************************
985 * ANDROID_MsgWaitForMultipleObjectsEx
987 DWORD CDECL ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
988 DWORD timeout, DWORD mask, DWORD flags )
990 if (GetCurrentThreadId() == desktop_tid)
992 /* don't process nested events */
993 if (current_event) mask = 0;
994 if (process_events( mask )) return count - 1;
996 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
997 timeout, flags & MWMO_ALERTABLE );
1000 /**********************************************************************
1001 * ANDROID_CreateWindow
1003 BOOL CDECL ANDROID_CreateWindow( HWND hwnd )
1005 TRACE( "%p\n", hwnd );
1007 if (hwnd == GetDesktopWindow())
1009 struct android_win_data *data;
1011 init_event_queue();
1012 start_android_device();
1013 if (!(data = alloc_win_data( hwnd ))) return FALSE;
1014 release_win_data( data );
1016 return TRUE;
1020 /***********************************************************************
1021 * ANDROID_DestroyWindow
1023 void CDECL ANDROID_DestroyWindow( HWND hwnd )
1025 struct android_win_data *data;
1027 if (!(data = get_win_data( hwnd ))) return;
1029 if (data->surface) window_surface_release( data->surface );
1030 data->surface = NULL;
1031 destroy_gl_drawable( hwnd );
1032 free_win_data( data );
1036 /***********************************************************************
1037 * create_win_data
1039 * Create a data window structure for an existing window.
1041 static struct android_win_data *create_win_data( HWND hwnd, const RECT *window_rect,
1042 const RECT *client_rect )
1044 struct android_win_data *data;
1045 HWND parent;
1047 if (!(parent = GetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop or HWND_MESSAGE */
1049 if (!(data = alloc_win_data( hwnd ))) return NULL;
1051 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
1052 data->whole_rect = data->window_rect = *window_rect;
1053 data->client_rect = *client_rect;
1054 return data;
1058 static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rect )
1060 if (!IntersectRect( surface_rect, visible_rect, &virtual_screen_rect )) return FALSE;
1061 OffsetRect( surface_rect, -visible_rect->left, -visible_rect->top );
1062 surface_rect->left &= ~31;
1063 surface_rect->top &= ~31;
1064 surface_rect->right = max( surface_rect->left + 32, (surface_rect->right + 31) & ~31 );
1065 surface_rect->bottom = max( surface_rect->top + 32, (surface_rect->bottom + 31) & ~31 );
1066 return TRUE;
1070 /***********************************************************************
1071 * ANDROID_WindowPosChanging
1073 void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
1074 const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
1075 struct window_surface **surface )
1077 struct android_win_data *data = get_win_data( hwnd );
1078 RECT surface_rect;
1079 DWORD flags;
1080 COLORREF key;
1081 BYTE alpha;
1082 BOOL layered = GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED;
1084 TRACE( "win %p window %s client %s style %08x flags %08x\n",
1085 hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1086 GetWindowLongW( hwnd, GWL_STYLE ), swp_flags );
1088 if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return;
1090 *visible_rect = *window_rect;
1092 /* create the window surface if necessary */
1094 if (data->parent) goto done;
1095 if (swp_flags & SWP_HIDEWINDOW) goto done;
1096 if (is_argb_surface( data->surface )) goto done;
1097 if (!get_surface_rect( visible_rect, &surface_rect )) goto done;
1099 if (data->surface)
1101 if (!memcmp( &data->surface->rect, &surface_rect, sizeof(surface_rect) ))
1103 /* existing surface is good enough */
1104 window_surface_add_ref( data->surface );
1105 if (*surface) window_surface_release( *surface );
1106 *surface = data->surface;
1107 goto done;
1110 if (!(swp_flags & SWP_SHOWWINDOW) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) goto done;
1112 if (!layered || !GetLayeredWindowAttributes( hwnd, &key, &alpha, &flags )) flags = 0;
1113 if (!(flags & LWA_ALPHA)) alpha = 255;
1114 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1116 if (*surface) window_surface_release( *surface );
1117 *surface = create_surface( data->hwnd, &surface_rect, alpha, key, FALSE );
1119 done:
1120 release_win_data( data );
1124 /***********************************************************************
1125 * ANDROID_WindowPosChanged
1127 void CDECL ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
1128 const RECT *window_rect, const RECT *client_rect,
1129 const RECT *visible_rect, const RECT *valid_rects,
1130 struct window_surface *surface )
1132 struct android_win_data *data;
1133 DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
1134 HWND owner = 0;
1136 if (!(data = get_win_data( hwnd ))) return;
1138 data->window_rect = *window_rect;
1139 data->whole_rect = *visible_rect;
1140 data->client_rect = *client_rect;
1142 if (!is_argb_surface( data->surface ))
1144 if (surface) window_surface_add_ref( surface );
1145 if (data->surface) window_surface_release( data->surface );
1146 data->surface = surface;
1148 if (!data->parent) owner = GetWindow( hwnd, GW_OWNER );
1149 release_win_data( data );
1151 if (!(swp_flags & SWP_NOZORDER)) insert_after = GetWindow( hwnd, GW_HWNDPREV );
1153 TRACE( "win %p window %s client %s style %08x owner %p after %p flags %08x\n", hwnd,
1154 wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1155 new_style, owner, insert_after, swp_flags );
1157 ioctl_window_pos_changed( hwnd, window_rect, client_rect, visible_rect,
1158 new_style, swp_flags, insert_after, owner );
1162 /***********************************************************************
1163 * ANDROID_ShowWindow
1165 UINT CDECL ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
1167 if (IsRectEmpty( rect )) return swp;
1168 if (!IsIconic( hwnd )) return swp;
1169 /* always hide icons off-screen */
1170 if (rect->left != -32000 || rect->top != -32000)
1172 OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
1173 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1175 return swp;
1179 /*****************************************************************
1180 * ANDROID_SetParent
1182 void CDECL ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent )
1184 struct android_win_data *data;
1186 if (parent == old_parent) return;
1187 if (!(data = get_win_data( hwnd ))) return;
1189 TRACE( "win %p parent %p -> %p\n", hwnd, old_parent, parent );
1191 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
1192 ioctl_set_window_parent( hwnd, parent, (float)get_win_monitor_dpi( hwnd ) / GetDpiForWindow( hwnd ));
1193 release_win_data( data );
1197 /***********************************************************************
1198 * ANDROID_SetCapture
1200 void CDECL ANDROID_SetCapture( HWND hwnd, UINT flags )
1202 if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
1203 ioctl_set_capture( hwnd );
1207 /***********************************************************************
1208 * ANDROID_SetWindowStyle
1210 void CDECL ANDROID_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
1212 struct android_win_data *data;
1213 DWORD changed = style->styleNew ^ style->styleOld;
1215 if (hwnd == GetDesktopWindow()) return;
1216 if (!(data = get_win_data( hwnd ))) return;
1218 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1220 if (is_argb_surface( data->surface ))
1222 if (data->surface) window_surface_release( data->surface );
1223 data->surface = NULL;
1225 else if (data->surface) set_surface_layered( data->surface, 255, CLR_INVALID );
1227 release_win_data( data );
1231 /***********************************************************************
1232 * ANDROID_SetWindowRgn
1234 void CDECL ANDROID_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1236 struct android_win_data *data;
1238 if ((data = get_win_data( hwnd )))
1240 if (data->surface) set_surface_region( data->surface, hrgn );
1241 release_win_data( data );
1243 else FIXME( "not supported on other process window %p\n", hwnd );
1247 /***********************************************************************
1248 * ANDROID_SetLayeredWindowAttributes
1250 void CDECL ANDROID_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
1252 struct android_win_data *data;
1254 if (!(flags & LWA_ALPHA)) alpha = 255;
1255 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1257 if ((data = get_win_data( hwnd )))
1259 if (data->surface) set_surface_layered( data->surface, alpha, key );
1260 release_win_data( data );
1265 /*****************************************************************************
1266 * ANDROID_UpdateLayeredWindow
1268 BOOL CDECL ANDROID_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1269 const RECT *window_rect )
1271 struct window_surface *surface;
1272 struct android_win_data *data;
1273 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1274 COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
1275 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1276 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1277 void *src_bits, *dst_bits;
1278 RECT rect, src_rect;
1279 HDC hdc = 0;
1280 HBITMAP dib;
1281 BOOL ret = FALSE;
1283 if (!(data = get_win_data( hwnd ))) return FALSE;
1285 rect = *window_rect;
1286 OffsetRect( &rect, -window_rect->left, -window_rect->top );
1288 surface = data->surface;
1289 if (!is_argb_surface( surface ))
1291 if (surface) window_surface_release( surface );
1292 surface = NULL;
1295 if (!surface || !EqualRect( &surface->rect, &rect ))
1297 data->surface = create_surface( data->hwnd, &rect, 255, color_key, TRUE );
1298 if (surface) window_surface_release( surface );
1299 surface = data->surface;
1301 else set_surface_layered( surface, 255, color_key );
1303 if (surface) window_surface_add_ref( surface );
1304 release_win_data( data );
1306 if (!surface) return FALSE;
1307 if (!info->hdcSrc)
1309 window_surface_release( surface );
1310 return TRUE;
1313 dst_bits = surface->funcs->get_info( surface, bmi );
1315 if (!(dib = CreateDIBSection( info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0 ))) goto done;
1316 if (!(hdc = CreateCompatibleDC( 0 ))) goto done;
1318 SelectObject( hdc, dib );
1320 surface->funcs->lock( surface );
1322 if (info->prcDirty)
1324 IntersectRect( &rect, &rect, info->prcDirty );
1325 memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage );
1326 PatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS );
1328 src_rect = rect;
1329 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1330 DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 );
1332 ret = GdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1333 info->hdcSrc, src_rect.left, src_rect.top,
1334 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1335 (info->dwFlags & ULW_ALPHA) ? *info->pblend : blend );
1336 if (ret)
1338 memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage );
1339 add_bounds_rect( surface->funcs->get_bounds( surface ), &rect );
1342 surface->funcs->unlock( surface );
1343 surface->funcs->flush( surface );
1345 done:
1346 window_surface_release( surface );
1347 if (hdc) DeleteDC( hdc );
1348 if (dib) DeleteObject( dib );
1349 return ret;
1353 /**********************************************************************
1354 * ANDROID_WindowMessage
1356 LRESULT CDECL ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1358 struct android_win_data *data;
1360 switch (msg)
1362 case WM_ANDROID_REFRESH:
1363 if (wp) /* opengl client window */
1365 update_gl_drawable( hwnd );
1367 else if ((data = get_win_data( hwnd )))
1369 struct window_surface *surface = data->surface;
1370 if (surface)
1372 surface->funcs->lock( surface );
1373 *surface->funcs->get_bounds( surface ) = surface->rect;
1374 surface->funcs->unlock( surface );
1375 if (is_argb_surface( surface )) surface->funcs->flush( surface );
1377 release_win_data( data );
1379 return 0;
1380 default:
1381 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
1382 return 0;
1387 /***********************************************************************
1388 * ANDROID_create_desktop
1390 BOOL CDECL ANDROID_create_desktop( UINT width, UINT height )
1392 desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( GetDesktopWindow(), GWLP_WNDPROC,
1393 (LONG_PTR)desktop_wndproc_wrapper );
1395 /* wait until we receive the surface changed event */
1396 while (!screen_width)
1398 if (wait_events( 2000 ) != 1)
1400 ERR( "wait timed out\n" );
1401 break;
1403 process_events( QS_ALLINPUT );
1405 return TRUE;