wineandroid: The event list may have been altered by a recursive call, so restart...
[wine.git] / dlls / wineandroid.drv / window.c
blobe3fd865daaa3d37e900a4872f14ac32dd8b43429
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 * alloc_win_data
109 static struct android_win_data *alloc_win_data( HWND hwnd )
111 struct android_win_data *data;
113 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
115 data->hwnd = hwnd;
116 data->window = create_ioctl_window( hwnd );
117 EnterCriticalSection( &win_data_section );
118 win_data_context[context_idx(hwnd)] = data;
120 return data;
124 /***********************************************************************
125 * free_win_data
127 static void free_win_data( struct android_win_data *data )
129 win_data_context[context_idx( data->hwnd )] = NULL;
130 LeaveCriticalSection( &win_data_section );
131 if (data->window) release_ioctl_window( data->window );
132 HeapFree( GetProcessHeap(), 0, data );
136 /***********************************************************************
137 * get_win_data
139 * Lock and return the data structure associated with a window.
141 static struct android_win_data *get_win_data( HWND hwnd )
143 struct android_win_data *data;
145 if (!hwnd) return NULL;
146 EnterCriticalSection( &win_data_section );
147 if ((data = win_data_context[context_idx(hwnd)]) && data->hwnd == hwnd) return data;
148 LeaveCriticalSection( &win_data_section );
149 return NULL;
153 /***********************************************************************
154 * release_win_data
156 * Release the data returned by get_win_data.
158 static void release_win_data( struct android_win_data *data )
160 if (data) LeaveCriticalSection( &win_data_section );
164 /***********************************************************************
165 * get_ioctl_window
167 static struct ANativeWindow *get_ioctl_window( HWND hwnd )
169 struct ANativeWindow *ret;
170 struct android_win_data *data = get_win_data( hwnd );
172 if (!data || !data->window) return NULL;
173 ret = grab_ioctl_window( data->window );
174 release_win_data( data );
175 return ret;
179 /* Handling of events coming from the Java side */
181 struct java_event
183 struct list entry;
184 union event_data data;
187 static struct list event_queue = LIST_INIT( event_queue );
188 static struct java_event *current_event;
189 static int event_pipe[2];
190 static DWORD desktop_tid;
192 /***********************************************************************
193 * send_event
195 int send_event( const union event_data *data )
197 int res;
199 if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
201 p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
202 return -1;
204 return 0;
208 /***********************************************************************
209 * desktop_changed
211 * JNI callback, runs in the context of the Java thread.
213 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
215 union event_data data;
217 memset( &data, 0, sizeof(data) );
218 data.type = DESKTOP_CHANGED;
219 data.desktop.width = width;
220 data.desktop.height = height;
221 p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
222 send_event( &data );
226 /***********************************************************************
227 * surface_changed
229 * JNI callback, runs in the context of the Java thread.
231 void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface )
233 union event_data data;
235 memset( &data, 0, sizeof(data) );
236 data.surface.hwnd = LongToHandle( win );
237 if (surface)
239 int width, height;
240 ANativeWindow *win = pANativeWindow_fromSurface( env, surface );
242 if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0;
243 if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0;
244 data.surface.window = win;
245 data.surface.width = width;
246 data.surface.height = height;
247 p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %ux%u",
248 data.surface.hwnd, width, height );
250 data.type = SURFACE_CHANGED;
251 send_event( &data );
255 /***********************************************************************
256 * init_event_queue
258 static void init_event_queue(void)
260 HANDLE handle;
261 int ret;
263 if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
265 ERR( "could not create data\n" );
266 ExitProcess(1);
268 if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
270 ERR( "Can't allocate handle for event fd\n" );
271 ExitProcess(1);
273 SERVER_START_REQ( set_queue_fd )
275 req->handle = wine_server_obj_handle( handle );
276 ret = wine_server_call( req );
278 SERVER_END_REQ;
279 if (ret)
281 ERR( "Can't store handle for event fd %x\n", ret );
282 ExitProcess(1);
284 CloseHandle( handle );
285 desktop_tid = GetCurrentThreadId();
289 /***********************************************************************
290 * pull_events
292 * Pull events from the event pipe and add them to the queue
294 static void pull_events(void)
296 struct java_event *event;
297 int res;
299 for (;;)
301 if (!(event = HeapAlloc( GetProcessHeap(), 0, sizeof(*event) ))) break;
303 res = read( event_pipe[0], &event->data, sizeof(event->data) );
304 if (res != sizeof(event->data)) break;
305 list_add_tail( &event_queue, &event->entry );
307 HeapFree( GetProcessHeap(), 0, event );
311 /***********************************************************************
312 * process_events
314 static int process_events( DWORD mask )
316 struct java_event *event, *next, *previous;
317 unsigned int count = 0;
319 assert( GetCurrentThreadId() == desktop_tid );
321 pull_events();
323 previous = current_event;
325 LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
327 switch (event->data.type)
329 case SURFACE_CHANGED:
330 break; /* always process it to unblock other threads */
331 default:
332 if (mask & QS_SENDMESSAGE) break;
333 continue; /* skip it */
336 /* remove it first, in case we process events recursively */
337 list_remove( &event->entry );
338 current_event = event;
340 switch (event->data.type)
342 case DESKTOP_CHANGED:
343 TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
344 screen_width = event->data.desktop.width;
345 screen_height = event->data.desktop.height;
346 init_monitors( screen_width, screen_height );
347 SetWindowPos( GetDesktopWindow(), 0, 0, 0, screen_width, screen_height,
348 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
349 break;
351 case SURFACE_CHANGED:
352 TRACE("SURFACE_CHANGED %p %p size %ux%u\n", event->data.surface.hwnd,
353 event->data.surface.window, event->data.surface.width, event->data.surface.height );
355 register_native_window( event->data.surface.hwnd, event->data.surface.window );
356 break;
358 default:
359 FIXME( "got event %u\n", event->data.type );
361 HeapFree( GetProcessHeap(), 0, event );
362 count++;
363 /* next may have been removed by a recursive call, so reset it to the beginning of the list */
364 next = LIST_ENTRY( event_queue.next, struct java_event, entry );
366 current_event = previous;
367 return count;
371 /***********************************************************************
372 * wait_events
374 static int wait_events( int timeout )
376 assert( GetCurrentThreadId() == desktop_tid );
378 for (;;)
380 struct pollfd pollfd;
381 int ret;
383 pollfd.fd = event_pipe[0];
384 pollfd.events = POLLIN | POLLHUP;
385 ret = poll( &pollfd, 1, timeout );
386 if (ret == -1 && errno == EINTR) continue;
387 if (ret && (pollfd.revents & (POLLHUP | POLLERR))) ret = -1;
388 return ret;
393 /* Window surface support */
395 struct android_window_surface
397 struct window_surface header;
398 HWND hwnd;
399 ANativeWindow *window;
400 RECT bounds;
401 BOOL byteswap;
402 RGNDATA *region_data;
403 HRGN region;
404 BYTE alpha;
405 COLORREF color_key;
406 void *bits;
407 CRITICAL_SECTION crit;
408 BITMAPINFO info; /* variable size, must be last */
411 static struct android_window_surface *get_android_surface( struct window_surface *surface )
413 return (struct android_window_surface *)surface;
416 static inline void reset_bounds( RECT *bounds )
418 bounds->left = bounds->top = INT_MAX;
419 bounds->right = bounds->bottom = INT_MIN;
422 static inline void add_bounds_rect( RECT *bounds, const RECT *rect )
424 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
425 bounds->left = min( bounds->left, rect->left );
426 bounds->top = min( bounds->top, rect->top );
427 bounds->right = max( bounds->right, rect->right );
428 bounds->bottom = max( bounds->bottom, rect->bottom );
431 /* store the palette or color mask data in the bitmap info structure */
432 static void set_color_info( BITMAPINFO *info, BOOL has_alpha )
434 DWORD *colors = (DWORD *)info->bmiColors;
436 info->bmiHeader.biSize = sizeof(info->bmiHeader);
437 info->bmiHeader.biClrUsed = 0;
438 info->bmiHeader.biBitCount = 32;
439 if (has_alpha)
441 info->bmiHeader.biCompression = BI_RGB;
442 return;
444 info->bmiHeader.biCompression = BI_BITFIELDS;
445 colors[0] = 0xff0000;
446 colors[1] = 0x00ff00;
447 colors[2] = 0x0000ff;
450 /* apply the window region to a single line of the destination image. */
451 static void apply_line_region( DWORD *dst, int width, int x, int y, const RECT *rect, const RECT *end )
453 while (rect < end && rect->top <= y && width > 0)
455 if (rect->left > x)
457 memset( dst, 0, min( rect->left - x, width ) * sizeof(*dst) );
458 dst += rect->left - x;
459 width -= rect->left - x;
460 x = rect->left;
462 if (rect->right > x)
464 dst += rect->right - x;
465 width -= rect->right - x;
466 x = rect->right;
468 rect++;
470 if (width > 0) memset( dst, 0, width * sizeof(*dst) );
473 /***********************************************************************
474 * android_surface_lock
476 static void android_surface_lock( struct window_surface *window_surface )
478 struct android_window_surface *surface = get_android_surface( window_surface );
480 EnterCriticalSection( &surface->crit );
483 /***********************************************************************
484 * android_surface_unlock
486 static void android_surface_unlock( struct window_surface *window_surface )
488 struct android_window_surface *surface = get_android_surface( window_surface );
490 LeaveCriticalSection( &surface->crit );
493 /***********************************************************************
494 * android_surface_get_bitmap_info
496 static void *android_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
498 struct android_window_surface *surface = get_android_surface( window_surface );
500 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
501 return surface->bits;
504 /***********************************************************************
505 * android_surface_get_bounds
507 static RECT *android_surface_get_bounds( struct window_surface *window_surface )
509 struct android_window_surface *surface = get_android_surface( window_surface );
511 return &surface->bounds;
514 /***********************************************************************
515 * android_surface_set_region
517 static void android_surface_set_region( struct window_surface *window_surface, HRGN region )
519 struct android_window_surface *surface = get_android_surface( window_surface );
521 TRACE( "updating surface %p hwnd %p with %p\n", surface, surface->hwnd, region );
523 window_surface->funcs->lock( window_surface );
524 if (!region)
526 if (surface->region) DeleteObject( surface->region );
527 surface->region = 0;
529 else
531 if (!surface->region) surface->region = CreateRectRgn( 0, 0, 0, 0 );
532 CombineRgn( surface->region, region, 0, RGN_COPY );
534 window_surface->funcs->unlock( window_surface );
535 set_surface_region( &surface->header, (HRGN)1 );
538 /***********************************************************************
539 * android_surface_flush
541 static void android_surface_flush( struct window_surface *window_surface )
543 struct android_window_surface *surface = get_android_surface( window_surface );
544 ANativeWindow_Buffer buffer;
545 ARect rc;
546 RECT rect;
547 BOOL needs_flush;
549 window_surface->funcs->lock( window_surface );
550 SetRect( &rect, 0, 0, surface->header.rect.right - surface->header.rect.left,
551 surface->header.rect.bottom - surface->header.rect.top );
552 needs_flush = IntersectRect( &rect, &rect, &surface->bounds );
553 reset_bounds( &surface->bounds );
554 window_surface->funcs->unlock( window_surface );
555 if (!needs_flush) return;
557 TRACE( "flushing %p hwnd %p surface %s rect %s bits %p alpha %02x key %08x region %u rects\n",
558 surface, surface->hwnd, wine_dbgstr_rect( &surface->header.rect ),
559 wine_dbgstr_rect( &rect ), surface->bits, surface->alpha, surface->color_key,
560 surface->region_data ? surface->region_data->rdh.nCount : 0 );
562 rc.left = rect.left;
563 rc.top = rect.top;
564 rc.right = rect.right;
565 rc.bottom = rect.bottom;
567 if (!surface->window->perform( surface->window, NATIVE_WINDOW_LOCK, &buffer, &rc ))
569 const RECT *rgn_rect = NULL, *end = NULL;
570 unsigned int *src, *dst;
571 int x, y, width;
573 rect.left = rc.left;
574 rect.top = rc.top;
575 rect.right = rc.right;
576 rect.bottom = rc.bottom;
577 IntersectRect( &rect, &rect, &surface->header.rect );
579 if (surface->region_data)
581 rgn_rect = (RECT *)surface->region_data->Buffer;
582 end = rgn_rect + surface->region_data->rdh.nCount;
584 src = (unsigned int *)surface->bits
585 + (rect.top - surface->header.rect.top) * surface->info.bmiHeader.biWidth
586 + (rect.left - surface->header.rect.left);
587 dst = (unsigned int *)buffer.bits + rect.top * buffer.stride + rect.left;
588 width = min( rect.right - rect.left, buffer.stride );
590 for (y = rect.top; y < min( buffer.height, rect.bottom); y++)
592 if (surface->info.bmiHeader.biCompression == BI_RGB)
593 memcpy( dst, src, width * sizeof(*dst) );
594 else if (surface->alpha == 255)
595 for (x = 0; x < width; x++) dst[x] = src[x] | 0xff000000;
596 else
597 for (x = 0; x < width; x++)
598 dst[x] = ((surface->alpha << 24) |
599 (((BYTE)(src[x] >> 16) * surface->alpha / 255) << 16) |
600 (((BYTE)(src[x] >> 8) * surface->alpha / 255) << 8) |
601 (((BYTE)src[x] * surface->alpha / 255)));
603 if (surface->color_key != CLR_INVALID)
604 for (x = 0; x < width; x++) if ((src[x] & 0xffffff) == surface->color_key) dst[x] = 0;
606 if (rgn_rect)
608 while (rgn_rect < end && rgn_rect->bottom <= y) rgn_rect++;
609 apply_line_region( dst, width, rect.left, y, rgn_rect, end );
612 src += surface->info.bmiHeader.biWidth;
613 dst += buffer.stride;
615 surface->window->perform( surface->window, NATIVE_WINDOW_UNLOCK_AND_POST );
617 else TRACE( "Unable to lock surface %p window %p buffer %p\n",
618 surface, surface->hwnd, surface->window );
621 /***********************************************************************
622 * android_surface_destroy
624 static void android_surface_destroy( struct window_surface *window_surface )
626 struct android_window_surface *surface = get_android_surface( window_surface );
628 TRACE( "freeing %p bits %p\n", surface, surface->bits );
630 surface->crit.DebugInfo->Spare[0] = 0;
631 DeleteCriticalSection( &surface->crit );
632 HeapFree( GetProcessHeap(), 0, surface->region_data );
633 if (surface->region) DeleteObject( surface->region );
634 release_ioctl_window( surface->window );
635 HeapFree( GetProcessHeap(), 0, surface->bits );
636 HeapFree( GetProcessHeap(), 0, surface );
639 static const struct window_surface_funcs android_surface_funcs =
641 android_surface_lock,
642 android_surface_unlock,
643 android_surface_get_bitmap_info,
644 android_surface_get_bounds,
645 android_surface_set_region,
646 android_surface_flush,
647 android_surface_destroy
650 static BOOL is_argb_surface( struct window_surface *surface )
652 return surface && surface->funcs == &android_surface_funcs &&
653 get_android_surface( surface )->info.bmiHeader.biCompression == BI_RGB;
656 /***********************************************************************
657 * set_color_key
659 static void set_color_key( struct android_window_surface *surface, COLORREF key )
661 if (key == CLR_INVALID)
662 surface->color_key = CLR_INVALID;
663 else if (surface->info.bmiHeader.biBitCount <= 8)
664 surface->color_key = CLR_INVALID;
665 else if (key & (1 << 24)) /* PALETTEINDEX */
666 surface->color_key = 0;
667 else if (key >> 16 == 0x10ff) /* DIBINDEX */
668 surface->color_key = 0;
669 else if (surface->info.bmiHeader.biBitCount == 24)
670 surface->color_key = key;
671 else
672 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
675 /***********************************************************************
676 * set_surface_region
678 static void set_surface_region( struct window_surface *window_surface, HRGN win_region )
680 struct android_window_surface *surface = get_android_surface( window_surface );
681 struct android_win_data *win_data;
682 HRGN region = win_region;
683 RGNDATA *data = NULL;
684 DWORD size;
685 int offset_x, offset_y;
687 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
689 if (!(win_data = get_win_data( surface->hwnd ))) return;
690 offset_x = win_data->window_rect.left - win_data->whole_rect.left;
691 offset_y = win_data->window_rect.top - win_data->whole_rect.top;
692 release_win_data( win_data );
694 if (win_region == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
696 region = CreateRectRgn( 0, 0, win_data->window_rect.right - win_data->window_rect.left,
697 win_data->window_rect.bottom - win_data->window_rect.top );
698 if (GetWindowRgn( surface->hwnd, region ) == ERROR && !surface->region) goto done;
701 OffsetRgn( region, offset_x, offset_y );
702 if (surface->region) CombineRgn( region, region, surface->region, RGN_AND );
704 if (!(size = GetRegionData( region, 0, NULL ))) goto done;
705 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
707 if (!GetRegionData( region, size, data ))
709 HeapFree( GetProcessHeap(), 0, data );
710 data = NULL;
713 done:
714 window_surface->funcs->lock( window_surface );
715 HeapFree( GetProcessHeap(), 0, surface->region_data );
716 surface->region_data = data;
717 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
718 window_surface->funcs->unlock( window_surface );
719 if (region != win_region) DeleteObject( region );
722 /***********************************************************************
723 * create_surface
725 static struct window_surface *create_surface( HWND hwnd, const RECT *rect,
726 BYTE alpha, COLORREF color_key, BOOL src_alpha )
728 struct android_window_surface *surface;
729 int width = rect->right - rect->left, height = rect->bottom - rect->top;
731 surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
732 FIELD_OFFSET( struct android_window_surface, info.bmiColors[3] ));
733 if (!surface) return NULL;
734 set_color_info( &surface->info, src_alpha );
735 surface->info.bmiHeader.biWidth = width;
736 surface->info.bmiHeader.biHeight = -height; /* top-down */
737 surface->info.bmiHeader.biPlanes = 1;
738 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
740 InitializeCriticalSection( &surface->crit );
741 surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
743 surface->header.funcs = &android_surface_funcs;
744 surface->header.rect = *rect;
745 surface->header.ref = 1;
746 surface->hwnd = hwnd;
747 surface->window = get_ioctl_window( hwnd );
748 surface->alpha = alpha;
749 set_color_key( surface, color_key );
750 set_surface_region( &surface->header, (HRGN)1 );
751 reset_bounds( &surface->bounds );
753 if (!(surface->bits = HeapAlloc( GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage )))
754 goto failed;
756 TRACE( "created %p hwnd %p %s bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect),
757 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage );
759 return &surface->header;
761 failed:
762 android_surface_destroy( &surface->header );
763 return NULL;
766 /***********************************************************************
767 * set_surface_layered
769 static void set_surface_layered( struct window_surface *window_surface, BYTE alpha, COLORREF color_key )
771 struct android_window_surface *surface = get_android_surface( window_surface );
772 COLORREF prev_key;
773 BYTE prev_alpha;
775 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
777 window_surface->funcs->lock( window_surface );
778 prev_key = surface->color_key;
779 prev_alpha = surface->alpha;
780 surface->alpha = alpha;
781 set_color_key( surface, color_key );
782 if (alpha != prev_alpha || surface->color_key != prev_key) /* refresh */
783 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
784 window_surface->funcs->unlock( window_surface );
788 static WNDPROC desktop_orig_wndproc;
790 static LRESULT CALLBACK desktop_wndproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
792 switch (msg)
794 case WM_PARENTNOTIFY:
795 if (LOWORD(wp) == WM_DESTROY) destroy_ioctl_window( (HWND)lp );
796 break;
798 return desktop_orig_wndproc( hwnd, msg, wp, lp );
802 /***********************************************************************
803 * ANDROID_MsgWaitForMultipleObjectsEx
805 DWORD CDECL ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
806 DWORD timeout, DWORD mask, DWORD flags )
808 if (GetCurrentThreadId() == desktop_tid)
810 /* don't process nested events */
811 if (current_event) mask = 0;
812 if (process_events( mask )) return count - 1;
814 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
815 timeout, flags & MWMO_ALERTABLE );
818 /**********************************************************************
819 * ANDROID_CreateWindow
821 BOOL CDECL ANDROID_CreateWindow( HWND hwnd )
823 TRACE( "%p\n", hwnd );
825 if (hwnd == GetDesktopWindow())
827 struct android_win_data *data;
829 init_event_queue();
830 start_android_device();
831 desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC,
832 (LONG_PTR)desktop_wndproc_wrapper );
833 if (!(data = alloc_win_data( hwnd ))) return FALSE;
834 release_win_data( data );
836 return TRUE;
840 /***********************************************************************
841 * ANDROID_DestroyWindow
843 void CDECL ANDROID_DestroyWindow( HWND hwnd )
845 struct android_win_data *data;
847 if (!(data = get_win_data( hwnd ))) return;
849 if (data->surface) window_surface_release( data->surface );
850 data->surface = NULL;
851 free_win_data( data );
855 /***********************************************************************
856 * create_win_data
858 * Create a data window structure for an existing window.
860 static struct android_win_data *create_win_data( HWND hwnd, const RECT *window_rect,
861 const RECT *client_rect )
863 struct android_win_data *data;
864 HWND parent;
866 if (!(parent = GetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop or HWND_MESSAGE */
868 if (parent != GetDesktopWindow())
870 if (!(data = get_win_data( parent )) &&
871 !(data = create_win_data( parent, NULL, NULL )))
872 return NULL;
873 release_win_data( data );
876 if (!(data = alloc_win_data( hwnd ))) return NULL;
878 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
880 if (window_rect)
882 data->whole_rect = data->window_rect = *window_rect;
883 data->client_rect = *client_rect;
885 else
887 GetWindowRect( hwnd, &data->window_rect );
888 MapWindowPoints( 0, parent, (POINT *)&data->window_rect, 2 );
889 data->whole_rect = data->window_rect;
890 GetClientRect( hwnd, &data->client_rect );
891 MapWindowPoints( hwnd, parent, (POINT *)&data->client_rect, 2 );
892 ioctl_window_pos_changed( hwnd, &data->window_rect, &data->client_rect, &data->whole_rect,
893 GetWindowLongW( hwnd, GWL_STYLE ), SWP_NOACTIVATE,
894 GetWindow( hwnd, GW_HWNDPREV ), GetWindow( hwnd, GW_OWNER ));
896 return data;
900 static inline RECT get_surface_rect( const RECT *visible_rect )
902 RECT rect;
904 IntersectRect( &rect, visible_rect, &virtual_screen_rect );
905 OffsetRect( &rect, -visible_rect->left, -visible_rect->top );
906 rect.left &= ~31;
907 rect.top &= ~31;
908 rect.right = max( rect.left + 32, (rect.right + 31) & ~31 );
909 rect.bottom = max( rect.top + 32, (rect.bottom + 31) & ~31 );
910 return rect;
914 /***********************************************************************
915 * ANDROID_WindowPosChanging
917 void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
918 const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
919 struct window_surface **surface )
921 struct android_win_data *data = get_win_data( hwnd );
922 RECT surface_rect;
923 DWORD flags;
924 COLORREF key;
925 BYTE alpha;
926 BOOL layered = GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED;
928 TRACE( "win %p window %s client %s style %08x flags %08x\n",
929 hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
930 GetWindowLongW( hwnd, GWL_STYLE ), swp_flags );
932 if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return;
934 *visible_rect = *window_rect;
936 /* create the window surface if necessary */
938 if (data->parent) goto done;
939 if (swp_flags & SWP_HIDEWINDOW) goto done;
940 if (is_argb_surface( data->surface )) goto done;
942 surface_rect = get_surface_rect( visible_rect );
943 if (data->surface)
945 if (!memcmp( &data->surface->rect, &surface_rect, sizeof(surface_rect) ))
947 /* existing surface is good enough */
948 window_surface_add_ref( data->surface );
949 if (*surface) window_surface_release( *surface );
950 *surface = data->surface;
951 goto done;
954 if (!(swp_flags & SWP_SHOWWINDOW) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) goto done;
956 if (!layered || !GetLayeredWindowAttributes( hwnd, &key, &alpha, &flags )) flags = 0;
957 if (!(flags & LWA_ALPHA)) alpha = 255;
958 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
960 if (*surface) window_surface_release( *surface );
961 *surface = create_surface( data->hwnd, &surface_rect, alpha, key, FALSE );
963 done:
964 release_win_data( data );
968 /***********************************************************************
969 * ANDROID_WindowPosChanged
971 void CDECL ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
972 const RECT *window_rect, const RECT *client_rect,
973 const RECT *visible_rect, const RECT *valid_rects,
974 struct window_surface *surface )
976 struct android_win_data *data;
977 DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
978 HWND owner = 0;
980 if (!(data = get_win_data( hwnd ))) return;
982 data->window_rect = *window_rect;
983 data->whole_rect = *visible_rect;
984 data->client_rect = *client_rect;
986 if (!is_argb_surface( data->surface ))
988 if (surface) window_surface_add_ref( surface );
989 if (data->surface) window_surface_release( data->surface );
990 data->surface = surface;
992 if (!data->parent) owner = GetWindow( hwnd, GW_OWNER );
993 release_win_data( data );
995 TRACE( "win %p window %s client %s style %08x owner %p flags %08x\n", hwnd,
996 wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), new_style, owner, swp_flags );
998 ioctl_window_pos_changed( hwnd, window_rect, client_rect, visible_rect,
999 new_style, swp_flags, insert_after, owner );
1003 /***********************************************************************
1004 * ANDROID_ShowWindow
1006 UINT CDECL ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
1008 if (IsRectEmpty( rect )) return swp;
1009 if (!IsIconic( hwnd )) return swp;
1010 /* always hide icons off-screen */
1011 if (rect->left != -32000 || rect->top != -32000)
1013 OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
1014 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1016 return swp;
1020 /*****************************************************************
1021 * ANDROID_SetParent
1023 void CDECL ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent )
1025 struct android_win_data *data;
1027 if (parent == old_parent) return;
1028 if (!(data = get_win_data( hwnd ))) return;
1030 TRACE( "win %p parent %p -> %p\n", hwnd, old_parent, parent );
1032 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
1033 ioctl_set_window_parent( hwnd, parent );
1034 release_win_data( data );
1038 /***********************************************************************
1039 * ANDROID_SetWindowStyle
1041 void CDECL ANDROID_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
1043 struct android_win_data *data;
1044 DWORD changed = style->styleNew ^ style->styleOld;
1046 if (hwnd == GetDesktopWindow()) return;
1047 if (!(data = get_win_data( hwnd ))) return;
1049 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1051 if (is_argb_surface( data->surface ))
1053 if (data->surface) window_surface_release( data->surface );
1054 data->surface = NULL;
1056 else if (data->surface) set_surface_layered( data->surface, 255, CLR_INVALID );
1058 release_win_data( data );
1062 /***********************************************************************
1063 * ANDROID_SetWindowRgn
1065 void CDECL ANDROID_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1067 struct android_win_data *data;
1069 if ((data = get_win_data( hwnd )))
1071 if (data->surface) set_surface_region( data->surface, hrgn );
1072 release_win_data( data );
1074 else FIXME( "not supported on other process window %p\n", hwnd );
1078 /***********************************************************************
1079 * ANDROID_SetLayeredWindowAttributes
1081 void CDECL ANDROID_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
1083 struct android_win_data *data;
1085 if (!(flags & LWA_ALPHA)) alpha = 255;
1086 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1088 if ((data = get_win_data( hwnd )))
1090 if (data->surface) set_surface_layered( data->surface, alpha, key );
1091 release_win_data( data );
1096 /*****************************************************************************
1097 * ANDROID_UpdateLayeredWindow
1099 BOOL CDECL ANDROID_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1100 const RECT *window_rect )
1102 struct window_surface *surface;
1103 struct android_win_data *data;
1104 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1105 COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
1106 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1107 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1108 void *src_bits, *dst_bits;
1109 RECT rect;
1110 HDC hdc = 0;
1111 HBITMAP dib;
1112 BOOL ret = FALSE;
1114 if (!(data = get_win_data( hwnd ))) return FALSE;
1116 rect = *window_rect;
1117 OffsetRect( &rect, -window_rect->left, -window_rect->top );
1119 surface = data->surface;
1120 if (!is_argb_surface( surface ))
1122 if (surface) window_surface_release( surface );
1123 surface = NULL;
1126 if (!surface || memcmp( &surface->rect, &rect, sizeof(RECT) ))
1128 data->surface = create_surface( data->hwnd, &rect, 255, color_key, TRUE );
1129 if (surface) window_surface_release( surface );
1130 surface = data->surface;
1132 else set_surface_layered( surface, 255, color_key );
1134 if (surface) window_surface_add_ref( surface );
1135 release_win_data( data );
1137 if (!surface) return FALSE;
1138 if (!info->hdcSrc)
1140 window_surface_release( surface );
1141 return TRUE;
1144 dst_bits = surface->funcs->get_info( surface, bmi );
1146 if (!(dib = CreateDIBSection( info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0 ))) goto done;
1147 if (!(hdc = CreateCompatibleDC( 0 ))) goto done;
1149 SelectObject( hdc, dib );
1151 surface->funcs->lock( surface );
1153 if (info->prcDirty)
1155 IntersectRect( &rect, &rect, info->prcDirty );
1156 memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage );
1157 PatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS );
1159 ret = GdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1160 info->hdcSrc,
1161 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1162 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1163 rect.right - rect.left, rect.bottom - rect.top,
1164 (info->dwFlags & ULW_ALPHA) ? *info->pblend : blend );
1165 if (ret)
1167 memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage );
1168 add_bounds_rect( surface->funcs->get_bounds( surface ), &rect );
1171 surface->funcs->unlock( surface );
1172 surface->funcs->flush( surface );
1174 done:
1175 window_surface_release( surface );
1176 if (hdc) DeleteDC( hdc );
1177 if (dib) DeleteObject( dib );
1178 return ret;
1182 /**********************************************************************
1183 * ANDROID_WindowMessage
1185 LRESULT CDECL ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1187 struct android_win_data *data;
1189 switch (msg)
1191 case WM_ANDROID_REFRESH:
1192 if ((data = get_win_data( hwnd )))
1194 struct window_surface *surface = data->surface;
1195 if (surface)
1197 surface->funcs->lock( surface );
1198 *surface->funcs->get_bounds( surface ) = surface->rect;
1199 surface->funcs->unlock( surface );
1200 if (is_argb_surface( surface )) surface->funcs->flush( surface );
1202 release_win_data( data );
1204 return 0;
1205 default:
1206 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
1207 return 0;
1212 /***********************************************************************
1213 * ANDROID_create_desktop
1215 BOOL CDECL ANDROID_create_desktop( UINT width, UINT height )
1217 /* wait until we receive the surface changed event */
1218 while (!screen_width)
1220 if (wait_events( 2000 ) != 1)
1222 ERR( "wait timed out\n" );
1223 break;
1225 process_events( QS_ALLINPUT );
1227 return TRUE;