wineandroid: Use the user driver interface to create host desktops.
[wine.git] / dlls / wineandroid.drv / window.c
blob2b65f80493851e975bee09a519cc69b434d3a6a7
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 #if 0
24 #pragma makedep unix
25 #endif
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
30 #include "config.h"
32 #include <assert.h>
33 #include <fcntl.h>
34 #include <poll.h>
35 #include <errno.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <unistd.h>
41 #define OEMRESOURCE
42 #include "windef.h"
43 #include "winbase.h"
44 #include "wingdi.h"
45 #include "winuser.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 pthread_mutex_t win_data_mutex;
69 static struct android_win_data *win_data_context[32768];
71 static inline int context_idx( HWND hwnd )
73 return LOWORD( hwnd ) >> 1;
76 static void set_surface_region( struct window_surface *window_surface, HRGN win_region );
78 /* only for use on sanitized BITMAPINFO structures */
79 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
81 if (info->bmiHeader.biCompression == BI_BITFIELDS)
82 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
83 if (coloruse == DIB_PAL_COLORS)
84 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
85 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
88 static inline int get_dib_stride( int width, int bpp )
90 return ((width * bpp + 31) >> 3) & ~3;
93 static inline int get_dib_image_size( const BITMAPINFO *info )
95 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
96 * abs( info->bmiHeader.biHeight );
99 static BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 )
101 dst->left = max(src1->left, src2->left);
102 dst->top = max(src1->top, src2->top);
103 dst->right = min(src1->right, src2->right);
104 dst->bottom = min(src1->bottom, src2->bottom);
105 return !IsRectEmpty( dst );
109 /**********************************************************************
110 * get_win_monitor_dpi
112 static UINT get_win_monitor_dpi( HWND hwnd )
114 return NtUserGetSystemDpiForProcess( NULL ); /* FIXME: get monitor dpi */
118 /***********************************************************************
119 * alloc_win_data
121 static struct android_win_data *alloc_win_data( HWND hwnd )
123 struct android_win_data *data;
125 if ((data = calloc( 1, sizeof(*data) )))
127 data->hwnd = hwnd;
128 data->window = create_ioctl_window( hwnd, FALSE,
129 (float)get_win_monitor_dpi( hwnd ) / NtUserGetDpiForWindow( hwnd ));
130 pthread_mutex_lock( &win_data_mutex );
131 win_data_context[context_idx(hwnd)] = data;
133 return data;
137 /***********************************************************************
138 * free_win_data
140 static void free_win_data( struct android_win_data *data )
142 win_data_context[context_idx( data->hwnd )] = NULL;
143 pthread_mutex_unlock( &win_data_mutex );
144 if (data->window) release_ioctl_window( data->window );
145 free( data );
149 /***********************************************************************
150 * get_win_data
152 * Lock and return the data structure associated with a window.
154 static struct android_win_data *get_win_data( HWND hwnd )
156 struct android_win_data *data;
158 if (!hwnd) return NULL;
159 pthread_mutex_lock( &win_data_mutex );
160 if ((data = win_data_context[context_idx(hwnd)]) && data->hwnd == hwnd) return data;
161 pthread_mutex_unlock( &win_data_mutex );
162 return NULL;
166 /***********************************************************************
167 * release_win_data
169 * Release the data returned by get_win_data.
171 static void release_win_data( struct android_win_data *data )
173 if (data) pthread_mutex_unlock( &win_data_mutex );
177 /***********************************************************************
178 * get_ioctl_window
180 static struct ANativeWindow *get_ioctl_window( HWND hwnd )
182 struct ANativeWindow *ret;
183 struct android_win_data *data = get_win_data( hwnd );
185 if (!data || !data->window) return NULL;
186 ret = grab_ioctl_window( data->window );
187 release_win_data( data );
188 return ret;
192 /* Handling of events coming from the Java side */
194 struct java_event
196 struct list entry;
197 union event_data data;
200 static struct list event_queue = LIST_INIT( event_queue );
201 static struct java_event *current_event;
202 static int event_pipe[2];
203 static DWORD desktop_tid;
205 /***********************************************************************
206 * send_event
208 int send_event( const union event_data *data )
210 int res;
212 if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
214 p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
215 return -1;
217 return 0;
221 /***********************************************************************
222 * desktop_changed
224 * JNI callback, runs in the context of the Java thread.
226 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
228 union event_data data;
230 memset( &data, 0, sizeof(data) );
231 data.type = DESKTOP_CHANGED;
232 data.desktop.width = width;
233 data.desktop.height = height;
234 p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
235 send_event( &data );
239 /***********************************************************************
240 * config_changed
242 * JNI callback, runs in the context of the Java thread.
244 void config_changed( JNIEnv *env, jobject obj, jint dpi )
246 union event_data data;
248 memset( &data, 0, sizeof(data) );
249 data.type = CONFIG_CHANGED;
250 data.cfg.dpi = dpi;
251 p__android_log_print( ANDROID_LOG_INFO, "wine", "config_changed: %u dpi", dpi );
252 send_event( &data );
256 /***********************************************************************
257 * surface_changed
259 * JNI callback, runs in the context of the Java thread.
261 void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jboolean client )
263 union event_data data;
265 memset( &data, 0, sizeof(data) );
266 data.surface.hwnd = LongToHandle( win );
267 data.surface.client = client;
268 if (surface)
270 int width, height;
271 ANativeWindow *win = pANativeWindow_fromSurface( env, surface );
273 if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0;
274 if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0;
275 data.surface.window = win;
276 data.surface.width = width;
277 data.surface.height = height;
278 p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %s %ux%u",
279 data.surface.hwnd, client ? "client" : "whole", width, height );
281 data.type = SURFACE_CHANGED;
282 send_event( &data );
286 /***********************************************************************
287 * motion_event
289 * JNI callback, runs in the context of the Java thread.
291 jboolean motion_event( JNIEnv *env, jobject obj, jint win, jint action, jint x, jint y, jint state, jint vscroll )
293 static LONG button_state;
294 union event_data data;
295 int prev_state;
297 int mask = action & AMOTION_EVENT_ACTION_MASK;
299 if (!( mask == AMOTION_EVENT_ACTION_DOWN ||
300 mask == AMOTION_EVENT_ACTION_UP ||
301 mask == AMOTION_EVENT_ACTION_CANCEL ||
302 mask == AMOTION_EVENT_ACTION_SCROLL ||
303 mask == AMOTION_EVENT_ACTION_MOVE ||
304 mask == AMOTION_EVENT_ACTION_HOVER_MOVE ||
305 mask == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
306 mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE ))
307 return JNI_FALSE;
309 /* make sure a subsequent AMOTION_EVENT_ACTION_UP is not treated as a touch event */
310 if (mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE) state |= 0x80000000;
312 prev_state = InterlockedExchange( &button_state, state );
314 data.type = MOTION_EVENT;
315 data.motion.hwnd = LongToHandle( win );
316 data.motion.input.type = INPUT_MOUSE;
317 data.motion.input.u.mi.dx = x;
318 data.motion.input.u.mi.dy = y;
319 data.motion.input.u.mi.mouseData = 0;
320 data.motion.input.u.mi.time = 0;
321 data.motion.input.u.mi.dwExtraInfo = 0;
322 data.motion.input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
323 switch (action & AMOTION_EVENT_ACTION_MASK)
325 case AMOTION_EVENT_ACTION_DOWN:
326 case AMOTION_EVENT_ACTION_BUTTON_PRESS:
327 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_PRIMARY)
328 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
329 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_SECONDARY)
330 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
331 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_TERTIARY)
332 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
333 if (!(state & ~prev_state)) /* touch event */
334 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
335 break;
336 case AMOTION_EVENT_ACTION_UP:
337 case AMOTION_EVENT_ACTION_CANCEL:
338 case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
339 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_PRIMARY)
340 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
341 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_SECONDARY)
342 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
343 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_TERTIARY)
344 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
345 if (!(prev_state & ~state)) /* touch event */
346 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
347 break;
348 case AMOTION_EVENT_ACTION_SCROLL:
349 data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_WHEEL;
350 data.motion.input.u.mi.mouseData = vscroll < 0 ? -WHEEL_DELTA : WHEEL_DELTA;
351 break;
352 case AMOTION_EVENT_ACTION_MOVE:
353 case AMOTION_EVENT_ACTION_HOVER_MOVE:
354 break;
355 default:
356 return JNI_FALSE;
358 send_event( &data );
359 return JNI_TRUE;
363 /***********************************************************************
364 * init_event_queue
366 static void init_event_queue(void)
368 HANDLE handle;
369 int ret;
371 if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
373 ERR( "could not create data\n" );
374 NtTerminateProcess( 0, 1 );
376 if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
378 ERR( "Can't allocate handle for event fd\n" );
379 NtTerminateProcess( 0, 1 );
381 SERVER_START_REQ( set_queue_fd )
383 req->handle = wine_server_obj_handle( handle );
384 ret = wine_server_call( req );
386 SERVER_END_REQ;
387 if (ret)
389 ERR( "Can't store handle for event fd %x\n", ret );
390 NtTerminateProcess( 0, 1 );
392 NtClose( handle );
393 desktop_tid = GetCurrentThreadId();
397 /***********************************************************************
398 * pull_events
400 * Pull events from the event pipe and add them to the queue
402 static void pull_events(void)
404 struct java_event *event;
405 int res;
407 for (;;)
409 if (!(event = malloc( sizeof(*event) ))) break;
411 res = read( event_pipe[0], &event->data, sizeof(event->data) );
412 if (res != sizeof(event->data)) break;
413 list_add_tail( &event_queue, &event->entry );
415 free( event );
419 /***********************************************************************
420 * process_events
422 static int process_events( DWORD mask )
424 DPI_AWARENESS_CONTEXT context;
425 struct java_event *event, *next, *previous;
426 unsigned int count = 0;
428 assert( GetCurrentThreadId() == desktop_tid );
430 pull_events();
432 previous = current_event;
434 LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
436 switch (event->data.type)
438 case SURFACE_CHANGED:
439 break; /* always process it to unblock other threads */
440 case MOTION_EVENT:
441 if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|
442 MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_LEFTUP|
443 MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
445 if (mask & QS_MOUSEBUTTON) break;
447 else if (mask & QS_MOUSEMOVE) break;
448 continue; /* skip it */
449 case KEYBOARD_EVENT:
450 if (mask & QS_KEY) break;
451 continue; /* skip it */
452 default:
453 if (mask & QS_SENDMESSAGE) break;
454 continue; /* skip it */
457 /* remove it first, in case we process events recursively */
458 list_remove( &event->entry );
459 current_event = event;
461 switch (event->data.type)
463 case DESKTOP_CHANGED:
464 TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
465 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
466 screen_width = event->data.desktop.width;
467 screen_height = event->data.desktop.height;
468 init_monitors( screen_width, screen_height );
469 NtUserSetWindowPos( NtUserGetDesktopWindow(), 0, 0, 0, screen_width, screen_height,
470 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
471 SetThreadDpiAwarenessContext( context );
472 break;
474 case CONFIG_CHANGED:
475 TRACE( "CONFIG_CHANGED dpi %u\n", event->data.cfg.dpi );
476 set_screen_dpi( event->data.cfg.dpi );
477 break;
479 case SURFACE_CHANGED:
480 TRACE("SURFACE_CHANGED %p %p %s size %ux%u\n", event->data.surface.hwnd,
481 event->data.surface.window, event->data.surface.client ? "client" : "whole",
482 event->data.surface.width, event->data.surface.height );
484 register_native_window( event->data.surface.hwnd, event->data.surface.window, event->data.surface.client );
485 break;
487 case MOTION_EVENT:
489 HWND capture = get_capture_window();
491 if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_MIDDLEDOWN))
492 TRACE( "BUTTONDOWN pos %d,%d hwnd %p flags %x\n",
493 (int)event->data.motion.input.u.mi.dx, (int)event->data.motion.input.u.mi.dy,
494 event->data.motion.hwnd, (int)event->data.motion.input.u.mi.dwFlags );
495 else if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTUP|MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
496 TRACE( "BUTTONUP pos %d,%d hwnd %p flags %x\n",
497 (int)event->data.motion.input.u.mi.dx, (int)event->data.motion.input.u.mi.dy,
498 event->data.motion.hwnd, (int)event->data.motion.input.u.mi.dwFlags );
499 else
500 TRACE( "MOUSEMOVE pos %d,%d hwnd %p flags %x\n",
501 (int)event->data.motion.input.u.mi.dx, (int)event->data.motion.input.u.mi.dy,
502 event->data.motion.hwnd, (int)event->data.motion.input.u.mi.dwFlags );
503 if (!capture && (event->data.motion.input.u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE))
505 RECT rect;
506 SetRect( &rect, event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
507 event->data.motion.input.u.mi.dx + 1, event->data.motion.input.u.mi.dy + 1 );
509 SERVER_START_REQ( update_window_zorder )
511 req->window = wine_server_user_handle( event->data.motion.hwnd );
512 req->rect.left = rect.left;
513 req->rect.top = rect.top;
514 req->rect.right = rect.right;
515 req->rect.bottom = rect.bottom;
516 wine_server_call( req );
518 SERVER_END_REQ;
520 __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, NULL );
522 break;
524 case KEYBOARD_EVENT:
525 if (event->data.kbd.input.u.ki.dwFlags & KEYEVENTF_KEYUP)
526 TRACE("KEYUP hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
527 event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk,
528 event->data.kbd.input.u.ki.wScan );
529 else
530 TRACE("KEYDOWN 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 update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state );
534 __wine_send_input( 0, &event->data.kbd.input, NULL );
535 break;
537 default:
538 FIXME( "got event %u\n", event->data.type );
540 free( event );
541 count++;
542 /* next may have been removed by a recursive call, so reset it to the beginning of the list */
543 next = LIST_ENTRY( event_queue.next, struct java_event, entry );
545 current_event = previous;
546 return count;
550 /***********************************************************************
551 * wait_events
553 static int wait_events( int timeout )
555 assert( GetCurrentThreadId() == desktop_tid );
557 for (;;)
559 struct pollfd pollfd;
560 int ret;
562 pollfd.fd = event_pipe[0];
563 pollfd.events = POLLIN | POLLHUP;
564 ret = poll( &pollfd, 1, timeout );
565 if (ret == -1 && errno == EINTR) continue;
566 if (ret && (pollfd.revents & (POLLHUP | POLLERR))) ret = -1;
567 return ret;
572 /* Window surface support */
574 struct android_window_surface
576 struct window_surface header;
577 HWND hwnd;
578 ANativeWindow *window;
579 RECT bounds;
580 BOOL byteswap;
581 RGNDATA *region_data;
582 HRGN region;
583 BYTE alpha;
584 COLORREF color_key;
585 void *bits;
586 pthread_mutex_t mutex;
587 BITMAPINFO info; /* variable size, must be last */
590 static struct android_window_surface *get_android_surface( struct window_surface *surface )
592 return (struct android_window_surface *)surface;
595 static inline void reset_bounds( RECT *bounds )
597 bounds->left = bounds->top = INT_MAX;
598 bounds->right = bounds->bottom = INT_MIN;
601 static inline void add_bounds_rect( RECT *bounds, const RECT *rect )
603 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
604 bounds->left = min( bounds->left, rect->left );
605 bounds->top = min( bounds->top, rect->top );
606 bounds->right = max( bounds->right, rect->right );
607 bounds->bottom = max( bounds->bottom, rect->bottom );
610 /* store the palette or color mask data in the bitmap info structure */
611 static void set_color_info( BITMAPINFO *info, BOOL has_alpha )
613 DWORD *colors = (DWORD *)info->bmiColors;
615 info->bmiHeader.biSize = sizeof(info->bmiHeader);
616 info->bmiHeader.biClrUsed = 0;
617 info->bmiHeader.biBitCount = 32;
618 if (has_alpha)
620 info->bmiHeader.biCompression = BI_RGB;
621 return;
623 info->bmiHeader.biCompression = BI_BITFIELDS;
624 colors[0] = 0xff0000;
625 colors[1] = 0x00ff00;
626 colors[2] = 0x0000ff;
629 /* apply the window region to a single line of the destination image. */
630 static void apply_line_region( DWORD *dst, int width, int x, int y, const RECT *rect, const RECT *end )
632 while (rect < end && rect->top <= y && width > 0)
634 if (rect->left > x)
636 memset( dst, 0, min( rect->left - x, width ) * sizeof(*dst) );
637 dst += rect->left - x;
638 width -= rect->left - x;
639 x = rect->left;
641 if (rect->right > x)
643 dst += rect->right - x;
644 width -= rect->right - x;
645 x = rect->right;
647 rect++;
649 if (width > 0) memset( dst, 0, width * sizeof(*dst) );
652 /***********************************************************************
653 * android_surface_lock
655 static void android_surface_lock( struct window_surface *window_surface )
657 struct android_window_surface *surface = get_android_surface( window_surface );
659 pthread_mutex_lock( &surface->mutex );
662 /***********************************************************************
663 * android_surface_unlock
665 static void android_surface_unlock( struct window_surface *window_surface )
667 struct android_window_surface *surface = get_android_surface( window_surface );
669 pthread_mutex_unlock( &surface->mutex );
672 /***********************************************************************
673 * android_surface_get_bitmap_info
675 static void *android_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
677 struct android_window_surface *surface = get_android_surface( window_surface );
679 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
680 return surface->bits;
683 /***********************************************************************
684 * android_surface_get_bounds
686 static RECT *android_surface_get_bounds( struct window_surface *window_surface )
688 struct android_window_surface *surface = get_android_surface( window_surface );
690 return &surface->bounds;
693 /***********************************************************************
694 * android_surface_set_region
696 static void android_surface_set_region( struct window_surface *window_surface, HRGN region )
698 struct android_window_surface *surface = get_android_surface( window_surface );
700 TRACE( "updating surface %p hwnd %p with %p\n", surface, surface->hwnd, region );
702 window_surface->funcs->lock( window_surface );
703 if (!region)
705 if (surface->region) NtGdiDeleteObjectApp( surface->region );
706 surface->region = 0;
708 else
710 if (!surface->region) surface->region = NtGdiCreateRectRgn( 0, 0, 0, 0 );
711 NtGdiCombineRgn( surface->region, region, 0, RGN_COPY );
713 window_surface->funcs->unlock( window_surface );
714 set_surface_region( &surface->header, (HRGN)1 );
717 /***********************************************************************
718 * android_surface_flush
720 static void android_surface_flush( struct window_surface *window_surface )
722 struct android_window_surface *surface = get_android_surface( window_surface );
723 ANativeWindow_Buffer buffer;
724 ARect rc;
725 RECT rect;
726 BOOL needs_flush;
728 window_surface->funcs->lock( window_surface );
729 SetRect( &rect, 0, 0, surface->header.rect.right - surface->header.rect.left,
730 surface->header.rect.bottom - surface->header.rect.top );
731 needs_flush = intersect_rect( &rect, &rect, &surface->bounds );
732 reset_bounds( &surface->bounds );
733 window_surface->funcs->unlock( window_surface );
734 if (!needs_flush) return;
736 TRACE( "flushing %p hwnd %p surface %s rect %s bits %p alpha %02x key %08x region %u rects\n",
737 surface, surface->hwnd, wine_dbgstr_rect( &surface->header.rect ),
738 wine_dbgstr_rect( &rect ), surface->bits, surface->alpha, (int)surface->color_key,
739 surface->region_data ? (int)surface->region_data->rdh.nCount : 0 );
741 rc.left = rect.left;
742 rc.top = rect.top;
743 rc.right = rect.right;
744 rc.bottom = rect.bottom;
746 if (!surface->window->perform( surface->window, NATIVE_WINDOW_LOCK, &buffer, &rc ))
748 const RECT *rgn_rect = NULL, *end = NULL;
749 unsigned int *src, *dst;
750 int x, y, width;
752 rect.left = rc.left;
753 rect.top = rc.top;
754 rect.right = rc.right;
755 rect.bottom = rc.bottom;
756 intersect_rect( &rect, &rect, &surface->header.rect );
758 if (surface->region_data)
760 rgn_rect = (RECT *)surface->region_data->Buffer;
761 end = rgn_rect + surface->region_data->rdh.nCount;
763 src = (unsigned int *)surface->bits
764 + (rect.top - surface->header.rect.top) * surface->info.bmiHeader.biWidth
765 + (rect.left - surface->header.rect.left);
766 dst = (unsigned int *)buffer.bits + rect.top * buffer.stride + rect.left;
767 width = min( rect.right - rect.left, buffer.stride );
769 for (y = rect.top; y < min( buffer.height, rect.bottom); y++)
771 if (surface->info.bmiHeader.biCompression == BI_RGB)
772 memcpy( dst, src, width * sizeof(*dst) );
773 else if (surface->alpha == 255)
774 for (x = 0; x < width; x++) dst[x] = src[x] | 0xff000000;
775 else
776 for (x = 0; x < width; x++)
777 dst[x] = ((surface->alpha << 24) |
778 (((BYTE)(src[x] >> 16) * surface->alpha / 255) << 16) |
779 (((BYTE)(src[x] >> 8) * surface->alpha / 255) << 8) |
780 (((BYTE)src[x] * surface->alpha / 255)));
782 if (surface->color_key != CLR_INVALID)
783 for (x = 0; x < width; x++) if ((src[x] & 0xffffff) == surface->color_key) dst[x] = 0;
785 if (rgn_rect)
787 while (rgn_rect < end && rgn_rect->bottom <= y) rgn_rect++;
788 apply_line_region( dst, width, rect.left, y, rgn_rect, end );
791 src += surface->info.bmiHeader.biWidth;
792 dst += buffer.stride;
794 surface->window->perform( surface->window, NATIVE_WINDOW_UNLOCK_AND_POST );
796 else TRACE( "Unable to lock surface %p window %p buffer %p\n",
797 surface, surface->hwnd, surface->window );
800 /***********************************************************************
801 * android_surface_destroy
803 static void android_surface_destroy( struct window_surface *window_surface )
805 struct android_window_surface *surface = get_android_surface( window_surface );
807 TRACE( "freeing %p bits %p\n", surface, surface->bits );
809 free( surface->region_data );
810 if (surface->region) NtGdiDeleteObjectApp( surface->region );
811 release_ioctl_window( surface->window );
812 free( surface->bits );
813 free( surface );
816 static const struct window_surface_funcs android_surface_funcs =
818 android_surface_lock,
819 android_surface_unlock,
820 android_surface_get_bitmap_info,
821 android_surface_get_bounds,
822 android_surface_set_region,
823 android_surface_flush,
824 android_surface_destroy
827 static BOOL is_argb_surface( struct window_surface *surface )
829 return surface && surface->funcs == &android_surface_funcs &&
830 get_android_surface( surface )->info.bmiHeader.biCompression == BI_RGB;
833 /***********************************************************************
834 * set_color_key
836 static void set_color_key( struct android_window_surface *surface, COLORREF key )
838 if (key == CLR_INVALID)
839 surface->color_key = CLR_INVALID;
840 else if (surface->info.bmiHeader.biBitCount <= 8)
841 surface->color_key = CLR_INVALID;
842 else if (key & (1 << 24)) /* PALETTEINDEX */
843 surface->color_key = 0;
844 else if (key >> 16 == 0x10ff) /* DIBINDEX */
845 surface->color_key = 0;
846 else if (surface->info.bmiHeader.biBitCount == 24)
847 surface->color_key = key;
848 else
849 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
852 /***********************************************************************
853 * set_surface_region
855 static void set_surface_region( struct window_surface *window_surface, HRGN win_region )
857 struct android_window_surface *surface = get_android_surface( window_surface );
858 struct android_win_data *win_data;
859 HRGN region = win_region;
860 RGNDATA *data = NULL;
861 DWORD size;
862 int offset_x, offset_y;
864 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
866 if (!(win_data = get_win_data( surface->hwnd ))) return;
867 offset_x = win_data->window_rect.left - win_data->whole_rect.left;
868 offset_y = win_data->window_rect.top - win_data->whole_rect.top;
869 release_win_data( win_data );
871 if (win_region == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
873 region = NtGdiCreateRectRgn( 0, 0, win_data->window_rect.right - win_data->window_rect.left,
874 win_data->window_rect.bottom - win_data->window_rect.top );
875 if (NtUserGetWindowRgnEx( surface->hwnd, region, 0 ) == ERROR && !surface->region) goto done;
878 NtGdiOffsetRgn( region, offset_x, offset_y );
879 if (surface->region) NtGdiCombineRgn( region, region, surface->region, RGN_AND );
881 if (!(size = NtGdiGetRegionData( region, 0, NULL ))) goto done;
882 if (!(data = malloc( size ))) goto done;
884 if (!NtGdiGetRegionData( region, size, data ))
886 free( data );
887 data = NULL;
890 done:
891 window_surface->funcs->lock( window_surface );
892 free( surface->region_data );
893 surface->region_data = data;
894 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
895 window_surface->funcs->unlock( window_surface );
896 if (region != win_region) NtGdiDeleteObjectApp( region );
899 /***********************************************************************
900 * create_surface
902 static struct window_surface *create_surface( HWND hwnd, const RECT *rect,
903 BYTE alpha, COLORREF color_key, BOOL src_alpha )
905 struct android_window_surface *surface;
906 int width = rect->right - rect->left, height = rect->bottom - rect->top;
907 pthread_mutexattr_t attr;
909 surface = calloc( 1, FIELD_OFFSET( struct android_window_surface, info.bmiColors[3] ));
910 if (!surface) return NULL;
911 set_color_info( &surface->info, src_alpha );
912 surface->info.bmiHeader.biWidth = width;
913 surface->info.bmiHeader.biHeight = -height; /* top-down */
914 surface->info.bmiHeader.biPlanes = 1;
915 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
917 pthread_mutexattr_init( &attr );
918 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
919 pthread_mutex_init( &surface->mutex, &attr );
920 pthread_mutexattr_destroy( &attr );
922 surface->header.funcs = &android_surface_funcs;
923 surface->header.rect = *rect;
924 surface->header.ref = 1;
925 surface->hwnd = hwnd;
926 surface->window = get_ioctl_window( hwnd );
927 surface->alpha = alpha;
928 set_color_key( surface, color_key );
929 set_surface_region( &surface->header, (HRGN)1 );
930 reset_bounds( &surface->bounds );
932 if (!(surface->bits = malloc( surface->info.bmiHeader.biSizeImage )))
933 goto failed;
935 TRACE( "created %p hwnd %p %s bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect),
936 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage );
938 return &surface->header;
940 failed:
941 android_surface_destroy( &surface->header );
942 return NULL;
945 /***********************************************************************
946 * set_surface_layered
948 static void set_surface_layered( struct window_surface *window_surface, BYTE alpha, COLORREF color_key )
950 struct android_window_surface *surface = get_android_surface( window_surface );
951 COLORREF prev_key;
952 BYTE prev_alpha;
954 if (window_surface->funcs != &android_surface_funcs) return; /* we may get the null surface */
956 window_surface->funcs->lock( window_surface );
957 prev_key = surface->color_key;
958 prev_alpha = surface->alpha;
959 surface->alpha = alpha;
960 set_color_key( surface, color_key );
961 if (alpha != prev_alpha || surface->color_key != prev_key) /* refresh */
962 *window_surface->funcs->get_bounds( window_surface ) = surface->header.rect;
963 window_surface->funcs->unlock( window_surface );
966 /***********************************************************************
967 * get_mono_icon_argb
969 * Return a monochrome icon/cursor bitmap bits in ARGB format.
971 static unsigned int *get_mono_icon_argb( HDC hdc, HBITMAP bmp, unsigned int *width, unsigned int *height )
973 BITMAP bm;
974 char *mask;
975 unsigned int i, j, stride, mask_size, bits_size, *bits = NULL, *ptr;
977 if (!NtGdiExtGetObjectW( bmp, sizeof(bm), &bm )) return NULL;
978 stride = ((bm.bmWidth + 15) >> 3) & ~1;
979 mask_size = stride * bm.bmHeight;
980 if (!(mask = malloc( mask_size ))) return NULL;
981 if (!NtGdiGetBitmapBits( bmp, mask_size, mask )) goto done;
983 bm.bmHeight /= 2;
984 bits_size = bm.bmWidth * bm.bmHeight * sizeof(*bits);
985 if (!(bits = malloc( bits_size ))) goto done;
987 ptr = bits;
988 for (i = 0; i < bm.bmHeight; i++)
989 for (j = 0; j < bm.bmWidth; j++, ptr++)
991 int and = ((mask[i * stride + j / 8] << (j % 8)) & 0x80);
992 int xor = ((mask[(i + bm.bmHeight) * stride + j / 8] << (j % 8)) & 0x80);
993 if (!xor && and)
994 *ptr = 0;
995 else if (xor && !and)
996 *ptr = 0xffffffff;
997 else
998 /* we can't draw "invert" pixels, so render them as black instead */
999 *ptr = 0xff000000;
1002 *width = bm.bmWidth;
1003 *height = bm.bmHeight;
1005 done:
1006 free( mask );
1007 return bits;
1010 /***********************************************************************
1011 * get_bitmap_argb
1013 * Return the bitmap bits in ARGB format. Helper for setting icons and cursors.
1015 static unsigned int *get_bitmap_argb( HDC hdc, HBITMAP color, HBITMAP mask, unsigned int *width,
1016 unsigned int *height )
1018 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1019 BITMAPINFO *info = (BITMAPINFO *)buffer;
1020 BITMAP bm;
1021 unsigned int *ptr, *bits = NULL;
1022 unsigned char *mask_bits = NULL;
1023 int i, j;
1024 BOOL has_alpha = FALSE;
1026 if (!color) return get_mono_icon_argb( hdc, mask, width, height );
1028 if (!NtGdiExtGetObjectW( color, sizeof(bm), &bm )) return NULL;
1029 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1030 info->bmiHeader.biWidth = bm.bmWidth;
1031 info->bmiHeader.biHeight = -bm.bmHeight;
1032 info->bmiHeader.biPlanes = 1;
1033 info->bmiHeader.biBitCount = 32;
1034 info->bmiHeader.biCompression = BI_RGB;
1035 info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
1036 info->bmiHeader.biXPelsPerMeter = 0;
1037 info->bmiHeader.biYPelsPerMeter = 0;
1038 info->bmiHeader.biClrUsed = 0;
1039 info->bmiHeader.biClrImportant = 0;
1040 if (!(bits = malloc( bm.bmWidth * bm.bmHeight * sizeof(unsigned int) )))
1041 goto failed;
1042 if (!NtGdiGetDIBitsInternal( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS, 0, 0 ))
1043 goto failed;
1045 *width = bm.bmWidth;
1046 *height = bm.bmHeight;
1048 for (i = 0; i < bm.bmWidth * bm.bmHeight; i++)
1049 if ((has_alpha = (bits[i] & 0xff000000) != 0)) break;
1051 if (!has_alpha)
1053 unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4;
1054 /* generate alpha channel from the mask */
1055 info->bmiHeader.biBitCount = 1;
1056 info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight;
1057 if (!(mask_bits = malloc( info->bmiHeader.biSizeImage ))) goto failed;
1058 if (!NtGdiGetDIBitsInternal( hdc, mask, 0, bm.bmHeight, mask_bits, info, DIB_RGB_COLORS, 0, 0 ))
1059 goto failed;
1060 ptr = bits;
1061 for (i = 0; i < bm.bmHeight; i++)
1062 for (j = 0; j < bm.bmWidth; j++, ptr++)
1063 if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000;
1064 free( mask_bits );
1067 return bits;
1069 failed:
1070 free( bits );
1071 free( mask_bits );
1072 *width = *height = 0;
1073 return NULL;
1077 enum android_system_cursors
1079 TYPE_ARROW = 1000,
1080 TYPE_CONTEXT_MENU = 1001,
1081 TYPE_HAND = 1002,
1082 TYPE_HELP = 1003,
1083 TYPE_WAIT = 1004,
1084 TYPE_CELL = 1006,
1085 TYPE_CROSSHAIR = 1007,
1086 TYPE_TEXT = 1008,
1087 TYPE_VERTICAL_TEXT = 1009,
1088 TYPE_ALIAS = 1010,
1089 TYPE_COPY = 1011,
1090 TYPE_NO_DROP = 1012,
1091 TYPE_ALL_SCROLL = 1013,
1092 TYPE_HORIZONTAL_DOUBLE_ARROW = 1014,
1093 TYPE_VERTICAL_DOUBLE_ARROW = 1015,
1094 TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016,
1095 TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017,
1096 TYPE_ZOOM_IN = 1018,
1097 TYPE_ZOOM_OUT = 1019,
1098 TYPE_GRAB = 1020,
1099 TYPE_GRABBING = 1021,
1102 struct system_cursors
1104 WORD id;
1105 enum android_system_cursors android_id;
1108 static const struct system_cursors user32_cursors[] =
1110 { OCR_NORMAL, TYPE_ARROW },
1111 { OCR_IBEAM, TYPE_TEXT },
1112 { OCR_WAIT, TYPE_WAIT },
1113 { OCR_CROSS, TYPE_CROSSHAIR },
1114 { OCR_SIZE, TYPE_ALL_SCROLL },
1115 { OCR_SIZEALL, TYPE_ALL_SCROLL },
1116 { OCR_SIZENWSE, TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW },
1117 { OCR_SIZENESW, TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW },
1118 { OCR_SIZEWE, TYPE_HORIZONTAL_DOUBLE_ARROW },
1119 { OCR_SIZENS, TYPE_VERTICAL_DOUBLE_ARROW },
1120 { OCR_NO, TYPE_NO_DROP },
1121 { OCR_HAND, TYPE_HAND },
1122 { OCR_HELP, TYPE_HELP },
1123 { 0 }
1126 static const struct system_cursors comctl32_cursors[] =
1128 /* 102 TYPE_MOVE doesn't exist */
1129 { 104, TYPE_COPY },
1130 { 105, TYPE_ARROW },
1131 { 106, TYPE_HORIZONTAL_DOUBLE_ARROW },
1132 { 107, TYPE_HORIZONTAL_DOUBLE_ARROW },
1133 { 108, TYPE_GRABBING },
1134 { 135, TYPE_VERTICAL_DOUBLE_ARROW },
1135 { 0 }
1138 static const struct system_cursors ole32_cursors[] =
1140 { 1, TYPE_NO_DROP },
1141 /* 2 TYPE_MOVE doesn't exist */
1142 { 3, TYPE_COPY },
1143 { 4, TYPE_ALIAS },
1144 { 0 }
1147 static const struct system_cursors riched20_cursors[] =
1149 { 105, TYPE_GRABBING },
1150 { 109, TYPE_COPY },
1151 /* 110 TYPE_MOVE doesn't exist */
1152 { 111, TYPE_NO_DROP },
1153 { 0 }
1156 static const struct
1158 const struct system_cursors *cursors;
1159 WCHAR name[16];
1160 } module_cursors[] =
1162 { user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
1163 { comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
1164 { ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
1165 { riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
1168 static int get_cursor_system_id( const ICONINFOEXW *info )
1170 const struct system_cursors *cursors;
1171 const WCHAR *module;
1172 unsigned int i;
1174 if (info->szResName[0]) return 0; /* only integer resources are supported here */
1176 if ((module = wcsrchr( info->szModName, '\\' ))) module++;
1177 else module = info->szModName;
1178 for (i = 0; i < ARRAY_SIZE( module_cursors ); i++)
1179 if (!wcsicmp( module, module_cursors[i].name )) break;
1180 if (i == ARRAY_SIZE( module_cursors )) return 0;
1182 cursors = module_cursors[i].cursors;
1183 for (i = 0; cursors[i].id; i++)
1184 if (cursors[i].id == info->wResID) return cursors[i].android_id;
1186 return 0;
1190 LRESULT ANDROID_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1192 switch (msg)
1194 case WM_PARENTNOTIFY:
1195 if (LOWORD(wp) == WM_DESTROY) destroy_ioctl_window( (HWND)lp, FALSE );
1196 break;
1198 return NtUserMessageCall( hwnd, msg, wp, lp, 0, NtUserDefWindowProc, FALSE );
1202 /***********************************************************************
1203 * ANDROID_ProcessEvents
1205 BOOL ANDROID_ProcessEvents( DWORD mask )
1207 if (GetCurrentThreadId() == desktop_tid)
1209 /* don't process nested events */
1210 if (current_event) mask = 0;
1211 return process_events( mask );
1213 return FALSE;
1216 /**********************************************************************
1217 * ANDROID_CreateWindow
1219 BOOL ANDROID_CreateWindow( HWND hwnd )
1221 TRACE( "%p\n", hwnd );
1223 if (hwnd == NtUserGetDesktopWindow())
1225 struct android_win_data *data;
1227 init_event_queue();
1228 start_android_device();
1229 if (!(data = alloc_win_data( hwnd ))) return FALSE;
1230 release_win_data( data );
1232 return TRUE;
1236 /***********************************************************************
1237 * ANDROID_DestroyWindow
1239 void ANDROID_DestroyWindow( HWND hwnd )
1241 struct android_win_data *data;
1243 if (!(data = get_win_data( hwnd ))) return;
1245 if (data->surface) window_surface_release( data->surface );
1246 data->surface = NULL;
1247 destroy_gl_drawable( hwnd );
1248 free_win_data( data );
1252 /***********************************************************************
1253 * create_win_data
1255 * Create a data window structure for an existing window.
1257 static struct android_win_data *create_win_data( HWND hwnd, const RECT *window_rect,
1258 const RECT *client_rect )
1260 struct android_win_data *data;
1261 HWND parent;
1263 if (!(parent = NtUserGetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop or HWND_MESSAGE */
1265 if (!(data = alloc_win_data( hwnd ))) return NULL;
1267 data->parent = (parent == NtUserGetDesktopWindow()) ? 0 : parent;
1268 data->whole_rect = data->window_rect = *window_rect;
1269 data->client_rect = *client_rect;
1270 return data;
1274 static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rect )
1276 if (!intersect_rect( surface_rect, visible_rect, &virtual_screen_rect )) return FALSE;
1277 OffsetRect( surface_rect, -visible_rect->left, -visible_rect->top );
1278 surface_rect->left &= ~31;
1279 surface_rect->top &= ~31;
1280 surface_rect->right = max( surface_rect->left + 32, (surface_rect->right + 31) & ~31 );
1281 surface_rect->bottom = max( surface_rect->top + 32, (surface_rect->bottom + 31) & ~31 );
1282 return TRUE;
1286 /***********************************************************************
1287 * ANDROID_WindowPosChanging
1289 BOOL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
1290 const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
1291 struct window_surface **surface )
1293 struct android_win_data *data = get_win_data( hwnd );
1294 RECT surface_rect;
1295 DWORD flags;
1296 COLORREF key;
1297 BYTE alpha;
1298 BOOL layered = NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED;
1300 TRACE( "win %p window %s client %s style %08x flags %08x\n",
1301 hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1302 (int)NtUserGetWindowLongW( hwnd, GWL_STYLE ), swp_flags );
1304 if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return TRUE;
1306 *visible_rect = *window_rect;
1308 /* create the window surface if necessary */
1310 if (data->parent) goto done;
1311 if (swp_flags & SWP_HIDEWINDOW) goto done;
1312 if (is_argb_surface( data->surface )) goto done;
1313 if (!get_surface_rect( visible_rect, &surface_rect )) goto done;
1315 if (data->surface)
1317 if (!memcmp( &data->surface->rect, &surface_rect, sizeof(surface_rect) ))
1319 /* existing surface is good enough */
1320 window_surface_add_ref( data->surface );
1321 if (*surface) window_surface_release( *surface );
1322 *surface = data->surface;
1323 goto done;
1326 if (!(swp_flags & SWP_SHOWWINDOW) && !(NtUserGetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1327 goto done;
1329 if (!layered || !NtUserGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags )) flags = 0;
1330 if (!(flags & LWA_ALPHA)) alpha = 255;
1331 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1333 if (*surface) window_surface_release( *surface );
1334 *surface = create_surface( data->hwnd, &surface_rect, alpha, key, FALSE );
1336 done:
1337 release_win_data( data );
1338 return TRUE;
1342 /***********************************************************************
1343 * ANDROID_WindowPosChanged
1345 void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
1346 const RECT *window_rect, const RECT *client_rect,
1347 const RECT *visible_rect, const RECT *valid_rects,
1348 struct window_surface *surface )
1350 struct android_win_data *data;
1351 UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
1352 HWND owner = 0;
1354 if (!(data = get_win_data( hwnd ))) return;
1356 data->window_rect = *window_rect;
1357 data->whole_rect = *visible_rect;
1358 data->client_rect = *client_rect;
1360 if (!is_argb_surface( data->surface ))
1362 if (surface) window_surface_add_ref( surface );
1363 if (data->surface) window_surface_release( data->surface );
1364 data->surface = surface;
1366 if (!data->parent) owner = NtUserGetWindowRelative( hwnd, GW_OWNER );
1367 release_win_data( data );
1369 if (!(swp_flags & SWP_NOZORDER)) insert_after = NtUserGetWindowRelative( hwnd, GW_HWNDPREV );
1371 TRACE( "win %p window %s client %s style %08x owner %p after %p flags %08x\n", hwnd,
1372 wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1373 new_style, owner, insert_after, swp_flags );
1375 ioctl_window_pos_changed( hwnd, window_rect, client_rect, visible_rect,
1376 new_style, swp_flags, insert_after, owner );
1380 /***********************************************************************
1381 * ANDROID_ShowWindow
1383 UINT ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
1385 if (!(NtUserGetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)) return swp;
1386 /* always hide icons off-screen */
1387 if (rect->left != -32000 || rect->top != -32000)
1389 OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
1390 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1392 return swp;
1396 /*****************************************************************
1397 * ANDROID_SetParent
1399 void ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent )
1401 struct android_win_data *data;
1403 if (parent == old_parent) return;
1404 if (!(data = get_win_data( hwnd ))) return;
1406 TRACE( "win %p parent %p -> %p\n", hwnd, old_parent, parent );
1408 data->parent = (parent == NtUserGetDesktopWindow()) ? 0 : parent;
1409 ioctl_set_window_parent( hwnd, parent, (float)get_win_monitor_dpi( hwnd ) / NtUserGetDpiForWindow( hwnd ));
1410 release_win_data( data );
1414 /***********************************************************************
1415 * ANDROID_SetCapture
1417 void ANDROID_SetCapture( HWND hwnd, UINT flags )
1419 if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
1420 ioctl_set_capture( hwnd );
1424 static BOOL get_icon_info( HICON handle, ICONINFOEXW *ret )
1426 UNICODE_STRING module, res_name;
1427 ICONINFO info;
1429 module.Buffer = ret->szModName;
1430 module.MaximumLength = sizeof(ret->szModName) - sizeof(WCHAR);
1431 res_name.Buffer = ret->szResName;
1432 res_name.MaximumLength = sizeof(ret->szResName) - sizeof(WCHAR);
1433 if (!NtUserGetIconInfo( handle, &info, &module, &res_name, NULL, 0 )) return FALSE;
1434 ret->fIcon = info.fIcon;
1435 ret->xHotspot = info.xHotspot;
1436 ret->yHotspot = info.yHotspot;
1437 ret->hbmColor = info.hbmColor;
1438 ret->hbmMask = info.hbmMask;
1439 ret->wResID = res_name.Length ? 0 : LOWORD(res_name.Buffer);
1440 ret->szModName[module.Length] = 0;
1441 ret->szResName[res_name.Length] = 0;
1442 return TRUE;
1446 /***********************************************************************
1447 * ANDROID_SetCursor
1449 void ANDROID_SetCursor( HCURSOR handle )
1451 static HCURSOR last_cursor;
1452 static DWORD last_cursor_change;
1454 if (InterlockedExchangePointer( (void **)&last_cursor, handle ) != handle ||
1455 NtGetTickCount() - last_cursor_change > 100)
1457 last_cursor_change = NtGetTickCount();
1459 if (handle)
1461 unsigned int width = 0, height = 0, *bits = NULL;
1462 ICONINFOEXW info;
1463 int id;
1465 if (!get_icon_info( handle, &info )) return;
1467 if (!(id = get_cursor_system_id( &info )))
1469 HDC hdc = NtGdiCreateCompatibleDC( 0 );
1470 bits = get_bitmap_argb( hdc, info.hbmColor, info.hbmMask, &width, &height );
1471 NtGdiDeleteObjectApp( hdc );
1473 /* make sure hotspot is valid */
1474 if (info.xHotspot >= width || info.yHotspot >= height)
1476 info.xHotspot = width / 2;
1477 info.yHotspot = height / 2;
1480 ioctl_set_cursor( id, width, height, info.xHotspot, info.yHotspot, bits );
1481 free( bits );
1482 NtGdiDeleteObjectApp( info.hbmColor );
1483 NtGdiDeleteObjectApp( info.hbmMask );
1485 else ioctl_set_cursor( 0, 0, 0, 0, 0, NULL );
1490 /***********************************************************************
1491 * ANDROID_SetWindowStyle
1493 void ANDROID_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
1495 struct android_win_data *data;
1496 DWORD changed = style->styleNew ^ style->styleOld;
1498 if (hwnd == NtUserGetDesktopWindow()) return;
1499 if (!(data = get_win_data( hwnd ))) return;
1501 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1503 if (is_argb_surface( data->surface ))
1505 if (data->surface) window_surface_release( data->surface );
1506 data->surface = NULL;
1508 else if (data->surface) set_surface_layered( data->surface, 255, CLR_INVALID );
1510 release_win_data( data );
1514 /***********************************************************************
1515 * ANDROID_SetWindowRgn
1517 void ANDROID_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1519 struct android_win_data *data;
1521 if ((data = get_win_data( hwnd )))
1523 if (data->surface) set_surface_region( data->surface, hrgn );
1524 release_win_data( data );
1526 else FIXME( "not supported on other process window %p\n", hwnd );
1530 /***********************************************************************
1531 * ANDROID_SetLayeredWindowAttributes
1533 void ANDROID_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
1535 struct android_win_data *data;
1537 if (!(flags & LWA_ALPHA)) alpha = 255;
1538 if (!(flags & LWA_COLORKEY)) key = CLR_INVALID;
1540 if ((data = get_win_data( hwnd )))
1542 if (data->surface) set_surface_layered( data->surface, alpha, key );
1543 release_win_data( data );
1548 /*****************************************************************************
1549 * ANDROID_UpdateLayeredWindow
1551 BOOL ANDROID_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1552 const RECT *window_rect )
1554 struct window_surface *surface;
1555 struct android_win_data *data;
1556 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1557 COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
1558 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1559 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1560 void *src_bits, *dst_bits;
1561 RECT rect, src_rect;
1562 HDC hdc = 0;
1563 HBITMAP dib;
1564 BOOL ret = FALSE;
1566 if (!(data = get_win_data( hwnd ))) return FALSE;
1568 rect = *window_rect;
1569 OffsetRect( &rect, -window_rect->left, -window_rect->top );
1571 surface = data->surface;
1572 if (!is_argb_surface( surface ))
1574 if (surface) window_surface_release( surface );
1575 surface = NULL;
1578 if (!surface || !EqualRect( &surface->rect, &rect ))
1580 data->surface = create_surface( data->hwnd, &rect, 255, color_key, TRUE );
1581 if (surface) window_surface_release( surface );
1582 surface = data->surface;
1584 else set_surface_layered( surface, 255, color_key );
1586 if (surface) window_surface_add_ref( surface );
1587 release_win_data( data );
1589 if (!surface) return FALSE;
1590 if (!info->hdcSrc)
1592 window_surface_release( surface );
1593 return TRUE;
1596 dst_bits = surface->funcs->get_info( surface, bmi );
1598 if (!(dib = NtGdiCreateDIBSection( info->hdcDst, NULL, 0, bmi, DIB_RGB_COLORS, 0, 0, 0, &src_bits )))
1599 goto done;
1600 if (!(hdc = NtGdiCreateCompatibleDC( 0 ))) goto done;
1602 NtGdiSelectBitmap( hdc, dib );
1604 surface->funcs->lock( surface );
1606 if (info->prcDirty)
1608 intersect_rect( &rect, &rect, info->prcDirty );
1609 memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage );
1610 NtGdiPatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS );
1612 src_rect = rect;
1613 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1614 NtGdiTransformPoints( info->hdcSrc, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiDPtoLP );
1616 if (info->dwFlags & ULW_ALPHA) blend = *info->pblend;
1617 ret = NtGdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1618 info->hdcSrc, src_rect.left, src_rect.top,
1619 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1620 *(DWORD *)&blend, 0 );
1621 if (ret)
1623 memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage );
1624 add_bounds_rect( surface->funcs->get_bounds( surface ), &rect );
1627 surface->funcs->unlock( surface );
1628 surface->funcs->flush( surface );
1630 done:
1631 window_surface_release( surface );
1632 if (hdc) NtGdiDeleteObjectApp( hdc );
1633 if (dib) NtGdiDeleteObjectApp( dib );
1634 return ret;
1638 /**********************************************************************
1639 * ANDROID_WindowMessage
1641 LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1643 struct android_win_data *data;
1645 switch (msg)
1647 case WM_ANDROID_REFRESH:
1648 if (wp) /* opengl client window */
1650 update_gl_drawable( hwnd );
1652 else if ((data = get_win_data( hwnd )))
1654 struct window_surface *surface = data->surface;
1655 if (surface)
1657 surface->funcs->lock( surface );
1658 *surface->funcs->get_bounds( surface ) = surface->rect;
1659 surface->funcs->unlock( surface );
1660 if (is_argb_surface( surface )) surface->funcs->flush( surface );
1662 release_win_data( data );
1664 return 0;
1665 default:
1666 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (long)wp, lp );
1667 return 0;
1672 /***********************************************************************
1673 * ANDROID_CreateDesktop
1675 BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height )
1677 /* wait until we receive the surface changed event */
1678 while (!screen_width)
1680 if (wait_events( 2000 ) != 1)
1682 ERR( "wait timed out\n" );
1683 break;
1685 process_events( QS_ALLINPUT );
1687 return 0;