wineandroid: Support for setting the cursor on Android >= N.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2b8d787b17
commit
61888e0012
@ -25,6 +25,7 @@ import android.app.Activity;
|
|||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -34,6 +35,7 @@ import android.util.Log;
|
|||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
import android.view.PointerIcon;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.TextureView;
|
import android.view.TextureView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -64,6 +66,7 @@ public class WineActivity extends Activity
|
|||||||
|
|
||||||
protected WineWindow desktop_window;
|
protected WineWindow desktop_window;
|
||||||
protected WineWindow message_window;
|
protected WineWindow message_window;
|
||||||
|
private PointerIcon current_cursor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
@ -684,6 +687,12 @@ public class WineActivity extends Activity
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TargetApi(24)
|
||||||
|
public PointerIcon onResolvePointerIcon( MotionEvent event, int index )
|
||||||
|
{
|
||||||
|
return current_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean onGenericMotionEvent( MotionEvent event )
|
public boolean onGenericMotionEvent( MotionEvent event )
|
||||||
{
|
{
|
||||||
if (is_client) return false; // let the whole window handle it
|
if (is_client) return false; // let the whole window handle it
|
||||||
@ -799,6 +808,18 @@ public class WineActivity extends Activity
|
|||||||
if (win.parent == desktop_window) win.create_whole_view();
|
if (win.parent == desktop_window) win.create_whole_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TargetApi(24)
|
||||||
|
public void set_cursor( int id, int width, int height, int hotspotx, int hotspoty, int bits[] )
|
||||||
|
{
|
||||||
|
Log.i( LOGTAG, String.format( "set_cursor id %d size %dx%d hotspot %dx%d", id, width, height, hotspotx, hotspoty ));
|
||||||
|
if (bits != null)
|
||||||
|
{
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap( bits, width, height, Bitmap.Config.ARGB_8888 );
|
||||||
|
current_cursor = PointerIcon.create( bitmap, hotspotx, hotspoty );
|
||||||
|
}
|
||||||
|
else current_cursor = PointerIcon.getSystemIcon( this, id );
|
||||||
|
}
|
||||||
|
|
||||||
public void window_pos_changed( int hwnd, int flags, int insert_after, int owner, int style,
|
public void window_pos_changed( int hwnd, int flags, int insert_after, int owner, int style,
|
||||||
Rect window_rect, Rect client_rect, Rect visible_rect )
|
Rect window_rect, Rect client_rect, Rect visible_rect )
|
||||||
{
|
{
|
||||||
@ -827,6 +848,13 @@ public class WineActivity extends Activity
|
|||||||
runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent, scale, pid ); }} );
|
runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent, scale, pid ); }} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCursor( final int id, final int width, final int height,
|
||||||
|
final int hotspotx, final int hotspoty, final int bits[] )
|
||||||
|
{
|
||||||
|
if (Build.VERSION.SDK_INT < 24) return;
|
||||||
|
runOnUiThread( new Runnable() { public void run() { set_cursor( id, width, height, hotspotx, hotspoty, bits ); }} );
|
||||||
|
}
|
||||||
|
|
||||||
public void windowPosChanged( final int hwnd, final int flags, final int insert_after,
|
public void windowPosChanged( final int hwnd, final int flags, final int insert_after,
|
||||||
final int owner, final int style,
|
final int owner, final int style,
|
||||||
final int window_left, final int window_top,
|
final int window_left, final int window_top,
|
||||||
|
@ -72,6 +72,8 @@ extern int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const R
|
|||||||
HWND after, HWND owner ) DECLSPEC_HIDDEN;
|
HWND after, HWND owner ) DECLSPEC_HIDDEN;
|
||||||
extern int ioctl_set_window_parent( HWND hwnd, HWND parent, float scale ) DECLSPEC_HIDDEN;
|
extern int ioctl_set_window_parent( HWND hwnd, HWND parent, float scale ) DECLSPEC_HIDDEN;
|
||||||
extern int ioctl_set_capture( HWND hwnd ) DECLSPEC_HIDDEN;
|
extern int ioctl_set_capture( HWND hwnd ) DECLSPEC_HIDDEN;
|
||||||
|
extern int ioctl_set_cursor( int id, int width, int height,
|
||||||
|
int hotspotx, int hotspoty, const unsigned int *bits ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
@ -151,7 +153,7 @@ union event_data
|
|||||||
} kbd;
|
} kbd;
|
||||||
};
|
};
|
||||||
|
|
||||||
int send_event( const union event_data *data );
|
int send_event( const union event_data *data ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern JavaVM *wine_get_java_vm(void);
|
extern JavaVM *wine_get_java_vm(void);
|
||||||
extern jobject wine_get_java_object(void);
|
extern jobject wine_get_java_object(void);
|
||||||
|
@ -58,7 +58,7 @@ tasks.whenTaskAdded { t ->
|
|||||||
|
|
||||||
android
|
android
|
||||||
{
|
{
|
||||||
compileSdkVersion 21
|
compileSdkVersion 25
|
||||||
buildToolsVersion "25.0.3"
|
buildToolsVersion "25.0.3"
|
||||||
|
|
||||||
defaultConfig
|
defaultConfig
|
||||||
|
@ -70,6 +70,7 @@ enum android_ioctl
|
|||||||
IOCTL_PERFORM,
|
IOCTL_PERFORM,
|
||||||
IOCTL_SET_SWAP_INT,
|
IOCTL_SET_SWAP_INT,
|
||||||
IOCTL_SET_CAPTURE,
|
IOCTL_SET_CAPTURE,
|
||||||
|
IOCTL_SET_CURSOR,
|
||||||
NB_IOCTLS
|
NB_IOCTLS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -212,6 +213,17 @@ struct ioctl_android_set_capture
|
|||||||
struct ioctl_header hdr;
|
struct ioctl_header hdr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ioctl_android_set_cursor
|
||||||
|
{
|
||||||
|
struct ioctl_header hdr;
|
||||||
|
int id;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int hotspotx;
|
||||||
|
int hotspoty;
|
||||||
|
int bits[1];
|
||||||
|
};
|
||||||
|
|
||||||
static struct gralloc_module_t *gralloc_module;
|
static struct gralloc_module_t *gralloc_module;
|
||||||
static struct gralloc1_device *gralloc1_device;
|
static struct gralloc1_device *gralloc1_device;
|
||||||
static BOOL gralloc1_caps[GRALLOC1_LAST_CAPABILITY + 1];
|
static BOOL gralloc1_caps[GRALLOC1_LAST_CAPABILITY + 1];
|
||||||
@ -1041,6 +1053,44 @@ static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULO
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
|
||||||
|
{
|
||||||
|
static jmethodID method;
|
||||||
|
jobject object;
|
||||||
|
int size;
|
||||||
|
struct ioctl_android_set_cursor *res = data;
|
||||||
|
|
||||||
|
if (in_size < offsetof( struct ioctl_android_set_cursor, bits )) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (res->width < 0 || res->height < 0 || res->width > 256 || res->height > 256)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
size = res->width * res->height;
|
||||||
|
if (in_size != offsetof( struct ioctl_android_set_cursor, bits[size] ))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size );
|
||||||
|
|
||||||
|
if (!(object = load_java_method( &method, "setCursor", "(IIIII[I)V" )))
|
||||||
|
return STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
wrap_java_call();
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
jintArray array = (*jni_env)->NewIntArray( jni_env, size );
|
||||||
|
(*jni_env)->SetIntArrayRegion( jni_env, array, 0, size, (jint *)res->bits );
|
||||||
|
(*jni_env)->CallVoidMethod( jni_env, object, method, 0, res->width, res->height,
|
||||||
|
res->hotspotx, res->hotspoty, array );
|
||||||
|
(*jni_env)->DeleteLocalRef( jni_env, array );
|
||||||
|
}
|
||||||
|
else (*jni_env)->CallVoidMethod( jni_env, object, method, res->id, 0, 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
unwrap_java_call();
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
|
typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
|
||||||
static const ioctl_func ioctl_funcs[] =
|
static const ioctl_func ioctl_funcs[] =
|
||||||
{
|
{
|
||||||
@ -1055,6 +1105,7 @@ static const ioctl_func ioctl_funcs[] =
|
|||||||
perform_ioctl, /* IOCTL_PERFORM */
|
perform_ioctl, /* IOCTL_PERFORM */
|
||||||
setSwapInterval_ioctl, /* IOCTL_SET_SWAP_INT */
|
setSwapInterval_ioctl, /* IOCTL_SET_SWAP_INT */
|
||||||
setCapture_ioctl, /* IOCTL_SET_CAPTURE */
|
setCapture_ioctl, /* IOCTL_SET_CAPTURE */
|
||||||
|
setCursor_ioctl, /* IOCTL_SET_CURSOR */
|
||||||
};
|
};
|
||||||
|
|
||||||
static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
|
static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
|
||||||
@ -1584,3 +1635,24 @@ int ioctl_set_capture( HWND hwnd )
|
|||||||
req.hdr.opengl = FALSE;
|
req.hdr.opengl = FALSE;
|
||||||
return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL );
|
return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ioctl_set_cursor( int id, int width, int height,
|
||||||
|
int hotspotx, int hotspoty, const unsigned int *bits )
|
||||||
|
{
|
||||||
|
struct ioctl_android_set_cursor *req;
|
||||||
|
unsigned int size = offsetof( struct ioctl_android_set_cursor, bits[width * height] );
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!(req = HeapAlloc( GetProcessHeap(), 0, size ))) return -ENOMEM;
|
||||||
|
req->hdr.hwnd = 0; /* unused */
|
||||||
|
req->hdr.opengl = FALSE;
|
||||||
|
req->id = id;
|
||||||
|
req->width = width;
|
||||||
|
req->height = height;
|
||||||
|
req->hotspotx = hotspotx;
|
||||||
|
req->hotspoty = hotspoty;
|
||||||
|
memcpy( req->bits, bits, width * height * sizeof(req->bits[0]) );
|
||||||
|
ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL );
|
||||||
|
HeapFree( GetProcessHeap(), 0, req );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define OEMRESOURCE
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "wingdi.h"
|
#include "wingdi.h"
|
||||||
@ -966,6 +967,226 @@ static void set_surface_layered( struct window_surface *window_surface, BYTE alp
|
|||||||
window_surface->funcs->unlock( window_surface );
|
window_surface->funcs->unlock( window_surface );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_mono_icon_argb
|
||||||
|
*
|
||||||
|
* Return a monochrome icon/cursor bitmap bits in ARGB format.
|
||||||
|
*/
|
||||||
|
static unsigned int *get_mono_icon_argb( HDC hdc, HBITMAP bmp, unsigned int *width, unsigned int *height )
|
||||||
|
{
|
||||||
|
BITMAP bm;
|
||||||
|
char *mask;
|
||||||
|
unsigned int i, j, stride, mask_size, bits_size, *bits = NULL, *ptr;
|
||||||
|
|
||||||
|
if (!GetObjectW( bmp, sizeof(bm), &bm )) return NULL;
|
||||||
|
stride = ((bm.bmWidth + 15) >> 3) & ~1;
|
||||||
|
mask_size = stride * bm.bmHeight;
|
||||||
|
if (!(mask = HeapAlloc( GetProcessHeap(), 0, mask_size ))) return NULL;
|
||||||
|
if (!GetBitmapBits( bmp, mask_size, mask )) goto done;
|
||||||
|
|
||||||
|
bm.bmHeight /= 2;
|
||||||
|
bits_size = bm.bmWidth * bm.bmHeight * sizeof(*bits);
|
||||||
|
if (!(bits = HeapAlloc( GetProcessHeap(), 0, bits_size ))) goto done;
|
||||||
|
|
||||||
|
ptr = bits;
|
||||||
|
for (i = 0; i < bm.bmHeight; i++)
|
||||||
|
for (j = 0; j < bm.bmWidth; j++, ptr++)
|
||||||
|
{
|
||||||
|
int and = ((mask[i * stride + j / 8] << (j % 8)) & 0x80);
|
||||||
|
int xor = ((mask[(i + bm.bmHeight) * stride + j / 8] << (j % 8)) & 0x80);
|
||||||
|
if (!xor && and)
|
||||||
|
*ptr = 0;
|
||||||
|
else if (xor && !and)
|
||||||
|
*ptr = 0xffffffff;
|
||||||
|
else
|
||||||
|
/* we can't draw "invert" pixels, so render them as black instead */
|
||||||
|
*ptr = 0xff000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
*width = bm.bmWidth;
|
||||||
|
*height = bm.bmHeight;
|
||||||
|
|
||||||
|
done:
|
||||||
|
HeapFree( GetProcessHeap(), 0, mask );
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_bitmap_argb
|
||||||
|
*
|
||||||
|
* Return the bitmap bits in ARGB format. Helper for setting icons and cursors.
|
||||||
|
*/
|
||||||
|
static unsigned int *get_bitmap_argb( HDC hdc, HBITMAP color, HBITMAP mask, unsigned int *width,
|
||||||
|
unsigned int *height )
|
||||||
|
{
|
||||||
|
char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
|
||||||
|
BITMAPINFO *info = (BITMAPINFO *)buffer;
|
||||||
|
BITMAP bm;
|
||||||
|
unsigned int *ptr, *bits = NULL;
|
||||||
|
unsigned char *mask_bits = NULL;
|
||||||
|
int i, j;
|
||||||
|
BOOL has_alpha = FALSE;
|
||||||
|
|
||||||
|
if (!color) return get_mono_icon_argb( hdc, mask, width, height );
|
||||||
|
|
||||||
|
if (!GetObjectW( color, sizeof(bm), &bm )) return NULL;
|
||||||
|
info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
info->bmiHeader.biWidth = bm.bmWidth;
|
||||||
|
info->bmiHeader.biHeight = -bm.bmHeight;
|
||||||
|
info->bmiHeader.biPlanes = 1;
|
||||||
|
info->bmiHeader.biBitCount = 32;
|
||||||
|
info->bmiHeader.biCompression = BI_RGB;
|
||||||
|
info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
|
||||||
|
info->bmiHeader.biXPelsPerMeter = 0;
|
||||||
|
info->bmiHeader.biYPelsPerMeter = 0;
|
||||||
|
info->bmiHeader.biClrUsed = 0;
|
||||||
|
info->bmiHeader.biClrImportant = 0;
|
||||||
|
if (!(bits = HeapAlloc( GetProcessHeap(), 0, bm.bmWidth * bm.bmHeight * sizeof(unsigned int) )))
|
||||||
|
goto failed;
|
||||||
|
if (!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) goto failed;
|
||||||
|
|
||||||
|
*width = bm.bmWidth;
|
||||||
|
*height = bm.bmHeight;
|
||||||
|
|
||||||
|
for (i = 0; i < bm.bmWidth * bm.bmHeight; i++)
|
||||||
|
if ((has_alpha = (bits[i] & 0xff000000) != 0)) break;
|
||||||
|
|
||||||
|
if (!has_alpha)
|
||||||
|
{
|
||||||
|
unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4;
|
||||||
|
/* generate alpha channel from the mask */
|
||||||
|
info->bmiHeader.biBitCount = 1;
|
||||||
|
info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight;
|
||||||
|
if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto failed;
|
||||||
|
if (!GetDIBits( hdc, mask, 0, bm.bmHeight, mask_bits, info, DIB_RGB_COLORS )) goto failed;
|
||||||
|
ptr = bits;
|
||||||
|
for (i = 0; i < bm.bmHeight; i++)
|
||||||
|
for (j = 0; j < bm.bmWidth; j++, ptr++)
|
||||||
|
if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000;
|
||||||
|
HeapFree( GetProcessHeap(), 0, mask_bits );
|
||||||
|
}
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
HeapFree( GetProcessHeap(), 0, bits );
|
||||||
|
HeapFree( GetProcessHeap(), 0, mask_bits );
|
||||||
|
*width = *height = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum android_system_cursors
|
||||||
|
{
|
||||||
|
TYPE_ARROW = 1000,
|
||||||
|
TYPE_CONTEXT_MENU = 1001,
|
||||||
|
TYPE_HAND = 1002,
|
||||||
|
TYPE_HELP = 1003,
|
||||||
|
TYPE_WAIT = 1004,
|
||||||
|
TYPE_CELL = 1006,
|
||||||
|
TYPE_CROSSHAIR = 1007,
|
||||||
|
TYPE_TEXT = 1008,
|
||||||
|
TYPE_VERTICAL_TEXT = 1009,
|
||||||
|
TYPE_ALIAS = 1010,
|
||||||
|
TYPE_COPY = 1011,
|
||||||
|
TYPE_NO_DROP = 1012,
|
||||||
|
TYPE_ALL_SCROLL = 1013,
|
||||||
|
TYPE_HORIZONTAL_DOUBLE_ARROW = 1014,
|
||||||
|
TYPE_VERTICAL_DOUBLE_ARROW = 1015,
|
||||||
|
TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016,
|
||||||
|
TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017,
|
||||||
|
TYPE_ZOOM_IN = 1018,
|
||||||
|
TYPE_ZOOM_OUT = 1019,
|
||||||
|
TYPE_GRAB = 1020,
|
||||||
|
TYPE_GRABBING = 1021,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct system_cursors
|
||||||
|
{
|
||||||
|
WORD id;
|
||||||
|
enum android_system_cursors android_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct system_cursors user32_cursors[] =
|
||||||
|
{
|
||||||
|
{ OCR_NORMAL, TYPE_ARROW },
|
||||||
|
{ OCR_IBEAM, TYPE_TEXT },
|
||||||
|
{ OCR_WAIT, TYPE_WAIT },
|
||||||
|
{ OCR_CROSS, TYPE_CROSSHAIR },
|
||||||
|
{ OCR_SIZE, TYPE_ALL_SCROLL },
|
||||||
|
{ OCR_SIZEALL, TYPE_ALL_SCROLL },
|
||||||
|
{ OCR_SIZENWSE, TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW },
|
||||||
|
{ OCR_SIZENESW, TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW },
|
||||||
|
{ OCR_SIZEWE, TYPE_HORIZONTAL_DOUBLE_ARROW },
|
||||||
|
{ OCR_SIZENS, TYPE_VERTICAL_DOUBLE_ARROW },
|
||||||
|
{ OCR_NO, TYPE_NO_DROP },
|
||||||
|
{ OCR_HAND, TYPE_HAND },
|
||||||
|
{ OCR_HELP, TYPE_HELP },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct system_cursors comctl32_cursors[] =
|
||||||
|
{
|
||||||
|
/* 102 TYPE_MOVE doesn't exist */
|
||||||
|
{ 104, TYPE_COPY },
|
||||||
|
{ 105, TYPE_ARROW },
|
||||||
|
{ 106, TYPE_HORIZONTAL_DOUBLE_ARROW },
|
||||||
|
{ 107, TYPE_HORIZONTAL_DOUBLE_ARROW },
|
||||||
|
{ 108, TYPE_GRABBING },
|
||||||
|
{ 135, TYPE_VERTICAL_DOUBLE_ARROW },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct system_cursors ole32_cursors[] =
|
||||||
|
{
|
||||||
|
{ 1, TYPE_NO_DROP },
|
||||||
|
/* 2 TYPE_MOVE doesn't exist */
|
||||||
|
{ 3, TYPE_COPY },
|
||||||
|
{ 4, TYPE_ALIAS },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct system_cursors riched20_cursors[] =
|
||||||
|
{
|
||||||
|
{ 105, TYPE_GRABBING },
|
||||||
|
{ 109, TYPE_COPY },
|
||||||
|
/* 110 TYPE_MOVE doesn't exist */
|
||||||
|
{ 111, TYPE_NO_DROP },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const struct system_cursors *cursors;
|
||||||
|
WCHAR name[16];
|
||||||
|
} module_cursors[] =
|
||||||
|
{
|
||||||
|
{ user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
|
||||||
|
{ comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
|
||||||
|
{ ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
|
||||||
|
{ riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_cursor_system_id( const ICONINFOEXW *info )
|
||||||
|
{
|
||||||
|
const struct system_cursors *cursors;
|
||||||
|
unsigned int i;
|
||||||
|
HMODULE module;
|
||||||
|
|
||||||
|
if (info->szResName[0]) return 0; /* only integer resources are supported here */
|
||||||
|
if (!(module = GetModuleHandleW( info->szModName ))) return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(module_cursors)/sizeof(module_cursors[0]); i++)
|
||||||
|
if (GetModuleHandleW( module_cursors[i].name ) == module) break;
|
||||||
|
if (i == sizeof(module_cursors)/sizeof(module_cursors[0])) return 0;
|
||||||
|
|
||||||
|
cursors = module_cursors[i].cursors;
|
||||||
|
for (i = 0; cursors[i].id; i++)
|
||||||
|
if (cursors[i].id == info->wResID) return cursors[i].android_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static WNDPROC desktop_orig_wndproc;
|
static WNDPROC desktop_orig_wndproc;
|
||||||
|
|
||||||
@ -1204,6 +1425,51 @@ void CDECL ANDROID_SetCapture( HWND hwnd, UINT flags )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* ANDROID_SetCursor
|
||||||
|
*/
|
||||||
|
void CDECL ANDROID_SetCursor( HCURSOR handle )
|
||||||
|
{
|
||||||
|
static HCURSOR last_cursor;
|
||||||
|
static DWORD last_cursor_change;
|
||||||
|
|
||||||
|
if (InterlockedExchangePointer( (void **)&last_cursor, handle ) != handle ||
|
||||||
|
GetTickCount() - last_cursor_change > 100)
|
||||||
|
{
|
||||||
|
last_cursor_change = GetTickCount();
|
||||||
|
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
unsigned int width = 0, height = 0, *bits = NULL;
|
||||||
|
ICONINFOEXW info;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
info.cbSize = sizeof(info);
|
||||||
|
if (!GetIconInfoExW( handle, &info )) return;
|
||||||
|
|
||||||
|
if (!(id = get_cursor_system_id( &info )))
|
||||||
|
{
|
||||||
|
HDC hdc = CreateCompatibleDC( 0 );
|
||||||
|
bits = get_bitmap_argb( hdc, info.hbmColor, info.hbmMask, &width, &height );
|
||||||
|
DeleteDC( hdc );
|
||||||
|
|
||||||
|
/* make sure hotspot is valid */
|
||||||
|
if (info.xHotspot >= width || info.yHotspot >= height)
|
||||||
|
{
|
||||||
|
info.xHotspot = width / 2;
|
||||||
|
info.yHotspot = height / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ioctl_set_cursor( id, width, height, info.xHotspot, info.yHotspot, bits );
|
||||||
|
HeapFree( GetProcessHeap(), 0, bits );
|
||||||
|
DeleteObject( info.hbmColor );
|
||||||
|
DeleteObject( info.hbmMask );
|
||||||
|
}
|
||||||
|
else ioctl_set_cursor( 0, 0, 0, 0, 0, NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ANDROID_SetWindowStyle
|
* ANDROID_SetWindowStyle
|
||||||
*/
|
*/
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
@ cdecl MapVirtualKeyEx(long long long) ANDROID_MapVirtualKeyEx
|
@ cdecl MapVirtualKeyEx(long long long) ANDROID_MapVirtualKeyEx
|
||||||
@ cdecl ToUnicodeEx(long long ptr ptr long long long) ANDROID_ToUnicodeEx
|
@ cdecl ToUnicodeEx(long long ptr ptr long long long) ANDROID_ToUnicodeEx
|
||||||
@ cdecl VkKeyScanEx(long long) ANDROID_VkKeyScanEx
|
@ cdecl VkKeyScanEx(long long) ANDROID_VkKeyScanEx
|
||||||
|
@ cdecl SetCursor(long) ANDROID_SetCursor
|
||||||
@ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) ANDROID_ChangeDisplaySettingsEx
|
@ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) ANDROID_ChangeDisplaySettingsEx
|
||||||
@ cdecl EnumDisplayMonitors(long ptr ptr long) ANDROID_EnumDisplayMonitors
|
@ cdecl EnumDisplayMonitors(long ptr ptr long) ANDROID_EnumDisplayMonitors
|
||||||
@ cdecl EnumDisplaySettingsEx(ptr long ptr long) ANDROID_EnumDisplaySettingsEx
|
@ cdecl EnumDisplaySettingsEx(ptr long ptr long) ANDROID_EnumDisplaySettingsEx
|
||||||
|
Loading…
x
Reference in New Issue
Block a user