Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
1b987bfd
Commit
1b987bfd
authored
Aug 25, 2023
by
Alexandros Frantzis
Committed by
Alexandre Julliard
Sep 11, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
winewayland.drv: Implement SetCursor using cursor bitmap data.
Set the cursor image used for Wayland surfaces by using the Windows cursor bitmap data.
parent
b8b90e40
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
300 additions
and
0 deletions
+300
-0
wayland_pointer.c
dlls/winewayland.drv/wayland_pointer.c
+286
-0
wayland_surface.c
dlls/winewayland.drv/wayland_surface.c
+3
-0
waylanddrv.h
dlls/winewayland.drv/waylanddrv.h
+10
-0
waylanddrv_main.c
dlls/winewayland.drv/waylanddrv_main.c
+1
-0
No files found.
dlls/winewayland.drv/wayland_pointer.c
View file @
1b987bfd
...
...
@@ -27,6 +27,7 @@
#include <linux/input.h>
#undef SW_MAX
/* Also defined in winuser.rh */
#include <math.h>
#include <stdlib.h>
#include "waylanddrv.h"
#include "wine/debug.h"
...
...
@@ -93,6 +94,14 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
pthread_mutex_lock
(
&
pointer
->
mutex
);
pointer
->
focused_hwnd
=
hwnd
;
pointer
->
enter_serial
=
serial
;
/* The cursor is undefined at every enter, so we set it again with
* the latest information we have. */
wl_pointer_set_cursor
(
pointer
->
wl_pointer
,
pointer
->
enter_serial
,
pointer
->
cursor
.
wl_surface
,
pointer
->
cursor
.
hotspot_x
,
pointer
->
cursor
.
hotspot_y
);
pthread_mutex_unlock
(
&
pointer
->
mutex
);
/* Handle the enter as a motion, to account for cases where the
...
...
@@ -112,6 +121,7 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
pthread_mutex_lock
(
&
pointer
->
mutex
);
pointer
->
focused_hwnd
=
NULL
;
pointer
->
enter_serial
=
0
;
pthread_mutex_unlock
(
&
pointer
->
mutex
);
}
...
...
@@ -208,6 +218,7 @@ void wayland_pointer_init(struct wl_pointer *wl_pointer)
pthread_mutex_lock
(
&
pointer
->
mutex
);
pointer
->
wl_pointer
=
wl_pointer
;
pointer
->
focused_hwnd
=
NULL
;
pointer
->
enter_serial
=
0
;
pthread_mutex_unlock
(
&
pointer
->
mutex
);
wl_pointer_add_listener
(
pointer
->
wl_pointer
,
&
pointer_listener
,
NULL
);
}
...
...
@@ -220,5 +231,280 @@ void wayland_pointer_deinit(void)
wl_pointer_release
(
pointer
->
wl_pointer
);
pointer
->
wl_pointer
=
NULL
;
pointer
->
focused_hwnd
=
NULL
;
pointer
->
enter_serial
=
0
;
pthread_mutex_unlock
(
&
pointer
->
mutex
);
}
/***********************************************************************
* create_mono_cursor_buffer
*
* Create a wayland_shm_buffer for a monochrome cursor bitmap.
*
* Adapted from wineandroid.drv code.
*/
static
struct
wayland_shm_buffer
*
create_mono_cursor_buffer
(
HBITMAP
bmp
)
{
struct
wayland_shm_buffer
*
shm_buffer
=
NULL
;
BITMAP
bm
;
char
*
mask
=
NULL
;
unsigned
int
i
,
j
,
stride
,
mask_size
,
*
ptr
;
if
(
!
NtGdiExtGetObjectW
(
bmp
,
sizeof
(
bm
),
&
bm
))
goto
done
;
stride
=
((
bm
.
bmWidth
+
15
)
>>
3
)
&
~
1
;
mask_size
=
stride
*
bm
.
bmHeight
;
if
(
!
(
mask
=
malloc
(
mask_size
)))
goto
done
;
if
(
!
NtGdiGetBitmapBits
(
bmp
,
mask_size
,
mask
))
goto
done
;
bm
.
bmHeight
/=
2
;
shm_buffer
=
wayland_shm_buffer_create
(
bm
.
bmWidth
,
bm
.
bmHeight
,
WL_SHM_FORMAT_ARGB8888
);
if
(
!
shm_buffer
)
goto
done
;
ptr
=
shm_buffer
->
map_data
;
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
;
}
}
done:
free
(
mask
);
return
shm_buffer
;
}
/***********************************************************************
* create_color_cursor_buffer
*
* Create a wayland_shm_buffer for a color cursor bitmap.
*
* Adapted from wineandroid.drv code.
*/
static
struct
wayland_shm_buffer
*
create_color_cursor_buffer
(
HDC
hdc
,
HBITMAP
color
,
HBITMAP
mask
)
{
struct
wayland_shm_buffer
*
shm_buffer
=
NULL
;
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
(
!
NtGdiExtGetObjectW
(
color
,
sizeof
(
bm
),
&
bm
))
goto
failed
;
shm_buffer
=
wayland_shm_buffer_create
(
bm
.
bmWidth
,
bm
.
bmHeight
,
WL_SHM_FORMAT_ARGB8888
);
if
(
!
shm_buffer
)
goto
failed
;
bits
=
shm_buffer
->
map_data
;
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
(
!
NtGdiGetDIBitsInternal
(
hdc
,
color
,
0
,
bm
.
bmHeight
,
bits
,
info
,
DIB_RGB_COLORS
,
0
,
0
))
goto
failed
;
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
=
malloc
(
info
->
bmiHeader
.
biSizeImage
)))
goto
failed
;
if
(
!
NtGdiGetDIBitsInternal
(
hdc
,
mask
,
0
,
bm
.
bmHeight
,
mask_bits
,
info
,
DIB_RGB_COLORS
,
0
,
0
))
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
;
}
}
free
(
mask_bits
);
}
/* Wayland requires pre-multiplied alpha values */
for
(
ptr
=
bits
,
i
=
0
;
i
<
bm
.
bmWidth
*
bm
.
bmHeight
;
ptr
++
,
i
++
)
{
unsigned
char
alpha
=
*
ptr
>>
24
;
if
(
alpha
==
0
)
{
*
ptr
=
0
;
}
else
if
(
alpha
!=
255
)
{
*
ptr
=
(
alpha
<<
24
)
|
(((
BYTE
)(
*
ptr
>>
16
)
*
alpha
/
255
)
<<
16
)
|
(((
BYTE
)(
*
ptr
>>
8
)
*
alpha
/
255
)
<<
8
)
|
(((
BYTE
)
*
ptr
*
alpha
/
255
));
}
}
return
shm_buffer
;
failed:
if
(
shm_buffer
)
wayland_shm_buffer_unref
(
shm_buffer
);
free
(
mask_bits
);
return
NULL
;
}
/***********************************************************************
* get_icon_info
*
* Local GetIconInfoExW helper implementation.
*/
static
BOOL
get_icon_info
(
HICON
handle
,
ICONINFOEXW
*
ret
)
{
UNICODE_STRING
module
,
res_name
;
ICONINFO
info
;
module
.
Buffer
=
ret
->
szModName
;
module
.
MaximumLength
=
sizeof
(
ret
->
szModName
)
-
sizeof
(
WCHAR
);
res_name
.
Buffer
=
ret
->
szResName
;
res_name
.
MaximumLength
=
sizeof
(
ret
->
szResName
)
-
sizeof
(
WCHAR
);
if
(
!
NtUserGetIconInfo
(
handle
,
&
info
,
&
module
,
&
res_name
,
NULL
,
0
))
return
FALSE
;
ret
->
fIcon
=
info
.
fIcon
;
ret
->
xHotspot
=
info
.
xHotspot
;
ret
->
yHotspot
=
info
.
yHotspot
;
ret
->
hbmColor
=
info
.
hbmColor
;
ret
->
hbmMask
=
info
.
hbmMask
;
ret
->
wResID
=
res_name
.
Length
?
0
:
LOWORD
(
res_name
.
Buffer
);
ret
->
szModName
[
module
.
Length
]
=
0
;
ret
->
szResName
[
res_name
.
Length
]
=
0
;
return
TRUE
;
}
static
void
wayland_pointer_update_cursor
(
HCURSOR
hcursor
)
{
struct
wayland_cursor
*
cursor
=
&
process_wayland
.
pointer
.
cursor
;
ICONINFOEXW
info
=
{
0
};
if
(
!
hcursor
)
goto
clear_cursor
;
/* Create a new buffer for the specified cursor. */
if
(
cursor
->
shm_buffer
)
{
wayland_shm_buffer_unref
(
cursor
->
shm_buffer
);
cursor
->
shm_buffer
=
NULL
;
}
if
(
!
get_icon_info
(
hcursor
,
&
info
))
{
ERR
(
"Failed to get icon info for cursor=%p
\n
"
,
hcursor
);
goto
clear_cursor
;
}
if
(
info
.
hbmColor
)
{
HDC
hdc
=
NtGdiCreateCompatibleDC
(
0
);
cursor
->
shm_buffer
=
create_color_cursor_buffer
(
hdc
,
info
.
hbmColor
,
info
.
hbmMask
);
NtGdiDeleteObjectApp
(
hdc
);
}
else
{
cursor
->
shm_buffer
=
create_mono_cursor_buffer
(
info
.
hbmMask
);
}
if
(
info
.
hbmColor
)
NtGdiDeleteObjectApp
(
info
.
hbmColor
);
if
(
info
.
hbmMask
)
NtGdiDeleteObjectApp
(
info
.
hbmMask
);
cursor
->
hotspot_x
=
info
.
xHotspot
;
cursor
->
hotspot_y
=
info
.
yHotspot
;
if
(
!
cursor
->
shm_buffer
)
{
ERR
(
"Failed to create shm_buffer for cursor=%p
\n
"
,
hcursor
);
goto
clear_cursor
;
}
/* Make sure the hotspot is valid. */
if
(
cursor
->
hotspot_x
>=
cursor
->
shm_buffer
->
width
||
cursor
->
hotspot_y
>=
cursor
->
shm_buffer
->
height
)
{
cursor
->
hotspot_x
=
cursor
->
shm_buffer
->
width
/
2
;
cursor
->
hotspot_y
=
cursor
->
shm_buffer
->
height
/
2
;
}
if
(
!
cursor
->
wl_surface
)
{
cursor
->
wl_surface
=
wl_compositor_create_surface
(
process_wayland
.
wl_compositor
);
if
(
!
cursor
->
wl_surface
)
{
ERR
(
"Failed to create wl_surface for cursor
\n
"
);
goto
clear_cursor
;
}
}
/* Commit the cursor buffer to the cursor surface. */
wl_surface_attach
(
cursor
->
wl_surface
,
cursor
->
shm_buffer
->
wl_buffer
,
0
,
0
);
wl_surface_damage_buffer
(
cursor
->
wl_surface
,
0
,
0
,
cursor
->
shm_buffer
->
width
,
cursor
->
shm_buffer
->
height
);
wl_surface_commit
(
cursor
->
wl_surface
);
return
;
clear_cursor:
if
(
cursor
->
shm_buffer
)
{
wayland_shm_buffer_unref
(
cursor
->
shm_buffer
);
cursor
->
shm_buffer
=
NULL
;
}
if
(
cursor
->
wl_surface
)
{
wl_surface_destroy
(
cursor
->
wl_surface
);
cursor
->
wl_surface
=
NULL
;
}
}
/***********************************************************************
* WAYLAND_SetCursor
*/
void
WAYLAND_SetCursor
(
HWND
hwnd
,
HCURSOR
hcursor
)
{
struct
wayland_pointer
*
pointer
=
&
process_wayland
.
pointer
;
TRACE
(
"hwnd=%p hcursor=%p
\n
"
,
hwnd
,
hcursor
);
pthread_mutex_lock
(
&
pointer
->
mutex
);
if
(
pointer
->
focused_hwnd
==
hwnd
)
{
wayland_pointer_update_cursor
(
hcursor
);
wl_pointer_set_cursor
(
pointer
->
wl_pointer
,
pointer
->
enter_serial
,
pointer
->
cursor
.
wl_surface
,
pointer
->
cursor
.
hotspot_x
,
pointer
->
cursor
.
hotspot_y
);
wl_display_flush
(
process_wayland
.
wl_display
);
}
pthread_mutex_unlock
(
&
pointer
->
mutex
);
}
dlls/winewayland.drv/wayland_surface.c
View file @
1b987bfd
...
...
@@ -126,7 +126,10 @@ void wayland_surface_destroy(struct wayland_surface *surface)
{
pthread_mutex_lock
(
&
process_wayland
.
pointer
.
mutex
);
if
(
process_wayland
.
pointer
.
focused_hwnd
==
surface
->
hwnd
)
{
process_wayland
.
pointer
.
focused_hwnd
=
NULL
;
process_wayland
.
pointer
.
enter_serial
=
0
;
}
pthread_mutex_unlock
(
&
process_wayland
.
pointer
.
mutex
);
pthread_mutex_lock
(
&
xdg_data_mutex
);
...
...
dlls/winewayland.drv/waylanddrv.h
View file @
1b987bfd
...
...
@@ -56,10 +56,19 @@ enum wayland_window_message
WM_WAYLAND_INIT_DISPLAY_DEVICES
=
0x80001000
};
struct
wayland_cursor
{
struct
wayland_shm_buffer
*
shm_buffer
;
struct
wl_surface
*
wl_surface
;
int
hotspot_x
,
hotspot_y
;
};
struct
wayland_pointer
{
struct
wl_pointer
*
wl_pointer
;
HWND
focused_hwnd
;
uint32_t
enter_serial
;
struct
wayland_cursor
cursor
;
pthread_mutex_t
mutex
;
};
...
...
@@ -204,6 +213,7 @@ RGNDATA *get_region_data(HRGN region) DECLSPEC_HIDDEN;
LRESULT
WAYLAND_DesktopWindowProc
(
HWND
hwnd
,
UINT
msg
,
WPARAM
wp
,
LPARAM
lp
)
DECLSPEC_HIDDEN
;
void
WAYLAND_DestroyWindow
(
HWND
hwnd
)
DECLSPEC_HIDDEN
;
void
WAYLAND_SetCursor
(
HWND
hwnd
,
HCURSOR
hcursor
)
DECLSPEC_HIDDEN
;
BOOL
WAYLAND_UpdateDisplayDevices
(
const
struct
gdi_device_manager
*
device_manager
,
BOOL
force
,
void
*
param
)
DECLSPEC_HIDDEN
;
LRESULT
WAYLAND_WindowMessage
(
HWND
hwnd
,
UINT
msg
,
WPARAM
wp
,
LPARAM
lp
)
DECLSPEC_HIDDEN
;
...
...
dlls/winewayland.drv/waylanddrv_main.c
View file @
1b987bfd
...
...
@@ -33,6 +33,7 @@ static const struct user_driver_funcs waylanddrv_funcs =
{
.
pDesktopWindowProc
=
WAYLAND_DesktopWindowProc
,
.
pDestroyWindow
=
WAYLAND_DestroyWindow
,
.
pSetCursor
=
WAYLAND_SetCursor
,
.
pUpdateDisplayDevices
=
WAYLAND_UpdateDisplayDevices
,
.
pWindowMessage
=
WAYLAND_WindowMessage
,
.
pWindowPosChanged
=
WAYLAND_WindowPosChanged
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment