include: Added missing Header_* defines.
[wine.git] / dlls / wineandroid.drv / window.c
blobeb05aaf28325a9d995a0c297e80e6663d10fa9ca
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 #define OEMRESOURCE
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wingdi.h"
44 #include "winuser.h"
45 #include "wine/unicode.h"
47 #include "android.h"
48 #include "wine/server.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(android);
53 /* private window data */
54 struct android_win_data
56 HWND hwnd; /* hwnd that this private data belongs to */
57 HWND parent; /* parent hwnd for child windows */
58 RECT window_rect; /* USER window rectangle relative to parent */
59 RECT whole_rect; /* X window rectangle for the whole window relative to parent */
60 RECT client_rect; /* client area relative to parent */
61 ANativeWindow *window; /* native window wrapper that forwards calls to the desktop process */
62 struct window_surface *surface;
65 #define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
67 static CRITICAL_SECTION win_data_section;
68 static CRITICAL_SECTION_DEBUG critsect_debug =
70 0, 0, &win_data_section,
71 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
74 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
76 static struct android_win_data *win_data_context[32768];
78 static inline int context_idx( HWND hwnd )
80 return LOWORD( hwnd ) >> 1;
83 static void set_surface_region( struct window_surface *window_surface, HRGN win_region );
85 /* only for use on sanitized BITMAPINFO structures */
86 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
88 if (info->bmiHeader.biCompression == BI_BITFIELDS)
89 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
90 if (coloruse == DIB_PAL_COLORS)
91 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
92 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
95 static inline int get_dib_stride( int width, int bpp )
97 return ((width * bpp + 31) >> 3) & ~3;
100 static inline int get_dib_image_size( const BITMAPINFO *info )
102 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
103 * abs( info->bmiHeader.biHeight );
107 /**********************************************************************
108 * get_win_monitor_dpi
110 static UINT get_win_monitor_dpi( HWND hwnd )
112 DPI_AWARENESS_CONTEXT context;
113 UINT ret;
115 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
116 ret = GetDpiForSystem(); /* FIXME: get monitor dpi */
117 SetThreadDpiAwarenessContext( context );
118 return ret;
122 /***********************************************************************
123 * alloc_win_data
125 static struct android_win_data *alloc_win_data( HWND hwnd )
127 struct android_win_data *data;
129 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
131 data->hwnd = hwnd;
132 data->window = create_ioctl_window( hwnd, FALSE,
133 (float)get_win_monitor_dpi( hwnd ) / GetDpiForWindow( hwnd ));
134 EnterCriticalSection( &win_data_section );
135 win_data_context[context_idx(hwnd)] = data;
137 return data;
141 /***********************************************************************
142 * free_win_data
144 static void free_win_data( struct android_win_data *data )
146 win_data_context[context_idx( data->hwnd )] = NULL;
147 LeaveCriticalSection( &win_data_section );
148 if (data->window) release_ioctl_window( data->window );
149 HeapFree( GetProcessHeap(), 0, data );
153 /***********************************************************************
154 * get_win_data
156 * Lock and return the data structure associated with a window.
158 static struct android_win_data *get_win_data( HWND hwnd )
160 struct android_win_data *data;
162 if (!hwnd) return NULL;
163 EnterCriticalSection( &win_data_section );
164 if ((data = win_data_context[context_idx(hwnd)]) && data->hwnd == hwnd) return data;
165 LeaveCriticalSection( &win_data_section );
166 return NULL;
170 /***********************************************************************
171 * release_win_data
173 * Release the data returned by get_win_data.
175 static void release_win_data( struct android_win_data *data )
177 if (data) LeaveCriticalSection( &win_data_section );
181 /***********************************************************************
182 * get_ioctl_window
184 static struct ANativeWindow *get_ioctl_window( HWND hwnd )
186 struct ANativeWindow *ret;
187 struct android_win_data *data = get_win_data( hwnd );
189 if (!data || !data->window) return NULL;
190 ret = grab_ioctl_window( data->window );
191 release_win_data( data );
192 return ret;
196 /* Handling of events coming from the Java side */
198 struct java_event
200 struct list entry;
201 union event_data data;
204 static struct list event_queue = LIST_INIT( event_queue );
205 static struct java_event *current_event;
206 static int event_pipe[2];
207 static DWORD desktop_tid;
209 /***********************************************************************
210 * send_event
212 int send_event( const union event_data *data )
214 int res;
216 if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
218 p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
219 return -1;
221 return 0;
225 /***********************************************************************
226 * desktop_changed
228 * JNI callback, runs in the context of the Java thread.
230 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
232 union event_data data;
234 memset( &data, 0, sizeof(data) );
235 data.type = DESKTOP_CHANGED;
236 data.desktop.width = width;
237 data.desktop.height = height;
238 p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
239 send_event( &data );
243 /***********************************************************************
244 * config_changed
246 * JNI callback, runs in the context of the Java thread.
248 void config_changed( JNIEnv *env, jobject obj, jint dpi )
250 union event_data data;
252 memset( &data, 0, sizeof(data) );
253 data.type = CONFIG_CHANGED;
254 data.cfg.dpi = dpi;
255 p__android_log_print( ANDROID_LOG_INFO, "wine", "config_changed: %u dpi", dpi );
256 send_event( &data );
260 /***********************************************************************
261 * surface_changed
263 * JNI callback, runs in the context of the Java thread.
265 void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jboolean client )
267 union event_data data;
269 memset( &data, 0, sizeof(data) );
270 data.surface.hwnd = LongToHandle( win );
271 data.surface.client = client;
272 if (surface)
274 int width, height;
275 ANativeWindow *win = pANativeWindow_fromSurface( env, surface );
277 if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0;
278 if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0;
279 data.surface.window = win;
280 data.surface.width = width;
281 data.surface.height = height;
282 p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %s %ux%u",
283 data.surface.hwnd, client ? "client" : "whole", width, height );
285 data.type = SURFACE_CHANGED;
286 send_event( &data );
290 /***********************************************************************
291 * motion_event
293 * JNI callback, runs in the context of the Java thread.
295 jboolean motion_event( JNIEnv *env, jobject obj, jint win, jint action, jint x, jint y, jint state, jint vscroll )
297 static LONG button_state;
298 union event_data data;
299 int prev_state;
301 int mask = action & AMOTION_EVENT_ACTION_MASK;
303 if (!( mask == AMOTION_EVENT_ACTION_DOWN ||
304 mask == AMOTION_EVENT_ACTION_UP ||
305 mask == AMOTION_EVENT_ACTION_CANCEL ||
306 mask == AMOTION_EVENT_ACTION_SCROLL ||
307 mask == AMOTION_EVENT_ACTION_MOVE ||
308 mask == AMOTION_EVENT_ACTION_HOVER_MOVE ||
309 mask == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
310 mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE ))
311 return JNI_FALSE;
313 /* make sure a subsequent AMOTION_EVENT_ACTION_UP is not treated as a touch event */
314 if (mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE) state |= 0x80000000;
316 prev_state = InterlockedExchange( &button_state, state );
318 data.type = MOTION_EVENT;
319 data.motion.hwnd = LongToHandle( win );
320 data.motion.input.type = INPUT_MOUSE;
321 data.motion.input.u.mi.dx = x;
322 data.motion.input.u.mi.dy = y;
323 data.motion.input.u.mi.mouseData = 0;
324 data.motion.input.u.mi.time = 0;
325 data.motion.input.u.mi.dwExtraInfo = 0;
326 data.motion.input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
327 switch (action & AMOTION_EVENT_ACTION_MASK)
329 case AMOTION_EVENT_ACTION_DOWN:
330 case AMOTION_EVENT_ACTION_BUTTON_PRESS:
331 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_PRIMARY)
332 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
333 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_SECONDARY)
334 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
335 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_TERTIARY)
336 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
337 if (!(state & ~prev_state)) /* touch event */
338 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
339 break;
340 case AMOTION_EVENT_ACTION_UP:
341 case AMOTION_EVENT_ACTION_CANCEL:
342 case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
343 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_PRIMARY)
344 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
345 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_SECONDARY)
346 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
347 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_TERTIARY)
348 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
349 if (!(prev_state & ~state)) /* touch event */
350 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
351 break;
352 case AMOTION_EVENT_ACTION_SCROLL:
353 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_WHEEL;
354 data.motion.input.u.mi.mouseData = vscroll < 0 ? -WHEEL_DELTA : WHEEL_DELTA;
355 break;
356 case AMOTION_EVENT_ACTION_MOVE:
357 case AMOTION_EVENT_ACTION_HOVER_MOVE:
358 break;
359 default:
360 return JNI_FALSE;
362 send_event( &data );
363 return JNI_TRUE;
367 /***********************************************************************
368 * init_event_queue
370 static void init_event_queue(void)
372 HANDLE handle;
373 int ret;
375 if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
377 ERR( "could not create data\n" );
378 ExitProcess(1);
380 if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
382 ERR( "Can't allocate handle for event fd\n" );
383 ExitProcess(1);
385 SERVER_START_REQ( set_queue_fd )
387 req->handle = wine_server_obj_handle( handle );
388 ret = wine_server_call( req );
390 SERVER_END_REQ;
391 if (ret)
393 ERR( "Can't store handle for event fd %x\n", ret );
394 ExitProcess(1);
396 CloseHandle( handle );
397 desktop_tid = GetCurrentThreadId();
401 /***********************************************************************
402 * pull_events
404 * Pull events from the event pipe and add them to the queue
406 static void pull_events(void)
408 struct java_event *event;
409 int res;
411 for (;;)
413 if (!(event = HeapAlloc( GetProcessHeap(), 0, sizeof(*event) ))) break;
415 res = read( event_pipe[0], &event->data, sizeof(event->data) );
416 if (res != sizeof(event->data)) break;
417 list_add_tail( &event_queue, &event->entry );
419 HeapFree( GetProcessHeap(), 0, event );
423 /***********************************************************************
424 * process_events
426 static int process_events( DWORD mask )
428 DPI_AWARENESS_CONTEXT context;
429 struct java_event *event, *next, *previous;
430 unsigned int count = 0;
432 assert( GetCurrentThreadId() == desktop_tid );
434 pull_events();
436 previous = current_event;
438 LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
440 switch (event->data.type)
442 case SURFACE_CHANGED:
443 break; /* always process it to unblock other threads */
444 case MOTION_EVENT:
445 if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|
446 MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_LEFTUP|
447 MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
449 if (mask & QS_MOUSEBUTTON) break;
451 else if (mask & QS_MOUSEMOVE) break;
452 continue; /* skip it */
453 case KEYBOARD_EVENT:
454 if (mask & QS_KEY) break;
455 continue; /* skip it */
456 default:
457 if (mask & QS_SENDMESSAGE) break;
458 continue; /* skip it */
461 /* remove it first, in case we process events recursively */
462 list_remove( &event->entry );
463 current_event = event;
465 switch (event->data.type)
467 case DESKTOP_CHANGED:
468 TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
469 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
470 screen_width = event->data.desktop.width;
471 screen_height = event->data.desktop.height;
472 init_monitors( screen_width, screen_height );
473 SetWindowPos( GetDesktopWindow(), 0, 0, 0, screen_width, screen_height,
474 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
475 SetThreadDpiAwarenessContext( context );
476 break;
478 case CONFIG_CHANGED:
479 TRACE( "CONFIG_CHANGED dpi %u\n", event->data.cfg.dpi );
480 set_screen_dpi( event->data.cfg.dpi );
481 break;
483 case SURFACE_CHANGED:
484 TRACE("SURFACE_CHANGED %p %p %s size %ux%u\n", event->data.surface.hwnd,
485 event->data.surface.window, event->data.surface.client ? "client" : "whole",
486 event->data.surface.width, event->data.surface.height );
488 register_native_window( event->data.surface.hwnd, event->data.surface.window, event->data.surface.client );
489 break;
491 case MOTION_EVENT:
493 HWND capture = get_capture_window();
495 if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_MIDDLEDOWN))
496 TRACE( "BUTTONDOWN pos %d,%d hwnd %p flags %x\n",
497 event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
498 event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
499 else if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTUP|MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
500 TRACE( "BUTTONUP pos %d,%d hwnd %p flags %x\n",
501 event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
502 event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
503 else
504 TRACE( "MOUSEMOVE pos %d,%d hwnd %p flags %x\n",
505 event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
506 event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
507 if (!capture && (event->data.motion.input.u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE))
509 RECT rect;
510 SetRect( &rect, event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
511 event->data.motion.input.u.mi.dx + 1, event->data.motion.input.u.mi.dy + 1 );
513 SERVER_START_REQ( update_window_zorder )
515 req->window = wine_server_user_handle( event->data.motion.hwnd );
516 req->rect.left = rect.left;
517 req->rect.top = rect.top;
518 req->rect.right = rect.right;
519 req->rect.bottom = rect.bottom;
520 wine_server_call( req );
522 SERVER_END_REQ;
524 __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input );
526 break;
528 case KEYBOARD_EVENT:
529 if (event->data.kbd.input.u.ki.dwFlags & KEYEVENTF_KEYUP)
530 TRACE("KEYUP hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
531 event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk,
532 event->data.kbd.input.u.ki.wScan );
533 else
534 TRACE("KEYDOWN hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
535 event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk,
536 event->data.kbd.input.u.ki.wScan );
537 update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state );
538 __wine_send_input( 0, &event->data.kbd.input );
539 break;
541 default:
542 FIXME( "got event %u\n", event->data.type );
544 HeapFree( GetProcessHeap(), 0, event );
545 count++;
546 /* next may have been removed by a recursive call, so reset it to the beginning of the list */
547 next = LIST_ENTRY( event_queue.next, struct java_event, entry );
549 current_event = previous;
550 return count;
554 /***********************************************************************
555 * wait_events
557 static int wait_events( int timeout )
559 assert( GetCurrentThreadId() == desktop_tid );
561 for (;;)
563 struct pollfd pollfd;
564 int ret;
566 pollfd.fd = event_pipe[0];
567 pollfd.events = POLLIN | POLLHUP;
568 ret = poll( &pollfd, 1, timeout );
569 if (ret == -1 && errno == EINTR) continue;
570 if (ret && (pollfd.revents & (POLLHUP | POLLERR))) ret = -1;
571 return ret;
576 /* Window surface support */
578 struct android_window_surface
580 struct window_surface header;
581 HWND hwnd;
582 ANativeWindow *window;
583 RECT bounds;
584 BOOL byteswap;
585 RGNDATA *region_data;
586 HRGN region;
587 BYTE alpha;
588 COLORREF color_key;
589 void *bits;
590 CRITICAL_SECTION crit;
591 BITMAPINFO info; /* variable size, must be last */
594 static struct android_window_surface *get_android_surface( struct window_surface *surface )
596 return (struct android_window_surface *)surface;
599 static inline void reset_bounds( RECT *bounds )
601 bounds->left = bounds->top = INT_MAX;
602 bounds->right = bounds->bottom = INT_MIN;
605 static inline void add_bounds_rect( RECT *bounds, const RECT *rect )
607 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
608 bounds->left = min( bounds->left, rect->left );
609 bounds->top = min( bounds->top, rect->top );
610 bounds->right = max( bounds->right, rect->right );
611 bounds->bottom = max( bounds->bottom, rect->bottom );
614 /* store the palette or color mask data in the bitmap info structure */
615 static void set_color_info( BITMAPINFO *info, BOOL has_alpha )
617 DWORD *colors = (DWORD *)info->bmiColors;
619 info->bmiHeader.biSize = sizeof(info->bmiHeader);
620 info->bmiHeader.biClrUsed = 0;
621 info->bmiHeader.biBitCount = 32;
622 if (has_alpha)
624 info->bmiHeader.biCompression = BI_RGB;
625 return;
627 info->bmiHeader.biCompression = BI_BITFIELDS;
628 colors[0] = 0xff0000;
629 colors[1] = 0x00ff00;
630 colors[2] = 0x0000ff;
633 /* apply the window region to a single line of the destination image. */
634 static void apply_line_region( DWORD *dst, int width, int x, int y, const RECT *rect, const RECT *end )
636 while (rect < end && rect->top <= y && width > 0)
638 if (rect->left > x)
640 memset( dst, 0, min( rect->left - x, width ) * sizeof(*dst) );
641 dst += rect->left - x;
642 width -= rect->left - x;
643 x = rect->left;
645 if (rect->right > x)
647 dst += rect->right - x;
648 width -= rect->right - x;
649 x = rect->right;
651 rect++;
653 if (width > 0) memset( dst, 0, width * sizeof(*dst) );
656 /***********************************************************************
657 * android_surface_lock
659 static void android_surface_lock( struct window_surface *window_surface )
661 struct android_window_surface *surface = get_android_surface( window_surface );
663 EnterCriticalSection( &surface->crit );
666 /***********************************************************************
667 * android_surface_unlock
669 static void android_surface_unlock( struct window_surface *window_surface )
671 struct android_window_surface *surface = get_android_surface( window_surface );
673 LeaveCriticalSection( &surface->crit );
676 /***********************************************************************
677 * android_surface_get_bitmap_info
679 static void *android_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
681 struct android_window_surface *surface = get_android_surface( window_surface );
683 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
684 return surface->bits;
687 /***********************************************************************
688 * android_surface_get_bounds
690 static RECT *android_surface_get_bounds( struct window_surface *window_surface )
692 struct android_window_surface *surface = get_android_surface( window_surface );
694 return &surface->bounds;
697 /***********************************************************************
698 * android_surface_set_region
700 static void android_surface_set_region( struct window_surface *window_surface, HRGN region )
702 struct android_window_surface *surface = get_android_surface( window_surface );
704 TRACE( "updating surface %p hwnd %p with %p\n", surface, surface->hwnd, region );
706 window_surface->funcs->lock( window_surface );
707 if (!region)
709 if (surface->region) DeleteObject( surface->region );
710 surface->region = 0;
712 else
714 if (!surface->region) surface->region = CreateRectRgn( 0, 0, 0, 0 );
715 CombineRgn( surface->region, region, 0, RGN_COPY );
717 window_surface->funcs->unlock( window_surface );
718 set_surface_region( &surface->header, (HRGN)1 );
721 /***********************************************************************
722 * android_surface_flush
724 static void android_surface_flush( struct window_surface *window_surface )
726 struct android_window_surface *surface = get_android_surface( window_surface );
727 ANativeWindow_Buffer buffer;
728 ARect rc;
729 RECT rect;
730 BOOL needs_flush;
732 window_surface->funcs->lock( window_surface );
733 SetRect( &rect, 0, 0, surface->header.rect.right - surface->header.rect.left,
734 surface->header.rect.bottom - surface->header.rect.top );
735 needs_flush = IntersectRect( &rect, &rect, &surface->bounds );
736 reset_bounds( &surface->bounds );
737 window_surface->funcs->unlock( window_surface );
738 if (!needs_flush) return;
740 TRACE( "flushing %p hwnd %p surface %s rect %s bits %p alpha %02x key %08x region %u rects\n",
741 surface, surface->hwnd, wine_dbgstr_rect( &surface->header.rect ),
742 wine_dbgstr_rect( &rect ), surface->bits, surface->alpha, surface->color_key,
743 surface->region_data ? surface->region_data->rdh.nCount : 0 );
745 rc.left = rect.left;
746 rc.top = rect.top;
747 rc.right = rect.right;
748 rc.bottom = rect.bottom;
750 if (!surface->window->perform( surface->window, NATIVE_WINDOW_LOCK, &buffer, &rc ))
752 const RECT *rgn_rect = NULL, *end = NULL;
753 unsigned int *src, *dst;
754 int x, y, width;
756 rect.left = rc.left;
757 rect.top = rc.top;
758 rect.right = rc.right;
759 rect.bottom = rc.bottom;
760 IntersectRect( &rect, &rect, &surface->header.rect );
762 if (surface->region_data)
764 rgn_rect = (RECT *)surface->region_data->Buffer;
765 end = rgn_rect + surface->region_data->rdh.nCount;
767 src = (unsigned int *)surface->bits
768 + (rect.top - surface->header.rect.top) * surface->info.bmiHeader.biWidth
769 + (rect.left - surface->header.rect.left);
770 dst = (unsigned int *)buffer.bits + rect.top * buffer.stride + rect.left;
771 width = min( rect.right - rect.left, buffer.stride );
773 for (y = rect.top; y < min( buffer.height, rect.bottom); y++)
775 if (surface->info.bmiHeader.biCompression == BI_RGB)
776 memcpy( dst, src, width * sizeof(*dst) );
777 else if (surface->alpha == 255)
778 for (x = 0; x < width; x++) dst[x] = src[x] | 0xff000000;
779 else
780 for (x = 0; x < width; x++)
781 dst[x] = ((surface->alpha << 24) |
782 (((BYTE)(src[x] >> 16) * surface->alpha / 255) << 16) |
783 (((BYTE)(src[x] >> 8) * surface->alpha / 255) << 8) |
784 (((BYTE)src[x] * surface->alpha / 255)));
786 if (surface->color_key != CLR_INVALID)
787 for (x = 0; x < width; x++) if ((src[x] & 0xffffff) == surface->color_key) dst[x] = 0;
789 if (rgn_rect)
791 while (rgn_rect < end && rgn_rect->bottom <= y) rgn_rect++;
792 apply_line_region( dst, width, rect.left, y, rgn_rect, end );
795 src += surface->info.bmiHeader.biWidth;
796 dst += buffer.stride;
798 surface->window->perform( surface->window, NATIVE_WINDOW_UNLOCK_AND_POST );
800 else TRACE( "Unable to lock surface %p window %p buffer %p\n",
801 surface, surface->hwnd, surface->window );
804 /***********************************************************************
805 * android_surface_destroy
807 static void android_surface_destroy( struct window_surface *window_surface )
809 struct android_window_surface *surface = get_android_surface( window_surface );
811 TRACE( "freeing %p bits %p\n", surface, surface->bits );
813 surface->crit.DebugInfo->Spare[0] = 0;
814 DeleteCriticalSection( &surface->crit );
815 HeapFree( GetProcessHeap(), 0, surface->region_data );
816 if (surface->region) DeleteObject( surface->region );
817 release_ioctl_window( surface->window );
818 HeapFree( GetProcessHeap(), 0, surface->bits );
819 HeapFree( GetProcessHeap(), 0, surface );
822 static const struct window_surface_funcs android_surface_funcs =
824 android_surface_lock,
825 android_surface_unlock,
826 android_surface_get_bitmap_info,
827 android_surface_get_bounds,
828 android_surface_set_region,
829 android_surface_flush,
830 android_surface_destroy
833 static BOOL is_argb_surface( struct window_surface *surface )
835 return surface && surface->funcs == &android_surface_funcs &&
836 get_android_surface( surface )->info.bmiHeader.biCompression == BI_RGB;
839 /***********************************************************************
840 * set_color_key
842 static void set_color_key( struct android_window_surface *surface, COLORREF key )
844 if (key == CLR_INVALID)
845 surface->color_key = CLR_INVALID;
846 else if (surface->info.bmiHeader.biBitCount <= 8)
847 surface->color_key = CLR_INVALID;
848 else if (key & (1 << 24)) /* PALETTEINDEX */
849 surface->color_key = 0;
850 else if (key >> 16 == 0x10ff) /* DIBINDEX */
851 surface->color_key = 0;
852 else if (surface->info.bmiHeader.biBitCount == 24)
853 surface->color_key = key;
854 else
855 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
858 /***********************************************************************
859 * set_surface_region
861 static void set_surface_region( struct window_surface *window_surface, HRGN win_region )
863 struct android_window_surface *surface = get_android_surface( window_surface );
864 struct android_win_data *win_data;
865 HRGN region = win_region;
866 RGNDATA *data = NULL;
867 DWORD size;
868 int offset_x, offset_y;
870 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
872 if (!(win_data = get_win_data( surface->hwnd ))) return;
873 offset_x = win_data->window_rect.left - win_data->whole_rect.left;
874 offset_y = win_data->window_rect.top - win_data->whole_rect.top;
875 release_win_data( win_data );
877 if (win_region == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
879 region = CreateRectRgn( 0, 0, win_data->window_rect.right - win_data->window_rect.left,
880 win_data->window_rect.bottom - win_data->window_rect.top );
881 if (GetWindowRgn( surface->hwnd, region ) == ERROR && !surface->region) goto done;
884 OffsetRgn( region, offset_x, offset_y );
885 if (surface->region) CombineRgn( region, region, surface->region, RGN_AND );
887 if (!(size = GetRegionData( region, 0, NULL ))) goto done;
888 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
890 if (!GetRegionData( region, size, data ))
892 HeapFree( GetProcessHeap(), 0, data );
893 data = NULL;
896 done:
897 window_surface->funcs->lock( window_surface );
898 HeapFree( GetProcessHeap(), 0, surface->region_data );
899 surface->region_data = data;
900 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
901 window_surface->funcs->unlock( window_surface );
902 if (region != win_region) DeleteObject( region );
905 /***********************************************************************
906 * create_surface
908 static struct window_surface *create_surface( HWND hwnd, const RECT *rect,
909 BYTE alpha, COLORREF color_key, BOOL src_alpha )
911 struct android_window_surface *surface;
912 int width = rect->right - rect->left, height = rect->bottom - rect->top;
914 surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
915 FIELD_OFFSET( struct android_window_surface, info.bmiColors[3] ));
916 if (!surface) return NULL;
917 set_color_info( &surface->info, src_alpha );
918 surface->info.bmiHeader.biWidth = width;
919 surface->info.bmiHeader.biHeight = -height; /* top-down */
920 surface->info.bmiHeader.biPlanes = 1;
921 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
923 InitializeCriticalSection( &surface->crit );
924 surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
926 surface->header.funcs = &android_surface_funcs;
927 surface->header.rect = *rect;
928 surface->header.ref = 1;
929 surface->hwnd = hwnd;
930 surface->window = get_ioctl_window( hwnd );
931 surface->alpha = alpha;
932 set_color_key( surface, color_key );
933 set_surface_region( &surface->header, (HRGN)1 );
934 reset_bounds( &surface->bounds );
936 if (!(surface->bits = HeapAlloc( GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage )))
937 goto failed;
939 TRACE( "created %p hwnd %p %s bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect),
940 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage );
942 return &surface->header;
944 failed:
945 android_surface_destroy( &surface->header );
946 return NULL;
949 /***********************************************************************
950 * set_surface_layered
952 static void set_surface_layered( struct window_surface *window_surface, BYTE alpha, COLORREF color_key )
954 struct android_window_surface *surface = get_android_surface( window_surface );
955 COLORREF prev_key;
956 BYTE prev_alpha;
958 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
960 window_surface->funcs->lock( window_surface );
961 prev_key = surface->color_key;
962 prev_alpha = surface->alpha;
963 surface->alpha = alpha;
964 set_color_key( surface, color_key );
965 if (alpha != prev_alpha || surface->color_key != prev_key) /* refresh */
966 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
967 window_surface->funcs->unlock( window_surface );
970 /***********************************************************************
971 * get_mono_icon_argb
973 * Return a monochrome icon/cursor bitmap bits in ARGB format.
975 static unsigned int *get_mono_icon_argb( HDC hdc, HBITMAP bmp, unsigned int *width, unsigned int *height )
977 BITMAP bm;
978 char *mask;
979 unsigned int i, j, stride, mask_size, bits_size, *bits = NULL, *ptr;
981 if (!GetObjectW( bmp, sizeof(bm), &bm )) return NULL;
982 stride = ((bm.bmWidth + 15) >> 3) & ~1;
983 mask_size = stride * bm.bmHeight;
984 if (!(mask = HeapAlloc( GetProcessHeap(), 0, mask_size ))) return NULL;
985 if (!GetBitmapBits( bmp, mask_size, mask )) goto done;
987 bm.bmHeight /= 2;
988 bits_size = bm.bmWidth * bm.bmHeight * sizeof(*bits);
989 if (!(bits = HeapAlloc( GetProcessHeap(), 0, bits_size ))) goto done;
991 ptr = bits;
992 for (i = 0; i < bm.bmHeight; i++)
993 for (j = 0; j < bm.bmWidth; j++, ptr++)
995 int and = ((mask[i * stride + j / 8] << (j % 8)) & 0x80);
996 int xor = ((mask[(i + bm.bmHeight) * stride + j / 8] << (j % 8)) & 0x80);
997 if (!xor && and)
998 *ptr = 0;
999 else if (xor && !and)
1000 *ptr = 0xffffffff;
1001 else
1002 /* we can't draw "invert" pixels, so render them as black instead */
1003 *ptr = 0xff000000;
1006 *width = bm.bmWidth;
1007 *height = bm.bmHeight;
1009 done:
1010 HeapFree( GetProcessHeap(), 0, mask );
1011 return bits;
1014 /***********************************************************************
1015 * get_bitmap_argb
1017 * Return the bitmap bits in ARGB format. Helper for setting icons and cursors.
1019 static unsigned int *get_bitmap_argb( HDC hdc, HBITMAP color, HBITMAP mask, unsigned int *width,
1020 unsigned int *height )
1022 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1023 BITMAPINFO *info = (BITMAPINFO *)buffer;
1024 BITMAP bm;
1025 unsigned int *ptr, *bits = NULL;
1026 unsigned char *mask_bits = NULL;
1027 int i, j;
1028 BOOL has_alpha = FALSE;
1030 if (!color) return get_mono_icon_argb( hdc, mask, width, height );
1032 if (!GetObjectW( color, sizeof(bm), &bm )) return NULL;
1033 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1034 info->bmiHeader.biWidth = bm.bmWidth;
1035 info->bmiHeader.biHeight = -bm.bmHeight;
1036 info->bmiHeader.biPlanes = 1;
1037 info->bmiHeader.biBitCount = 32;
1038 info->bmiHeader.biCompression = BI_RGB;
1039 info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
1040 info->bmiHeader.biXPelsPerMeter = 0;
1041 info->bmiHeader.biYPelsPerMeter = 0;
1042 info->bmiHeader.biClrUsed = 0;
1043 info->bmiHeader.biClrImportant = 0;
1044 if (!(bits = HeapAlloc( GetProcessHeap(), 0, bm.bmWidth * bm.bmHeight * sizeof(unsigned int) )))
1045 goto failed;
1046 if (!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) goto failed;
1048 *width = bm.bmWidth;
1049 *height = bm.bmHeight;
1051 for (i = 0; i < bm.bmWidth * bm.bmHeight; i++)
1052 if ((has_alpha = (bits[i] & 0xff000000) != 0)) break;
1054 if (!has_alpha)
1056 unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4;
1057 /* generate alpha channel from the mask */
1058 info->bmiHeader.biBitCount = 1;
1059 info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight;
1060 if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto failed;
1061 if (!GetDIBits( hdc, mask, 0, bm.bmHeight, mask_bits, info, DIB_RGB_COLORS )) goto failed;
1062 ptr = bits;
1063 for (i = 0; i < bm.bmHeight; i++)
1064 for (j = 0; j < bm.bmWidth; j++, ptr++)
1065 if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000;
1066 HeapFree( GetProcessHeap(), 0, mask_bits );
1069 return bits;
1071 failed:
1072 HeapFree( GetProcessHeap(), 0, bits );
1073 HeapFree( GetProcessHeap(), 0, mask_bits );
1074 *width = *height = 0;
1075 return NULL;
1079 enum android_system_cursors
1081 TYPE_ARROW = 1000,
1082 TYPE_CONTEXT_MENU = 1001,
1083 TYPE_HAND = 1002,
1084 TYPE_HELP = 1003,
1085 TYPE_WAIT = 1004,
1086 TYPE_CELL = 1006,
1087 TYPE_CROSSHAIR = 1007,
1088 TYPE_TEXT = 1008,
1089 TYPE_VERTICAL_TEXT = 1009,
1090 TYPE_ALIAS = 1010,
1091 TYPE_COPY = 1011,
1092 TYPE_NO_DROP = 1012,
1093 TYPE_ALL_SCROLL = 1013,
1094 TYPE_HORIZONTAL_DOUBLE_ARROW = 1014,
1095 TYPE_VERTICAL_DOUBLE_ARROW = 1015,
1096 TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016,
1097 TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017,
1098 TYPE_ZOOM_IN = 1018,
1099 TYPE_ZOOM_OUT = 1019,
1100 TYPE_GRAB = 1020,
1101 TYPE_GRABBING = 1021,
1104 struct system_cursors
1106 WORD id;
1107 enum android_system_cursors android_id;
1110 static const struct system_cursors user32_cursors[] =
1112 { OCR_NORMAL, TYPE_ARROW },
1113 { OCR_IBEAM, TYPE_TEXT },
1114 { OCR_WAIT, TYPE_WAIT },
1115 { OCR_CROSS, TYPE_CROSSHAIR },
1116 { OCR_SIZE, TYPE_ALL_SCROLL },
1117 { OCR_SIZEALL, TYPE_ALL_SCROLL },
1118 { OCR_SIZENWSE, TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW },
1119 { OCR_SIZENESW, TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW },
1120 { OCR_SIZEWE, TYPE_HORIZONTAL_DOUBLE_ARROW },
1121 { OCR_SIZENS, TYPE_VERTICAL_DOUBLE_ARROW },
1122 { OCR_NO, TYPE_NO_DROP },
1123 { OCR_HAND, TYPE_HAND },
1124 { OCR_HELP, TYPE_HELP },
1125 { 0 }
1128 static const struct system_cursors comctl32_cursors[] =
1130 /* 102 TYPE_MOVE doesn't exist */
1131 { 104, TYPE_COPY },
1132 { 105, TYPE_ARROW },
1133 { 106, TYPE_HORIZONTAL_DOUBLE_ARROW },
1134 { 107, TYPE_HORIZONTAL_DOUBLE_ARROW },
1135 { 108, TYPE_GRABBING },
1136 { 135, TYPE_VERTICAL_DOUBLE_ARROW },
1137 { 0 }
1140 static const struct system_cursors ole32_cursors[] =
1142 { 1, TYPE_NO_DROP },
1143 /* 2 TYPE_MOVE doesn't exist */
1144 { 3, TYPE_COPY },
1145 { 4, TYPE_ALIAS },
1146 { 0 }
1149 static const struct system_cursors riched20_cursors[] =
1151 { 105, TYPE_GRABBING },
1152 { 109, TYPE_COPY },
1153 /* 110 TYPE_MOVE doesn't exist */
1154 { 111, TYPE_NO_DROP },
1155 { 0 }
1158 static const struct
1160 const struct system_cursors *cursors;
1161 WCHAR name[16];
1162 } module_cursors[] =
1164 { user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
1165 { comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
1166 { ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
1167 { riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
1170 static int get_cursor_system_id( const ICONINFOEXW *info )
1172 const struct system_cursors *cursors;
1173 unsigned int i;
1174 HMODULE module;
1176 if (info->szResName[0]) return 0; /* only integer resources are supported here */
1177 if (!(module = GetModuleHandleW( info->szModName ))) return 0;
1179 for (i = 0; i < ARRAY_SIZE( module_cursors ); i++)
1180 if (GetModuleHandleW( module_cursors[i].name ) == module) break;
1181 if (i == ARRAY_SIZE( module_cursors )) return 0;
1183 cursors = module_cursors[i].cursors;
1184 for (i = 0; cursors[i].id; i++)
1185 if (cursors[i].id == info->wResID) return cursors[i].android_id;
1187 return 0;
1191 static WNDPROC desktop_orig_wndproc;
1193 static LRESULT CALLBACK desktop_wndproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1195 switch (msg)
1197 case WM_PARENTNOTIFY:
1198 if (LOWORD(wp) == WM_DESTROY) destroy_ioctl_window( (HWND)lp, FALSE );
1199 break;
1201 return desktop_orig_wndproc( hwnd, msg, wp, lp );
1205 /***********************************************************************
1206 * ANDROID_MsgWaitForMultipleObjectsEx
1208 DWORD CDECL ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
1209 DWORD timeout, DWORD mask, DWORD flags )
1211 if (GetCurrentThreadId() == desktop_tid)
1213 /* don't process nested events */
1214 if (current_event) mask = 0;
1215 if (process_events( mask )) return count - 1;
1217 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
1218 timeout, flags & MWMO_ALERTABLE );
1221 /**********************************************************************
1222 * ANDROID_CreateWindow
1224 BOOL CDECL ANDROID_CreateWindow( HWND hwnd )
1226 TRACE( "%p\n", hwnd );
1228 if (hwnd == GetDesktopWindow())
1230 struct android_win_data *data;
1232 init_event_queue();
1233 start_android_device();
1234 if (!(data = alloc_win_data( hwnd ))) return FALSE;
1235 release_win_data( data );
1237 return TRUE;
1241 /***********************************************************************
1242 * ANDROID_DestroyWindow
1244 void CDECL ANDROID_DestroyWindow( HWND hwnd )
1246 struct android_win_data *data;
1248 if (!(data = get_win_data( hwnd ))) return;
1250 if (data->surface) window_surface_release( data->surface );
1251 data->surface = NULL;
1252 destroy_gl_drawable( hwnd );
1253 free_win_data( data );
1257 /***********************************************************************
1258 * create_win_data
1260 * Create a data window structure for an existing window.
1262 static struct android_win_data *create_win_data( HWND hwnd, const RECT *window_rect,
1263 const RECT *client_rect )
1265 struct android_win_data *data;
1266 HWND parent;
1268 if (!(parent = GetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop or HWND_MESSAGE */
1270 if (!(data = alloc_win_data( hwnd ))) return NULL;
1272 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
1273 data->whole_rect = data->window_rect = *window_rect;
1274 data->client_rect = *client_rect;
1275 return data;
1279 static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rect )
1281 if (!IntersectRect( surface_rect, visible_rect, &virtual_screen_rect )) return FALSE;
1282 OffsetRect( surface_rect, -visible_rect->left, -visible_rect->top );
1283 surface_rect->left &= ~31;
1284 surface_rect->top &= ~31;
1285 surface_rect->right = max( surface_rect->left + 32, (surface_rect->right + 31) & ~31 );
1286 surface_rect->bottom = max( surface_rect->top + 32, (surface_rect->bottom + 31) & ~31 );
1287 return TRUE;
1291 /***********************************************************************
1292 * ANDROID_WindowPosChanging
1294 void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
1295 const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
1296 struct window_surface **surface )
1298 struct android_win_data *data = get_win_data( hwnd );
1299 RECT surface_rect;
1300 DWORD flags;
1301 COLORREF key;
1302 BYTE alpha;
1303 BOOL layered = GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED;
1305 TRACE( "win %p window %s client %s style %08x flags %08x\n",
1306 hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1307 GetWindowLongW( hwnd, GWL_STYLE ), swp_flags );
1309 if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return;
1311 *visible_rect = *window_rect;
1313 /* create the window surface if necessary */
1315 if (data->parent) goto done;
1316 if (swp_flags & SWP_HIDEWINDOW) goto done;
1317 if (is_argb_surface( data->surface )) goto done;
1318 if (!get_surface_rect( visible_rect, &surface_rect )) goto done;
1320 if (data->surface)
1322 if (!memcmp( &data->surface->rect, &surface_rect, sizeof(surface_rect) ))
1324 /* existing surface is good enough */
1325 window_surface_add_ref( data->surface );
1326 if (*surface) window_surface_release( *surface );
1327 *surface = data->surface;
1328 goto done;
1331 if (!(swp_flags & SWP_SHOWWINDOW) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) goto done;
1333 if (!layered || !GetLayeredWindowAttributes( hwnd, &key, &alpha, &flags )) flags = 0;
1334 if (!(flags & LWA_ALPHA)) alpha = 255;
1335 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1337 if (*surface) window_surface_release( *surface );
1338 *surface = create_surface( data->hwnd, &surface_rect, alpha, key, FALSE );
1340 done:
1341 release_win_data( data );
1345 /***********************************************************************
1346 * ANDROID_WindowPosChanged
1348 void CDECL ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
1349 const RECT *window_rect, const RECT *client_rect,
1350 const RECT *visible_rect, const RECT *valid_rects,
1351 struct window_surface *surface )
1353 struct android_win_data *data;
1354 DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
1355 HWND owner = 0;
1357 if (!(data = get_win_data( hwnd ))) return;
1359 data->window_rect = *window_rect;
1360 data->whole_rect = *visible_rect;
1361 data->client_rect = *client_rect;
1363 if (!is_argb_surface( data->surface ))
1365 if (surface) window_surface_add_ref( surface );
1366 if (data->surface) window_surface_release( data->surface );
1367 data->surface = surface;
1369 if (!data->parent) owner = GetWindow( hwnd, GW_OWNER );
1370 release_win_data( data );
1372 if (!(swp_flags & SWP_NOZORDER)) insert_after = GetWindow( hwnd, GW_HWNDPREV );
1374 TRACE( "win %p window %s client %s style %08x owner %p after %p flags %08x\n", hwnd,
1375 wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1376 new_style, owner, insert_after, swp_flags );
1378 ioctl_window_pos_changed( hwnd, window_rect, client_rect, visible_rect,
1379 new_style, swp_flags, insert_after, owner );
1383 /***********************************************************************
1384 * ANDROID_ShowWindow
1386 UINT CDECL ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
1388 if (IsRectEmpty( rect )) return swp;
1389 if (!IsIconic( hwnd )) return swp;
1390 /* always hide icons off-screen */
1391 if (rect->left != -32000 || rect->top != -32000)
1393 OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
1394 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1396 return swp;
1400 /*****************************************************************
1401 * ANDROID_SetParent
1403 void CDECL ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent )
1405 struct android_win_data *data;
1407 if (parent == old_parent) return;
1408 if (!(data = get_win_data( hwnd ))) return;
1410 TRACE( "win %p parent %p -> %p\n", hwnd, old_parent, parent );
1412 data->parent = (parent == GetDesktopWindow()) ? 0 : parent;
1413 ioctl_set_window_parent( hwnd, parent, (float)get_win_monitor_dpi( hwnd ) / GetDpiForWindow( hwnd ));
1414 release_win_data( data );
1418 /***********************************************************************
1419 * ANDROID_SetCapture
1421 void CDECL ANDROID_SetCapture( HWND hwnd, UINT flags )
1423 if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
1424 ioctl_set_capture( hwnd );
1428 /***********************************************************************
1429 * ANDROID_SetCursor
1431 void CDECL ANDROID_SetCursor( HCURSOR handle )
1433 static HCURSOR last_cursor;
1434 static DWORD last_cursor_change;
1436 if (InterlockedExchangePointer( (void **)&last_cursor, handle ) != handle ||
1437 GetTickCount() - last_cursor_change > 100)
1439 last_cursor_change = GetTickCount();
1441 if (handle)
1443 unsigned int width = 0, height = 0, *bits = NULL;
1444 ICONINFOEXW info;
1445 int id;
1447 info.cbSize = sizeof(info);
1448 if (!GetIconInfoExW( handle, &info )) return;
1450 if (!(id = get_cursor_system_id( &info )))
1452 HDC hdc = CreateCompatibleDC( 0 );
1453 bits = get_bitmap_argb( hdc, info.hbmColor, info.hbmMask, &width, &height );
1454 DeleteDC( hdc );
1456 /* make sure hotspot is valid */
1457 if (info.xHotspot >= width || info.yHotspot >= height)
1459 info.xHotspot = width / 2;
1460 info.yHotspot = height / 2;
1463 ioctl_set_cursor( id, width, height, info.xHotspot, info.yHotspot, bits );
1464 HeapFree( GetProcessHeap(), 0, bits );
1465 DeleteObject( info.hbmColor );
1466 DeleteObject( info.hbmMask );
1468 else ioctl_set_cursor( 0, 0, 0, 0, 0, NULL );
1473 /***********************************************************************
1474 * ANDROID_SetWindowStyle
1476 void CDECL ANDROID_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
1478 struct android_win_data *data;
1479 DWORD changed = style->styleNew ^ style->styleOld;
1481 if (hwnd == GetDesktopWindow()) return;
1482 if (!(data = get_win_data( hwnd ))) return;
1484 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1486 if (is_argb_surface( data->surface ))
1488 if (data->surface) window_surface_release( data->surface );
1489 data->surface = NULL;
1491 else if (data->surface) set_surface_layered( data->surface, 255, CLR_INVALID );
1493 release_win_data( data );
1497 /***********************************************************************
1498 * ANDROID_SetWindowRgn
1500 void CDECL ANDROID_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1502 struct android_win_data *data;
1504 if ((data = get_win_data( hwnd )))
1506 if (data->surface) set_surface_region( data->surface, hrgn );
1507 release_win_data( data );
1509 else FIXME( "not supported on other process window %p\n", hwnd );
1513 /***********************************************************************
1514 * ANDROID_SetLayeredWindowAttributes
1516 void CDECL ANDROID_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
1518 struct android_win_data *data;
1520 if (!(flags & LWA_ALPHA)) alpha = 255;
1521 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1523 if ((data = get_win_data( hwnd )))
1525 if (data->surface) set_surface_layered( data->surface, alpha, key );
1526 release_win_data( data );
1531 /*****************************************************************************
1532 * ANDROID_UpdateLayeredWindow
1534 BOOL CDECL ANDROID_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1535 const RECT *window_rect )
1537 struct window_surface *surface;
1538 struct android_win_data *data;
1539 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1540 COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
1541 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1542 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1543 void *src_bits, *dst_bits;
1544 RECT rect, src_rect;
1545 HDC hdc = 0;
1546 HBITMAP dib;
1547 BOOL ret = FALSE;
1549 if (!(data = get_win_data( hwnd ))) return FALSE;
1551 rect = *window_rect;
1552 OffsetRect( &rect, -window_rect->left, -window_rect->top );
1554 surface = data->surface;
1555 if (!is_argb_surface( surface ))
1557 if (surface) window_surface_release( surface );
1558 surface = NULL;
1561 if (!surface || !EqualRect( &surface->rect, &rect ))
1563 data->surface = create_surface( data->hwnd, &rect, 255, color_key, TRUE );
1564 if (surface) window_surface_release( surface );
1565 surface = data->surface;
1567 else set_surface_layered( surface, 255, color_key );
1569 if (surface) window_surface_add_ref( surface );
1570 release_win_data( data );
1572 if (!surface) return FALSE;
1573 if (!info->hdcSrc)
1575 window_surface_release( surface );
1576 return TRUE;
1579 dst_bits = surface->funcs->get_info( surface, bmi );
1581 if (!(dib = CreateDIBSection( info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0 ))) goto done;
1582 if (!(hdc = CreateCompatibleDC( 0 ))) goto done;
1584 SelectObject( hdc, dib );
1586 surface->funcs->lock( surface );
1588 if (info->prcDirty)
1590 IntersectRect( &rect, &rect, info->prcDirty );
1591 memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage );
1592 PatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS );
1594 src_rect = rect;
1595 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1596 DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 );
1598 ret = GdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1599 info->hdcSrc, src_rect.left, src_rect.top,
1600 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1601 (info->dwFlags & ULW_ALPHA) ? *info->pblend : blend );
1602 if (ret)
1604 memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage );
1605 add_bounds_rect( surface->funcs->get_bounds( surface ), &rect );
1608 surface->funcs->unlock( surface );
1609 surface->funcs->flush( surface );
1611 done:
1612 window_surface_release( surface );
1613 if (hdc) DeleteDC( hdc );
1614 if (dib) DeleteObject( dib );
1615 return ret;
1619 /**********************************************************************
1620 * ANDROID_WindowMessage
1622 LRESULT CDECL ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1624 struct android_win_data *data;
1626 switch (msg)
1628 case WM_ANDROID_REFRESH:
1629 if (wp) /* opengl client window */
1631 update_gl_drawable( hwnd );
1633 else if ((data = get_win_data( hwnd )))
1635 struct window_surface *surface = data->surface;
1636 if (surface)
1638 surface->funcs->lock( surface );
1639 *surface->funcs->get_bounds( surface ) = surface->rect;
1640 surface->funcs->unlock( surface );
1641 if (is_argb_surface( surface )) surface->funcs->flush( surface );
1643 release_win_data( data );
1645 return 0;
1646 default:
1647 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
1648 return 0;
1653 /***********************************************************************
1654 * ANDROID_create_desktop
1656 BOOL CDECL ANDROID_create_desktop( UINT width, UINT height )
1658 desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( GetDesktopWindow(), GWLP_WNDPROC,
1659 (LONG_PTR)desktop_wndproc_wrapper );
1661 /* wait until we receive the surface changed event */
1662 while (!screen_width)
1664 if (wait_events( 2000 ) != 1)
1666 ERR( "wait timed out\n" );
1667 break;
1669 process_events( QS_ALLINPUT );
1671 return TRUE;