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
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
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 /***********************************************************************
121 static struct android_win_data
*alloc_win_data( HWND hwnd
)
123 struct android_win_data
*data
;
125 if ((data
= calloc( 1, sizeof(*data
) )))
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
;
137 /***********************************************************************
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
);
149 /***********************************************************************
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
);
166 /***********************************************************************
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 /***********************************************************************
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
);
192 /* Handling of events coming from the Java side */
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 /***********************************************************************
208 int send_event( const union event_data
*data
)
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" );
221 /***********************************************************************
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
);
239 /***********************************************************************
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
;
251 p__android_log_print( ANDROID_LOG_INFO
, "wine", "config_changed: %u dpi", dpi
);
256 /***********************************************************************
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
;
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
;
286 /***********************************************************************
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
;
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
))
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
;
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
;
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
;
352 case AMOTION_EVENT_ACTION_MOVE
:
353 case AMOTION_EVENT_ACTION_HOVER_MOVE
:
363 /***********************************************************************
366 static void init_event_queue(void)
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
);
389 ERR( "Can't store handle for event fd %x\n", ret
);
390 NtTerminateProcess( 0, 1 );
393 desktop_tid
= GetCurrentThreadId();
397 /***********************************************************************
400 * Pull events from the event pipe and add them to the queue
402 static void pull_events(void)
404 struct java_event
*event
;
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
);
419 /***********************************************************************
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
);
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 */
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 */
450 if (mask
& QS_KEY
) break;
451 continue; /* skip it */
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
);
475 TRACE( "CONFIG_CHANGED dpi %u\n", event
->data
.cfg
.dpi
);
476 set_screen_dpi( event
->data
.cfg
.dpi
);
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
);
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
);
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
))
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
);
520 __wine_send_input( capture
? capture
: event
->data
.motion
.hwnd
, &event
->data
.motion
.input
, NULL
);
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
);
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
);
538 FIXME( "got event %u\n", event
->data
.type
);
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
;
550 /***********************************************************************
553 static int wait_events( int timeout
)
555 assert( GetCurrentThreadId() == desktop_tid
);
559 struct pollfd pollfd
;
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;
572 /* Window surface support */
574 struct android_window_surface
576 struct window_surface header
;
578 ANativeWindow
*window
;
581 RGNDATA
*region_data
;
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;
620 info
->bmiHeader
.biCompression
= BI_RGB
;
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)
636 memset( dst
, 0, min( rect
->left
- x
, width
) * sizeof(*dst
) );
637 dst
+= rect
->left
- x
;
638 width
-= rect
->left
- x
;
643 dst
+= rect
->right
- x
;
644 width
-= rect
->right
- x
;
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
);
705 if (surface
->region
) NtGdiDeleteObjectApp( surface
->region
);
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
;
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 );
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
;
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;
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;
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
);
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 /***********************************************************************
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
;
849 surface
->color_key
= (GetRValue(key
) << 16) | (GetGValue(key
) << 8) | GetBValue(key
);
852 /***********************************************************************
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
;
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
))
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 /***********************************************************************
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
)))
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
;
941 android_surface_destroy( &surface
->header
);
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
);
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 /***********************************************************************
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
)
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
;
984 bits_size
= bm
.bmWidth
* bm
.bmHeight
* sizeof(*bits
);
985 if (!(bits
= malloc( bits_size
))) goto done
;
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);
995 else if (xor && !and)
998 /* we can't draw "invert" pixels, so render them as black instead */
1002 *width
= bm
.bmWidth
;
1003 *height
= bm
.bmHeight
;
1010 /***********************************************************************
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
;
1021 unsigned int *ptr
, *bits
= NULL
;
1022 unsigned char *mask_bits
= NULL
;
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) )))
1042 if (!NtGdiGetDIBitsInternal( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
, 0, 0 ))
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;
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 ))
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;
1072 *width
= *height
= 0;
1077 enum android_system_cursors
1080 TYPE_CONTEXT_MENU
= 1001,
1085 TYPE_CROSSHAIR
= 1007,
1087 TYPE_VERTICAL_TEXT
= 1009,
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,
1099 TYPE_GRABBING
= 1021,
1102 struct system_cursors
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
},
1126 static const struct system_cursors comctl32_cursors
[] =
1128 /* 102 TYPE_MOVE doesn't exist */
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
},
1138 static const struct system_cursors ole32_cursors
[] =
1140 { 1, TYPE_NO_DROP
},
1141 /* 2 TYPE_MOVE doesn't exist */
1147 static const struct system_cursors riched20_cursors
[] =
1149 { 105, TYPE_GRABBING
},
1151 /* 110 TYPE_MOVE doesn't exist */
1152 { 111, TYPE_NO_DROP
},
1158 const struct system_cursors
*cursors
;
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
;
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
;
1190 LRESULT
ANDROID_DesktopWindowProc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1194 case WM_PARENTNOTIFY
:
1195 if (LOWORD(wp
) == WM_DESTROY
) destroy_ioctl_window( (HWND
)lp
, FALSE
);
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
);
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
;
1228 start_android_device();
1229 if (!(data
= alloc_win_data( hwnd
))) return FALSE
;
1230 release_win_data( data
);
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 /***********************************************************************
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
;
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
;
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 );
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
);
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
;
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
;
1326 if (!(swp_flags
& SWP_SHOWWINDOW
) && !(NtUserGetWindowLongW( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
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
);
1337 release_win_data( data
);
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
);
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
);
1396 /*****************************************************************
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
;
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;
1446 /***********************************************************************
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();
1461 unsigned int width
= 0, height
= 0, *bits
= NULL
;
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
);
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
;
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
);
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
;
1592 window_surface_release( surface
);
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
)))
1600 if (!(hdc
= NtGdiCreateCompatibleDC( 0 ))) goto done
;
1602 NtGdiSelectBitmap( hdc
, dib
);
1604 surface
->funcs
->lock( surface
);
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
);
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 );
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
);
1631 window_surface_release( surface
);
1632 if (hdc
) NtGdiDeleteObjectApp( hdc
);
1633 if (dib
) NtGdiDeleteObjectApp( dib
);
1638 /**********************************************************************
1639 * ANDROID_WindowMessage
1641 LRESULT
ANDROID_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1643 struct android_win_data
*data
;
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
;
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
);
1666 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, (long)wp
, lp
);
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" );
1685 process_events( QS_ALLINPUT
);