include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / wineandroid.drv / window.c
blob553ed985fae29eea222e22d8392ed37bfa5f1e71
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 #include "config.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 #include <unistd.h>
38 #define OEMRESOURCE
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
44 #include "android.h"
45 #include "wine/server.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(android);
50 /* private window data */
51 struct android_win_data
53 HWND hwnd; /* hwnd that this private data belongs to */
54 HWND parent; /* parent hwnd for child windows */
55 RECT window_rect; /* USER window rectangle relative to parent */
56 RECT whole_rect; /* X window rectangle for the whole window relative to parent */
57 RECT client_rect; /* client area relative to parent */
58 ANativeWindow *window; /* native window wrapper that forwards calls to the desktop process */
59 struct window_surface *surface;
62 #define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
64 pthread_mutex_t win_data_mutex;
66 static struct android_win_data *win_data_context[32768];
68 static inline int context_idx( HWND hwnd )
70 return LOWORD( hwnd ) >> 1;
73 static inline int get_dib_stride( int width, int bpp )
75 return ((width * bpp + 31) >> 3) & ~3;
78 static inline int get_dib_image_size( const BITMAPINFO *info )
80 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
81 * abs( info->bmiHeader.biHeight );
84 static BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 )
86 dst->left = max(src1->left, src2->left);
87 dst->top = max(src1->top, src2->top);
88 dst->right = min(src1->right, src2->right);
89 dst->bottom = min(src1->bottom, src2->bottom);
90 return !IsRectEmpty( dst );
94 /**********************************************************************
95 * get_win_monitor_dpi
97 UINT get_win_monitor_dpi( HWND hwnd )
99 return NtUserGetSystemDpiForProcess( NULL ); /* FIXME: get monitor dpi */
103 /***********************************************************************
104 * alloc_win_data
106 static struct android_win_data *alloc_win_data( HWND hwnd )
108 struct android_win_data *data;
110 if ((data = calloc( 1, sizeof(*data) )))
112 data->hwnd = hwnd;
113 data->window = create_ioctl_window( hwnd, FALSE,
114 (float)get_win_monitor_dpi( hwnd ) / NtUserGetDpiForWindow( hwnd ));
115 pthread_mutex_lock( &win_data_mutex );
116 win_data_context[context_idx(hwnd)] = data;
118 return data;
122 /***********************************************************************
123 * free_win_data
125 static void free_win_data( struct android_win_data *data )
127 win_data_context[context_idx( data->hwnd )] = NULL;
128 pthread_mutex_unlock( &win_data_mutex );
129 if (data->window) release_ioctl_window( data->window );
130 free( data );
134 /***********************************************************************
135 * get_win_data
137 * Lock and return the data structure associated with a window.
139 static struct android_win_data *get_win_data( HWND hwnd )
141 struct android_win_data *data;
143 if (!hwnd) return NULL;
144 pthread_mutex_lock( &win_data_mutex );
145 if ((data = win_data_context[context_idx(hwnd)]) && data->hwnd == hwnd) return data;
146 pthread_mutex_unlock( &win_data_mutex );
147 return NULL;
151 /***********************************************************************
152 * release_win_data
154 * Release the data returned by get_win_data.
156 static void release_win_data( struct android_win_data *data )
158 if (data) pthread_mutex_unlock( &win_data_mutex );
162 /***********************************************************************
163 * get_ioctl_window
165 static struct ANativeWindow *get_ioctl_window( HWND hwnd )
167 struct ANativeWindow *ret;
168 struct android_win_data *data = get_win_data( hwnd );
170 if (!data || !data->window) return NULL;
171 ret = grab_ioctl_window( data->window );
172 release_win_data( data );
173 return ret;
177 /* Handling of events coming from the Java side */
179 struct java_event
181 struct list entry;
182 union event_data data;
185 static struct list event_queue = LIST_INIT( event_queue );
186 static struct java_event *current_event;
187 static int event_pipe[2];
188 static DWORD desktop_tid;
190 /***********************************************************************
191 * send_event
193 int send_event( const union event_data *data )
195 int res;
197 if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
199 p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
200 return -1;
202 return 0;
206 /***********************************************************************
207 * desktop_changed
209 * JNI callback, runs in the context of the Java thread.
211 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
213 union event_data data;
215 memset( &data, 0, sizeof(data) );
216 data.type = DESKTOP_CHANGED;
217 data.desktop.width = width;
218 data.desktop.height = height;
219 p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
220 send_event( &data );
224 /***********************************************************************
225 * config_changed
227 * JNI callback, runs in the context of the Java thread.
229 void config_changed( JNIEnv *env, jobject obj, jint dpi )
231 union event_data data;
233 memset( &data, 0, sizeof(data) );
234 data.type = CONFIG_CHANGED;
235 data.cfg.dpi = dpi;
236 p__android_log_print( ANDROID_LOG_INFO, "wine", "config_changed: %u dpi", dpi );
237 send_event( &data );
241 /***********************************************************************
242 * surface_changed
244 * JNI callback, runs in the context of the Java thread.
246 void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jboolean client )
248 union event_data data;
250 memset( &data, 0, sizeof(data) );
251 data.surface.hwnd = LongToHandle( win );
252 data.surface.client = client;
253 if (surface)
255 int width, height;
256 ANativeWindow *win = pANativeWindow_fromSurface( env, surface );
258 if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0;
259 if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0;
260 data.surface.window = win;
261 data.surface.width = width;
262 data.surface.height = height;
263 p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %s %ux%u",
264 data.surface.hwnd, client ? "client" : "whole", width, height );
266 data.type = SURFACE_CHANGED;
267 send_event( &data );
271 /***********************************************************************
272 * motion_event
274 * JNI callback, runs in the context of the Java thread.
276 jboolean motion_event( JNIEnv *env, jobject obj, jint win, jint action, jint x, jint y, jint state, jint vscroll )
278 static LONG button_state;
279 union event_data data;
280 int prev_state;
282 int mask = action & AMOTION_EVENT_ACTION_MASK;
284 if (!( mask == AMOTION_EVENT_ACTION_DOWN ||
285 mask == AMOTION_EVENT_ACTION_UP ||
286 mask == AMOTION_EVENT_ACTION_CANCEL ||
287 mask == AMOTION_EVENT_ACTION_SCROLL ||
288 mask == AMOTION_EVENT_ACTION_MOVE ||
289 mask == AMOTION_EVENT_ACTION_HOVER_MOVE ||
290 mask == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
291 mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE ))
292 return JNI_FALSE;
294 /* make sure a subsequent AMOTION_EVENT_ACTION_UP is not treated as a touch event */
295 if (mask == AMOTION_EVENT_ACTION_BUTTON_RELEASE) state |= 0x80000000;
297 prev_state = InterlockedExchange( &button_state, state );
299 data.type = MOTION_EVENT;
300 data.motion.hwnd = LongToHandle( win );
301 data.motion.input.type = INPUT_MOUSE;
302 data.motion.input.mi.dx = x;
303 data.motion.input.mi.dy = y;
304 data.motion.input.mi.mouseData = 0;
305 data.motion.input.mi.time = 0;
306 data.motion.input.mi.dwExtraInfo = 0;
307 data.motion.input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
308 switch (action & AMOTION_EVENT_ACTION_MASK)
310 case AMOTION_EVENT_ACTION_DOWN:
311 case AMOTION_EVENT_ACTION_BUTTON_PRESS:
312 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_PRIMARY)
313 data.motion.input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
314 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_SECONDARY)
315 data.motion.input.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
316 if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_TERTIARY)
317 data.motion.input.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
318 if (!(state & ~prev_state)) /* touch event */
319 data.motion.input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
320 break;
321 case AMOTION_EVENT_ACTION_UP:
322 case AMOTION_EVENT_ACTION_CANCEL:
323 case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
324 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_PRIMARY)
325 data.motion.input.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
326 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_SECONDARY)
327 data.motion.input.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
328 if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_TERTIARY)
329 data.motion.input.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
330 if (!(prev_state & ~state)) /* touch event */
331 data.motion.input.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
332 break;
333 case AMOTION_EVENT_ACTION_SCROLL:
334 data.motion.input.mi.dwFlags |= MOUSEEVENTF_WHEEL;
335 data.motion.input.mi.mouseData = vscroll < 0 ? -WHEEL_DELTA : WHEEL_DELTA;
336 break;
337 case AMOTION_EVENT_ACTION_MOVE:
338 case AMOTION_EVENT_ACTION_HOVER_MOVE:
339 break;
340 default:
341 return JNI_FALSE;
343 send_event( &data );
344 return JNI_TRUE;
348 /***********************************************************************
349 * init_event_queue
351 static void init_event_queue(void)
353 HANDLE handle;
354 int ret;
356 if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
358 ERR( "could not create data\n" );
359 NtTerminateProcess( 0, 1 );
361 if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
363 ERR( "Can't allocate handle for event fd\n" );
364 NtTerminateProcess( 0, 1 );
366 SERVER_START_REQ( set_queue_fd )
368 req->handle = wine_server_obj_handle( handle );
369 ret = wine_server_call( req );
371 SERVER_END_REQ;
372 if (ret)
374 ERR( "Can't store handle for event fd %x\n", ret );
375 NtTerminateProcess( 0, 1 );
377 NtClose( handle );
378 desktop_tid = GetCurrentThreadId();
382 /***********************************************************************
383 * pull_events
385 * Pull events from the event pipe and add them to the queue
387 static void pull_events(void)
389 struct java_event *event;
390 int res;
392 for (;;)
394 if (!(event = malloc( sizeof(*event) ))) break;
396 res = read( event_pipe[0], &event->data, sizeof(event->data) );
397 if (res != sizeof(event->data)) break;
398 list_add_tail( &event_queue, &event->entry );
400 free( event );
404 /***********************************************************************
405 * process_events
407 static int process_events( DWORD mask )
409 struct java_event *event, *next, *previous;
410 unsigned int count = 0;
412 assert( GetCurrentThreadId() == desktop_tid );
414 pull_events();
416 previous = current_event;
418 LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
420 switch (event->data.type)
422 case SURFACE_CHANGED:
423 break; /* always process it to unblock other threads */
424 case MOTION_EVENT:
425 if (event->data.motion.input.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|
426 MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_LEFTUP|
427 MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
429 if (mask & QS_MOUSEBUTTON) break;
431 else if (mask & QS_MOUSEMOVE) break;
432 continue; /* skip it */
433 case KEYBOARD_EVENT:
434 if (mask & QS_KEY) break;
435 continue; /* skip it */
436 default:
437 if (mask & QS_SENDMESSAGE) break;
438 continue; /* skip it */
441 /* remove it first, in case we process events recursively */
442 list_remove( &event->entry );
443 current_event = event;
445 switch (event->data.type)
447 case DESKTOP_CHANGED:
448 TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
449 screen_width = event->data.desktop.width;
450 screen_height = event->data.desktop.height;
451 init_monitors( screen_width, screen_height );
452 break;
454 case CONFIG_CHANGED:
455 TRACE( "CONFIG_CHANGED dpi %u\n", event->data.cfg.dpi );
456 set_screen_dpi( event->data.cfg.dpi );
457 break;
459 case SURFACE_CHANGED:
460 TRACE("SURFACE_CHANGED %p %p %s size %ux%u\n", event->data.surface.hwnd,
461 event->data.surface.window, event->data.surface.client ? "client" : "whole",
462 event->data.surface.width, event->data.surface.height );
464 register_native_window( event->data.surface.hwnd, event->data.surface.window, event->data.surface.client );
465 break;
467 case MOTION_EVENT:
469 HWND capture = get_capture_window();
471 if (event->data.motion.input.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_MIDDLEDOWN))
472 TRACE( "BUTTONDOWN pos %d,%d hwnd %p flags %x\n",
473 (int)event->data.motion.input.mi.dx, (int)event->data.motion.input.mi.dy,
474 event->data.motion.hwnd, (int)event->data.motion.input.mi.dwFlags );
475 else if (event->data.motion.input.mi.dwFlags & (MOUSEEVENTF_LEFTUP|MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
476 TRACE( "BUTTONUP pos %d,%d hwnd %p flags %x\n",
477 (int)event->data.motion.input.mi.dx, (int)event->data.motion.input.mi.dy,
478 event->data.motion.hwnd, (int)event->data.motion.input.mi.dwFlags );
479 else
480 TRACE( "MOUSEMOVE pos %d,%d hwnd %p flags %x\n",
481 (int)event->data.motion.input.mi.dx, (int)event->data.motion.input.mi.dy,
482 event->data.motion.hwnd, (int)event->data.motion.input.mi.dwFlags );
483 if (!capture && (event->data.motion.input.mi.dwFlags & MOUSEEVENTF_ABSOLUTE))
485 RECT rect;
486 SetRect( &rect, event->data.motion.input.mi.dx, event->data.motion.input.mi.dy,
487 event->data.motion.input.mi.dx + 1, event->data.motion.input.mi.dy + 1 );
489 SERVER_START_REQ( update_window_zorder )
491 req->window = wine_server_user_handle( event->data.motion.hwnd );
492 req->rect = wine_server_rectangle( rect );
493 wine_server_call( req );
495 SERVER_END_REQ;
497 NtUserSendHardwareInput( capture ? capture : event->data.motion.hwnd, 0, &event->data.motion.input, 0 );
499 break;
501 case KEYBOARD_EVENT:
502 if (event->data.kbd.input.ki.dwFlags & KEYEVENTF_KEYUP)
503 TRACE("KEYUP hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
504 event->data.kbd.input.ki.wVk, event->data.kbd.input.ki.wVk,
505 event->data.kbd.input.ki.wScan );
506 else
507 TRACE("KEYDOWN hwnd %p vkey %x '%c' scancode %x\n", event->data.kbd.hwnd,
508 event->data.kbd.input.ki.wVk, event->data.kbd.input.ki.wVk,
509 event->data.kbd.input.ki.wScan );
510 update_keyboard_lock_state( event->data.kbd.input.ki.wVk, event->data.kbd.lock_state );
511 NtUserSendHardwareInput( 0, 0, &event->data.kbd.input, 0 );
512 break;
514 default:
515 FIXME( "got event %u\n", event->data.type );
517 free( event );
518 count++;
519 /* next may have been removed by a recursive call, so reset it to the beginning of the list */
520 next = LIST_ENTRY( event_queue.next, struct java_event, entry );
522 current_event = previous;
523 return count;
527 /***********************************************************************
528 * wait_events
530 static int wait_events( int timeout )
532 assert( GetCurrentThreadId() == desktop_tid );
534 for (;;)
536 struct pollfd pollfd;
537 int ret;
539 pollfd.fd = event_pipe[0];
540 pollfd.events = POLLIN | POLLHUP;
541 ret = poll( &pollfd, 1, timeout );
542 if (ret == -1 && errno == EINTR) continue;
543 if (ret && (pollfd.revents & (POLLHUP | POLLERR))) ret = -1;
544 return ret;
549 /* Window surface support */
551 struct android_window_surface
553 struct window_surface header;
554 ANativeWindow *window;
555 UINT clip_count;
556 RECT *clip_rects;
559 static struct android_window_surface *get_android_surface( struct window_surface *surface )
561 return (struct android_window_surface *)surface;
564 /* apply the window region to a single line of the destination image. */
565 static void apply_line_region( DWORD *dst, int width, int x, int y, const RECT *rect, const RECT *end )
567 while (rect < end && rect->top <= y && width > 0)
569 if (rect->left > x)
571 memset( dst, 0, min( rect->left - x, width ) * sizeof(*dst) );
572 dst += rect->left - x;
573 width -= rect->left - x;
574 x = rect->left;
576 if (rect->right > x)
578 dst += rect->right - x;
579 width -= rect->right - x;
580 x = rect->right;
582 rect++;
584 if (width > 0) memset( dst, 0, width * sizeof(*dst) );
587 /***********************************************************************
588 * android_surface_set_clip
590 static void android_surface_set_clip( struct window_surface *window_surface, const RECT *rects, UINT count )
592 struct android_window_surface *surface = get_android_surface( window_surface );
594 free( surface->clip_rects );
595 surface->clip_rects = NULL;
597 if (!count || !(surface->clip_rects = malloc( count * sizeof(*rects) ))) return;
598 memcpy( surface->clip_rects, rects, count * sizeof(*rects) );
599 surface->clip_count = count;
602 /***********************************************************************
603 * android_surface_flush
605 static BOOL android_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty,
606 const BITMAPINFO *color_info, const void *color_bits, BOOL shape_changed,
607 const BITMAPINFO *shape_info, const void *shape_bits )
609 struct android_window_surface *surface = get_android_surface( window_surface );
610 ANativeWindow_Buffer buffer;
611 ARect rc;
613 rc.left = dirty->left;
614 rc.top = dirty->top;
615 rc.right = dirty->right;
616 rc.bottom = dirty->bottom;
618 if (!surface->window->perform( surface->window, NATIVE_WINDOW_LOCK, &buffer, &rc ))
620 const RECT *rgn_rect = surface->clip_rects, *end = surface->clip_rects + surface->clip_count;
621 UINT alpha_mask = window_surface->alpha_mask, alpha_bits = window_surface->alpha_bits;
622 COLORREF color_key = window_surface->color_key;
623 BYTE alpha = alpha_bits >> 24;
624 DWORD *src, *dst;
625 int x, y, width;
626 RECT locked;
628 locked.left = rc.left;
629 locked.top = rc.top;
630 locked.right = rc.right;
631 locked.bottom = rc.bottom;
632 intersect_rect( &locked, &locked, rect );
634 src = (DWORD *)color_bits + (locked.top - rect->top) * color_info->bmiHeader.biWidth +
635 (locked.left - rect->left);
636 dst = (DWORD *)buffer.bits + locked.top * buffer.stride + locked.left;
637 width = min( locked.right - locked.left, buffer.stride );
639 for (y = locked.top; y < min( buffer.height, locked.bottom ); y++)
641 if (alpha_mask)
642 memcpy( dst, src, width * sizeof(*dst) );
643 else if (alpha == 255)
644 for (x = 0; x < width; x++) dst[x] = src[x] | 0xff000000;
645 else
646 for (x = 0; x < width; x++)
647 dst[x] = ((alpha << 24) |
648 (((BYTE)(src[x] >> 16) * alpha / 255) << 16) |
649 (((BYTE)(src[x] >> 8) * alpha / 255) << 8) |
650 (((BYTE)src[x] * alpha / 255)));
652 if (color_key != CLR_INVALID)
653 for (x = 0; x < width; x++) if ((src[x] & 0xffffff) == color_key) dst[x] = 0;
655 if (rgn_rect)
657 while (rgn_rect < end && rgn_rect->bottom <= y) rgn_rect++;
658 apply_line_region( dst, width, locked.left, y, rgn_rect, end );
661 src += color_info->bmiHeader.biWidth;
662 dst += buffer.stride;
664 surface->window->perform( surface->window, NATIVE_WINDOW_UNLOCK_AND_POST );
666 else TRACE( "Unable to lock surface %p window %p buffer %p\n",
667 surface, window_surface->hwnd, surface->window );
669 return TRUE;
672 /***********************************************************************
673 * android_surface_destroy
675 static void android_surface_destroy( struct window_surface *window_surface )
677 struct android_window_surface *surface = get_android_surface( window_surface );
679 TRACE( "freeing %p\n", surface );
681 free( surface->clip_rects );
682 release_ioctl_window( surface->window );
683 free( surface );
686 static const struct window_surface_funcs android_surface_funcs =
688 android_surface_set_clip,
689 android_surface_flush,
690 android_surface_destroy
693 static BOOL is_argb_surface( struct window_surface *surface )
695 return surface && surface->funcs == &android_surface_funcs && !!surface->alpha_mask;
698 /***********************************************************************
699 * create_surface
701 static struct window_surface *create_surface( HWND hwnd, const RECT *rect )
703 struct android_window_surface *surface;
704 int width = rect->right - rect->left, height = rect->bottom - rect->top;
705 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
706 BITMAPINFO *info = (BITMAPINFO *)buffer;
708 memset( info, 0, sizeof(*info) );
709 info->bmiHeader.biSize = sizeof(info->bmiHeader);
710 info->bmiHeader.biWidth = width;
711 info->bmiHeader.biHeight = -height; /* top-down */
712 info->bmiHeader.biPlanes = 1;
713 info->bmiHeader.biBitCount = 32;
714 info->bmiHeader.biSizeImage = get_dib_image_size(info);
715 info->bmiHeader.biCompression = BI_RGB;
717 if (!(surface = calloc( 1, sizeof(*surface) ))) return NULL;
718 if (!window_surface_init( &surface->header, &android_surface_funcs, hwnd, rect, info, 0 )) goto failed;
720 surface->window = get_ioctl_window( hwnd );
722 TRACE( "created %p hwnd %p %s\n", surface, hwnd, wine_dbgstr_rect(rect) );
724 return &surface->header;
726 failed:
727 window_surface_release( &surface->header );
728 return NULL;
731 /***********************************************************************
732 * get_mono_icon_argb
734 * Return a monochrome icon/cursor bitmap bits in ARGB format.
736 static unsigned int *get_mono_icon_argb( HDC hdc, HBITMAP bmp, unsigned int *width, unsigned int *height )
738 BITMAP bm;
739 char *mask;
740 unsigned int i, j, stride, mask_size, bits_size, *bits = NULL, *ptr;
742 if (!NtGdiExtGetObjectW( bmp, sizeof(bm), &bm )) return NULL;
743 stride = ((bm.bmWidth + 15) >> 3) & ~1;
744 mask_size = stride * bm.bmHeight;
745 if (!(mask = malloc( mask_size ))) return NULL;
746 if (!NtGdiGetBitmapBits( bmp, mask_size, mask )) goto done;
748 bm.bmHeight /= 2;
749 bits_size = bm.bmWidth * bm.bmHeight * sizeof(*bits);
750 if (!(bits = malloc( bits_size ))) goto done;
752 ptr = bits;
753 for (i = 0; i < bm.bmHeight; i++)
754 for (j = 0; j < bm.bmWidth; j++, ptr++)
756 int and = ((mask[i * stride + j / 8] << (j % 8)) & 0x80);
757 int xor = ((mask[(i + bm.bmHeight) * stride + j / 8] << (j % 8)) & 0x80);
758 if (!xor && and)
759 *ptr = 0;
760 else if (xor && !and)
761 *ptr = 0xffffffff;
762 else
763 /* we can't draw "invert" pixels, so render them as black instead */
764 *ptr = 0xff000000;
767 *width = bm.bmWidth;
768 *height = bm.bmHeight;
770 done:
771 free( mask );
772 return bits;
775 /***********************************************************************
776 * get_bitmap_argb
778 * Return the bitmap bits in ARGB format. Helper for setting icons and cursors.
780 static unsigned int *get_bitmap_argb( HDC hdc, HBITMAP color, HBITMAP mask, unsigned int *width,
781 unsigned int *height )
783 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
784 BITMAPINFO *info = (BITMAPINFO *)buffer;
785 BITMAP bm;
786 unsigned int *ptr, *bits = NULL;
787 unsigned char *mask_bits = NULL;
788 int i, j;
789 BOOL has_alpha = FALSE;
791 if (!color) return get_mono_icon_argb( hdc, mask, width, height );
793 if (!NtGdiExtGetObjectW( color, sizeof(bm), &bm )) return NULL;
794 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
795 info->bmiHeader.biWidth = bm.bmWidth;
796 info->bmiHeader.biHeight = -bm.bmHeight;
797 info->bmiHeader.biPlanes = 1;
798 info->bmiHeader.biBitCount = 32;
799 info->bmiHeader.biCompression = BI_RGB;
800 info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
801 info->bmiHeader.biXPelsPerMeter = 0;
802 info->bmiHeader.biYPelsPerMeter = 0;
803 info->bmiHeader.biClrUsed = 0;
804 info->bmiHeader.biClrImportant = 0;
805 if (!(bits = malloc( bm.bmWidth * bm.bmHeight * sizeof(unsigned int) )))
806 goto failed;
807 if (!NtGdiGetDIBitsInternal( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS, 0, 0 ))
808 goto failed;
810 *width = bm.bmWidth;
811 *height = bm.bmHeight;
813 for (i = 0; i < bm.bmWidth * bm.bmHeight; i++)
814 if ((has_alpha = (bits[i] & 0xff000000) != 0)) break;
816 if (!has_alpha)
818 unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4;
819 /* generate alpha channel from the mask */
820 info->bmiHeader.biBitCount = 1;
821 info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight;
822 if (!(mask_bits = malloc( info->bmiHeader.biSizeImage ))) goto failed;
823 if (!NtGdiGetDIBitsInternal( hdc, mask, 0, bm.bmHeight, mask_bits, info, DIB_RGB_COLORS, 0, 0 ))
824 goto failed;
825 ptr = bits;
826 for (i = 0; i < bm.bmHeight; i++)
827 for (j = 0; j < bm.bmWidth; j++, ptr++)
828 if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000;
829 free( mask_bits );
832 return bits;
834 failed:
835 free( bits );
836 free( mask_bits );
837 *width = *height = 0;
838 return NULL;
842 enum android_system_cursors
844 TYPE_ARROW = 1000,
845 TYPE_CONTEXT_MENU = 1001,
846 TYPE_HAND = 1002,
847 TYPE_HELP = 1003,
848 TYPE_WAIT = 1004,
849 TYPE_CELL = 1006,
850 TYPE_CROSSHAIR = 1007,
851 TYPE_TEXT = 1008,
852 TYPE_VERTICAL_TEXT = 1009,
853 TYPE_ALIAS = 1010,
854 TYPE_COPY = 1011,
855 TYPE_NO_DROP = 1012,
856 TYPE_ALL_SCROLL = 1013,
857 TYPE_HORIZONTAL_DOUBLE_ARROW = 1014,
858 TYPE_VERTICAL_DOUBLE_ARROW = 1015,
859 TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016,
860 TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017,
861 TYPE_ZOOM_IN = 1018,
862 TYPE_ZOOM_OUT = 1019,
863 TYPE_GRAB = 1020,
864 TYPE_GRABBING = 1021,
867 struct system_cursors
869 WORD id;
870 enum android_system_cursors android_id;
873 static const struct system_cursors user32_cursors[] =
875 { OCR_NORMAL, TYPE_ARROW },
876 { OCR_IBEAM, TYPE_TEXT },
877 { OCR_WAIT, TYPE_WAIT },
878 { OCR_CROSS, TYPE_CROSSHAIR },
879 { OCR_SIZE, TYPE_ALL_SCROLL },
880 { OCR_SIZEALL, TYPE_ALL_SCROLL },
881 { OCR_SIZENWSE, TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW },
882 { OCR_SIZENESW, TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW },
883 { OCR_SIZEWE, TYPE_HORIZONTAL_DOUBLE_ARROW },
884 { OCR_SIZENS, TYPE_VERTICAL_DOUBLE_ARROW },
885 { OCR_NO, TYPE_NO_DROP },
886 { OCR_HAND, TYPE_HAND },
887 { OCR_HELP, TYPE_HELP },
888 { 0 }
891 static const struct system_cursors comctl32_cursors[] =
893 /* 102 TYPE_MOVE doesn't exist */
894 { 104, TYPE_COPY },
895 { 105, TYPE_ARROW },
896 { 106, TYPE_HORIZONTAL_DOUBLE_ARROW },
897 { 107, TYPE_HORIZONTAL_DOUBLE_ARROW },
898 { 108, TYPE_GRABBING },
899 { 135, TYPE_VERTICAL_DOUBLE_ARROW },
900 { 0 }
903 static const struct system_cursors ole32_cursors[] =
905 { 1, TYPE_NO_DROP },
906 /* 2 TYPE_MOVE doesn't exist */
907 { 3, TYPE_COPY },
908 { 4, TYPE_ALIAS },
909 { 0 }
912 static const struct system_cursors riched20_cursors[] =
914 { 105, TYPE_GRABBING },
915 { 109, TYPE_COPY },
916 /* 110 TYPE_MOVE doesn't exist */
917 { 111, TYPE_NO_DROP },
918 { 0 }
921 static const struct
923 const struct system_cursors *cursors;
924 WCHAR name[16];
925 } module_cursors[] =
927 { user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
928 { comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
929 { ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
930 { riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
933 static int get_cursor_system_id( const ICONINFOEXW *info )
935 const struct system_cursors *cursors;
936 const WCHAR *module;
937 unsigned int i;
939 if (info->szResName[0]) return 0; /* only integer resources are supported here */
941 if ((module = wcsrchr( info->szModName, '\\' ))) module++;
942 else module = info->szModName;
943 for (i = 0; i < ARRAY_SIZE( module_cursors ); i++)
944 if (!wcsicmp( module, module_cursors[i].name )) break;
945 if (i == ARRAY_SIZE( module_cursors )) return 0;
947 cursors = module_cursors[i].cursors;
948 for (i = 0; cursors[i].id; i++)
949 if (cursors[i].id == info->wResID) return cursors[i].android_id;
951 return 0;
955 LRESULT ANDROID_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
957 switch (msg)
959 case WM_PARENTNOTIFY:
960 if (LOWORD(wp) == WM_DESTROY) destroy_ioctl_window( (HWND)lp, FALSE );
961 break;
963 return NtUserMessageCall( hwnd, msg, wp, lp, 0, NtUserDefWindowProc, FALSE );
967 /***********************************************************************
968 * ANDROID_ProcessEvents
970 BOOL ANDROID_ProcessEvents( DWORD mask )
972 if (GetCurrentThreadId() == desktop_tid)
974 /* don't process nested events */
975 if (current_event) mask = 0;
976 return process_events( mask );
978 return FALSE;
981 /**********************************************************************
982 * ANDROID_CreateWindow
984 BOOL ANDROID_CreateWindow( HWND hwnd )
986 TRACE( "%p\n", hwnd );
988 if (hwnd == NtUserGetDesktopWindow())
990 struct android_win_data *data;
992 init_event_queue();
993 start_android_device();
994 if (!(data = alloc_win_data( hwnd ))) return FALSE;
995 release_win_data( data );
997 return TRUE;
1001 /***********************************************************************
1002 * ANDROID_DestroyWindow
1004 void ANDROID_DestroyWindow( HWND hwnd )
1006 struct android_win_data *data;
1008 if (!(data = get_win_data( hwnd ))) return;
1010 if (data->surface) window_surface_release( data->surface );
1011 data->surface = NULL;
1012 destroy_gl_drawable( hwnd );
1013 free_win_data( data );
1017 /***********************************************************************
1018 * create_win_data
1020 * Create a data window structure for an existing window.
1022 static struct android_win_data *create_win_data( HWND hwnd, const RECT *window_rect,
1023 const RECT *client_rect )
1025 struct android_win_data *data;
1026 HWND parent;
1028 if (!(parent = NtUserGetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop or HWND_MESSAGE */
1030 if (!(data = alloc_win_data( hwnd ))) return NULL;
1032 data->parent = (parent == NtUserGetDesktopWindow()) ? 0 : parent;
1033 data->whole_rect = data->window_rect = *window_rect;
1034 data->client_rect = *client_rect;
1035 return data;
1039 /***********************************************************************
1040 * ANDROID_WindowPosChanging
1042 BOOL ANDROID_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const RECT *window_rect,
1043 const RECT *client_rect, RECT *visible_rect )
1045 struct android_win_data *data = get_win_data( hwnd );
1046 BOOL ret = FALSE;
1048 TRACE( "hwnd %p, swp_flags %04x, shaped %u, window_rect %s, client_rect %s, visible_rect %s\n",
1049 hwnd, swp_flags, shaped, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1050 wine_dbgstr_rect(visible_rect) );
1052 if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return FALSE; /* use default surface */
1054 if (data->parent) goto done; /* use default surface */
1055 if (is_argb_surface( data->surface )) goto done; /* use default surface */
1057 ret = TRUE;
1059 done:
1060 release_win_data(data);
1061 return ret;
1065 /***********************************************************************
1066 * ANDROID_CreateWindowSurface
1068 BOOL ANDROID_CreateWindowSurface( HWND hwnd, const RECT *surface_rect, struct window_surface **surface )
1070 struct android_win_data *data;
1072 TRACE( "hwnd %p, surface_rect %s, surface %p\n", hwnd, wine_dbgstr_rect( surface_rect ), surface );
1074 if (!(data = get_win_data( hwnd ))) return TRUE; /* use default surface */
1076 if (data->surface)
1078 if (EqualRect( &data->surface->rect, surface_rect ))
1080 /* existing surface is good enough */
1081 window_surface_add_ref( data->surface );
1082 if (*surface) window_surface_release( *surface );
1083 *surface = data->surface;
1084 goto done;
1088 if (*surface) window_surface_release( *surface );
1089 *surface = create_surface( data->hwnd, surface_rect );
1091 done:
1092 release_win_data( data );
1093 return TRUE;
1097 /***********************************************************************
1098 * ANDROID_WindowPosChanged
1100 void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
1101 const RECT *window_rect, const RECT *client_rect,
1102 const RECT *visible_rect, const RECT *valid_rects,
1103 struct window_surface *surface )
1105 struct android_win_data *data;
1106 UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
1107 HWND owner = 0;
1109 if (!(data = get_win_data( hwnd ))) return;
1111 data->window_rect = *window_rect;
1112 data->whole_rect = *visible_rect;
1113 data->client_rect = *client_rect;
1115 if (!is_argb_surface( data->surface ))
1117 if (surface) window_surface_add_ref( surface );
1118 if (data->surface) window_surface_release( data->surface );
1119 data->surface = surface;
1121 if (!data->parent) owner = NtUserGetWindowRelative( hwnd, GW_OWNER );
1122 release_win_data( data );
1124 if (!(swp_flags & SWP_NOZORDER)) insert_after = NtUserGetWindowRelative( hwnd, GW_HWNDPREV );
1126 TRACE( "win %p window %s client %s style %08x owner %p after %p flags %08x\n", hwnd,
1127 wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1128 new_style, owner, insert_after, swp_flags );
1130 ioctl_window_pos_changed( hwnd, window_rect, client_rect, visible_rect,
1131 new_style, swp_flags, insert_after, owner );
1135 /***********************************************************************
1136 * ANDROID_ShowWindow
1138 UINT ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
1140 if (!(NtUserGetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)) return swp;
1141 /* always hide icons off-screen */
1142 if (rect->left != -32000 || rect->top != -32000)
1144 OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
1145 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1147 return swp;
1151 /*****************************************************************
1152 * ANDROID_SetParent
1154 void ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent )
1156 struct android_win_data *data;
1158 if (parent == old_parent) return;
1159 if (!(data = get_win_data( hwnd ))) return;
1161 TRACE( "win %p parent %p -> %p\n", hwnd, old_parent, parent );
1163 data->parent = (parent == NtUserGetDesktopWindow()) ? 0 : parent;
1164 ioctl_set_window_parent( hwnd, parent, (float)get_win_monitor_dpi( hwnd ) / NtUserGetDpiForWindow( hwnd ));
1165 release_win_data( data );
1169 /***********************************************************************
1170 * ANDROID_SetCapture
1172 void ANDROID_SetCapture( HWND hwnd, UINT flags )
1174 if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
1175 ioctl_set_capture( hwnd );
1179 static BOOL get_icon_info( HICON handle, ICONINFOEXW *ret )
1181 UNICODE_STRING module, res_name;
1182 ICONINFO info;
1184 module.Buffer = ret->szModName;
1185 module.MaximumLength = sizeof(ret->szModName) - sizeof(WCHAR);
1186 res_name.Buffer = ret->szResName;
1187 res_name.MaximumLength = sizeof(ret->szResName) - sizeof(WCHAR);
1188 if (!NtUserGetIconInfo( handle, &info, &module, &res_name, NULL, 0 )) return FALSE;
1189 ret->fIcon = info.fIcon;
1190 ret->xHotspot = info.xHotspot;
1191 ret->yHotspot = info.yHotspot;
1192 ret->hbmColor = info.hbmColor;
1193 ret->hbmMask = info.hbmMask;
1194 ret->wResID = res_name.Length ? 0 : LOWORD(res_name.Buffer);
1195 ret->szModName[module.Length] = 0;
1196 ret->szResName[res_name.Length] = 0;
1197 return TRUE;
1201 /***********************************************************************
1202 * ANDROID_SetCursor
1204 void ANDROID_SetCursor( HWND hwnd, HCURSOR handle )
1206 if (handle)
1208 unsigned int width = 0, height = 0, *bits = NULL;
1209 ICONINFOEXW info;
1210 int id;
1212 if (!get_icon_info( handle, &info )) return;
1214 if (!(id = get_cursor_system_id( &info )))
1216 HDC hdc = NtGdiCreateCompatibleDC( 0 );
1217 bits = get_bitmap_argb( hdc, info.hbmColor, info.hbmMask, &width, &height );
1218 NtGdiDeleteObjectApp( hdc );
1220 /* make sure hotspot is valid */
1221 if (info.xHotspot >= width || info.yHotspot >= height)
1223 info.xHotspot = width / 2;
1224 info.yHotspot = height / 2;
1227 ioctl_set_cursor( id, width, height, info.xHotspot, info.yHotspot, bits );
1228 free( bits );
1229 NtGdiDeleteObjectApp( info.hbmColor );
1230 NtGdiDeleteObjectApp( info.hbmMask );
1232 else ioctl_set_cursor( 0, 0, 0, 0, 0, NULL );
1236 /***********************************************************************
1237 * ANDROID_SetWindowStyle
1239 void ANDROID_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
1241 struct android_win_data *data;
1242 DWORD changed = style->styleNew ^ style->styleOld;
1244 if (hwnd == NtUserGetDesktopWindow()) return;
1245 if (!(data = get_win_data( hwnd ))) return;
1247 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1249 if (is_argb_surface( data->surface ))
1251 if (data->surface) window_surface_release( data->surface );
1252 data->surface = NULL;
1255 release_win_data( data );
1259 /*****************************************************************************
1260 * ANDROID_CreateLayeredWindow
1262 BOOL ANDROID_CreateLayeredWindow( HWND hwnd, const RECT *surface_rect, COLORREF color_key,
1263 struct window_surface **window_surface )
1265 struct window_surface *surface;
1266 struct android_win_data *data;
1268 if (!(data = get_win_data( hwnd ))) return FALSE;
1270 surface = data->surface;
1271 if (!is_argb_surface( surface ))
1273 if (surface) window_surface_release( surface );
1274 surface = NULL;
1277 if (!surface || !EqualRect( &surface->rect, surface_rect ))
1279 data->surface = create_surface( data->hwnd, surface_rect );
1280 if (surface) window_surface_release( surface );
1281 surface = data->surface;
1284 if ((*window_surface = surface)) window_surface_add_ref( surface );
1285 release_win_data( data );
1287 return TRUE;
1291 /**********************************************************************
1292 * ANDROID_WindowMessage
1294 LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1296 struct android_win_data *data;
1298 switch (msg)
1300 case WM_ANDROID_REFRESH:
1301 if (wp) /* opengl client window */
1303 update_gl_drawable( hwnd );
1305 else if ((data = get_win_data( hwnd )))
1307 struct window_surface *surface = data->surface;
1308 if (surface)
1310 window_surface_lock( surface );
1311 surface->bounds = surface->rect;
1312 window_surface_unlock( surface );
1313 if (is_argb_surface( surface )) window_surface_flush( surface );
1315 release_win_data( data );
1317 return 0;
1318 default:
1319 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (long)wp, lp );
1320 return 0;
1325 /***********************************************************************
1326 * ANDROID_CreateDesktop
1328 BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height )
1330 /* wait until we receive the surface changed event */
1331 while (!screen_width)
1333 if (wait_events( 2000 ) != 1)
1335 ERR( "wait timed out\n" );
1336 break;
1338 process_events( QS_ALLINPUT );
1340 return 0;