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
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 /**********************************************************************
97 UINT
get_win_monitor_dpi( HWND hwnd
)
99 return NtUserGetSystemDpiForProcess( NULL
); /* FIXME: get monitor dpi */
103 /***********************************************************************
106 static struct android_win_data
*alloc_win_data( HWND hwnd
)
108 struct android_win_data
*data
;
110 if ((data
= calloc( 1, sizeof(*data
) )))
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
;
122 /***********************************************************************
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
);
134 /***********************************************************************
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
);
151 /***********************************************************************
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 /***********************************************************************
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
);
177 /* Handling of events coming from the Java side */
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 /***********************************************************************
193 int send_event( const union event_data
*data
)
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" );
206 /***********************************************************************
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
);
224 /***********************************************************************
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
;
236 p__android_log_print( ANDROID_LOG_INFO
, "wine", "config_changed: %u dpi", dpi
);
241 /***********************************************************************
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
;
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
;
271 /***********************************************************************
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
;
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
))
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
;
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
;
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
;
337 case AMOTION_EVENT_ACTION_MOVE
:
338 case AMOTION_EVENT_ACTION_HOVER_MOVE
:
348 /***********************************************************************
351 static void init_event_queue(void)
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
);
374 ERR( "Can't store handle for event fd %x\n", ret
);
375 NtTerminateProcess( 0, 1 );
378 desktop_tid
= GetCurrentThreadId();
382 /***********************************************************************
385 * Pull events from the event pipe and add them to the queue
387 static void pull_events(void)
389 struct java_event
*event
;
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
);
404 /***********************************************************************
407 static int process_events( DWORD mask
)
409 struct java_event
*event
, *next
, *previous
;
410 unsigned int count
= 0;
412 assert( GetCurrentThreadId() == desktop_tid
);
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 */
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 */
434 if (mask
& QS_KEY
) break;
435 continue; /* skip it */
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
);
455 TRACE( "CONFIG_CHANGED dpi %u\n", event
->data
.cfg
.dpi
);
456 set_screen_dpi( event
->data
.cfg
.dpi
);
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
);
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
);
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
))
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
);
497 NtUserSendHardwareInput( capture
? capture
: event
->data
.motion
.hwnd
, 0, &event
->data
.motion
.input
, 0 );
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
);
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 );
515 FIXME( "got event %u\n", event
->data
.type
);
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
;
527 /***********************************************************************
530 static int wait_events( int timeout
)
532 assert( GetCurrentThreadId() == desktop_tid
);
536 struct pollfd pollfd
;
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;
549 /* Window surface support */
551 struct android_window_surface
553 struct window_surface header
;
554 ANativeWindow
*window
;
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)
571 memset( dst
, 0, min( rect
->left
- x
, width
) * sizeof(*dst
) );
572 dst
+= rect
->left
- x
;
573 width
-= rect
->left
- x
;
578 dst
+= rect
->right
- x
;
579 width
-= rect
->right
- x
;
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
;
613 rc
.left
= dirty
->left
;
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;
628 locked
.left
= rc
.left
;
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
++)
642 memcpy( dst
, src
, width
* sizeof(*dst
) );
643 else if (alpha
== 255)
644 for (x
= 0; x
< width
; x
++) dst
[x
] = src
[x
] | 0xff000000;
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;
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
);
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
);
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 /***********************************************************************
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
;
727 window_surface_release( &surface
->header
);
731 /***********************************************************************
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
)
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
;
749 bits_size
= bm
.bmWidth
* bm
.bmHeight
* sizeof(*bits
);
750 if (!(bits
= malloc( bits_size
))) goto done
;
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);
760 else if (xor && !and)
763 /* we can't draw "invert" pixels, so render them as black instead */
768 *height
= bm
.bmHeight
;
775 /***********************************************************************
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
;
786 unsigned int *ptr
, *bits
= NULL
;
787 unsigned char *mask_bits
= NULL
;
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) )))
807 if (!NtGdiGetDIBitsInternal( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
, 0, 0 ))
811 *height
= bm
.bmHeight
;
813 for (i
= 0; i
< bm
.bmWidth
* bm
.bmHeight
; i
++)
814 if ((has_alpha
= (bits
[i
] & 0xff000000) != 0)) break;
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 ))
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;
837 *width
= *height
= 0;
842 enum android_system_cursors
845 TYPE_CONTEXT_MENU
= 1001,
850 TYPE_CROSSHAIR
= 1007,
852 TYPE_VERTICAL_TEXT
= 1009,
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,
862 TYPE_ZOOM_OUT
= 1019,
864 TYPE_GRABBING
= 1021,
867 struct system_cursors
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
},
891 static const struct system_cursors comctl32_cursors
[] =
893 /* 102 TYPE_MOVE doesn't exist */
896 { 106, TYPE_HORIZONTAL_DOUBLE_ARROW
},
897 { 107, TYPE_HORIZONTAL_DOUBLE_ARROW
},
898 { 108, TYPE_GRABBING
},
899 { 135, TYPE_VERTICAL_DOUBLE_ARROW
},
903 static const struct system_cursors ole32_cursors
[] =
906 /* 2 TYPE_MOVE doesn't exist */
912 static const struct system_cursors riched20_cursors
[] =
914 { 105, TYPE_GRABBING
},
916 /* 110 TYPE_MOVE doesn't exist */
917 { 111, TYPE_NO_DROP
},
923 const struct system_cursors
*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
;
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
;
955 LRESULT
ANDROID_DesktopWindowProc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
959 case WM_PARENTNOTIFY
:
960 if (LOWORD(wp
) == WM_DESTROY
) destroy_ioctl_window( (HWND
)lp
, FALSE
);
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
);
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
;
993 start_android_device();
994 if (!(data
= alloc_win_data( hwnd
))) return FALSE
;
995 release_win_data( data
);
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 /***********************************************************************
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
;
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
;
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
);
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 */
1060 release_win_data(data
);
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 */
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
;
1088 if (*surface
) window_surface_release( *surface
);
1089 *surface
= create_surface( data
->hwnd
, surface_rect
);
1092 release_win_data( data
);
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
);
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
);
1151 /*****************************************************************
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
;
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;
1201 /***********************************************************************
1204 void ANDROID_SetCursor( HWND hwnd
, HCURSOR handle
)
1208 unsigned int width
= 0, height
= 0, *bits
= NULL
;
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
);
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
);
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
);
1291 /**********************************************************************
1292 * ANDROID_WindowMessage
1294 LRESULT
ANDROID_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1296 struct android_win_data
*data
;
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
;
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
);
1319 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, (long)wp
, lp
);
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" );
1338 process_events( QS_ALLINPUT
);