1
1
use winapi:: shared:: guiddef:: GUID ;
2
- use winapi:: shared:: minwindef:: { ATOM , FALSE , LPARAM , LRESULT , UINT , WPARAM } ;
2
+ use winapi:: shared:: minwindef:: { ATOM , FALSE , LOWORD , LPARAM , LRESULT , UINT , WPARAM } ;
3
3
use winapi:: shared:: windef:: { HWND , RECT } ;
4
4
use winapi:: um:: combaseapi:: CoCreateGuid ;
5
5
use winapi:: um:: ole2:: { OleInitialize , RegisterDragDrop , RevokeDragDrop } ;
6
6
use winapi:: um:: oleidl:: LPDROPTARGET ;
7
7
use winapi:: um:: winuser:: {
8
8
AdjustWindowRectEx , CreateWindowExW , DefWindowProcW , DestroyWindow , DispatchMessageW ,
9
9
GetDpiForWindow , GetFocus , GetMessageW , GetWindowLongPtrW , LoadCursorW , PostMessageW ,
10
- RegisterClassW , ReleaseCapture , SetCapture , SetFocus , SetProcessDpiAwarenessContext , SetTimer ,
11
- SetWindowLongPtrW , SetWindowPos , TrackMouseEvent , TranslateMessage , UnregisterClassW , CS_OWNDC ,
12
- GET_XBUTTON_WPARAM , GWLP_USERDATA , IDC_ARROW , MSG , SWP_NOMOVE , SWP_NOZORDER , TRACKMOUSEEVENT ,
13
- WHEEL_DELTA , WM_CHAR , WM_CLOSE , WM_CREATE , WM_DPICHANGED , WM_INPUTLANGCHANGE , WM_KEYDOWN ,
14
- WM_KEYUP , WM_LBUTTONDOWN , WM_LBUTTONUP , WM_MBUTTONDOWN , WM_MBUTTONUP , WM_MOUSEHWHEEL ,
15
- WM_MOUSELEAVE , WM_MOUSEMOVE , WM_MOUSEWHEEL , WM_NCDESTROY , WM_RBUTTONDOWN , WM_RBUTTONUP ,
16
- WM_SHOWWINDOW , WM_SIZE , WM_SYSCHAR , WM_SYSKEYDOWN , WM_SYSKEYUP , WM_TIMER , WM_USER ,
17
- WM_XBUTTONDOWN , WM_XBUTTONUP , WNDCLASSW , WS_CAPTION , WS_CHILD , WS_CLIPSIBLINGS , WS_MAXIMIZEBOX ,
18
- WS_MINIMIZEBOX , WS_POPUPWINDOW , WS_SIZEBOX , WS_VISIBLE , XBUTTON1 , XBUTTON2 ,
10
+ RegisterClassW , ReleaseCapture , SetCapture , SetCursor , SetFocus , SetProcessDpiAwarenessContext ,
11
+ SetTimer , SetWindowLongPtrW , SetWindowPos , TrackMouseEvent , TranslateMessage , UnregisterClassW ,
12
+ CS_OWNDC , GET_XBUTTON_WPARAM , GWLP_USERDATA , HTCLIENT , IDC_ARROW , MSG , SWP_NOMOVE ,
13
+ SWP_NOZORDER , TRACKMOUSEEVENT , WHEEL_DELTA , WM_CHAR , WM_CLOSE , WM_CREATE , WM_DPICHANGED ,
14
+ WM_INPUTLANGCHANGE , WM_KEYDOWN , WM_KEYUP , WM_LBUTTONDOWN , WM_LBUTTONUP , WM_MBUTTONDOWN ,
15
+ WM_MBUTTONUP , WM_MOUSEHWHEEL , WM_MOUSELEAVE , WM_MOUSEMOVE , WM_MOUSEWHEEL , WM_NCDESTROY ,
16
+ WM_RBUTTONDOWN , WM_RBUTTONUP , WM_SETCURSOR , WM_SHOWWINDOW , WM_SIZE , WM_SYSCHAR , WM_SYSKEYDOWN ,
17
+ WM_SYSKEYUP , WM_TIMER , WM_USER , WM_XBUTTONDOWN , WM_XBUTTONUP , WNDCLASSW , WS_CAPTION , WS_CHILD ,
18
+ WS_CLIPSIBLINGS , WS_MAXIMIZEBOX , WS_MINIMIZEBOX , WS_POPUPWINDOW , WS_SIZEBOX , WS_VISIBLE ,
19
+ XBUTTON1 , XBUTTON2 ,
19
20
} ;
20
21
21
22
use std:: cell:: { Cell , Ref , RefCell , RefMut } ;
@@ -37,6 +38,7 @@ use crate::{
37
38
WindowHandler , WindowInfo , WindowOpenOptions , WindowScalePolicy ,
38
39
} ;
39
40
41
+ use super :: cursor:: cursor_to_lpcwstr;
40
42
use super :: drop_target:: DropTarget ;
41
43
use super :: keyboard:: KeyboardState ;
42
44
@@ -428,6 +430,24 @@ unsafe fn wnd_proc_inner(
428
430
429
431
None
430
432
}
433
+ // If WM_SETCURSOR returns `None`, WM_SETCURSOR continues to get handled by the outer window(s),
434
+ // If it returns `Some(1)`, the current window decides what the cursor is
435
+ WM_SETCURSOR => {
436
+ let low_word = LOWORD ( lparam as u32 ) as isize ;
437
+ let mouse_in_window = low_word == HTCLIENT ;
438
+ if mouse_in_window {
439
+ // Here we need to set the cursor back to what the state says, since it can have changed when outside the window
440
+ let cursor =
441
+ LoadCursorW ( null_mut ( ) , cursor_to_lpcwstr ( window_state. cursor_icon . get ( ) ) ) ;
442
+ unsafe {
443
+ SetCursor ( cursor) ;
444
+ }
445
+ Some ( 1 )
446
+ } else {
447
+ // Cursor is being changed by some other window, e.g. when having mouse on the borders to resize it
448
+ None
449
+ }
450
+ }
431
451
// NOTE: `WM_NCDESTROY` is handled in the outer function because this deallocates the window
432
452
// state
433
453
BV_WINDOW_MUST_CLOSE => {
@@ -480,6 +500,7 @@ pub(super) struct WindowState {
480
500
keyboard_state : RefCell < KeyboardState > ,
481
501
mouse_button_counter : Cell < usize > ,
482
502
mouse_was_outside_window : RefCell < bool > ,
503
+ cursor_icon : Cell < MouseCursor > ,
483
504
// Initialized late so the `Window` can hold a reference to this `WindowState`
484
505
handler : RefCell < Option < Box < dyn WindowHandler > > > ,
485
506
_drop_target : RefCell < Option < Rc < DropTarget > > > ,
@@ -685,6 +706,7 @@ impl Window<'_> {
685
706
keyboard_state : RefCell :: new ( KeyboardState :: new ( ) ) ,
686
707
mouse_button_counter : Cell :: new ( 0 ) ,
687
708
mouse_was_outside_window : RefCell :: new ( true ) ,
709
+ cursor_icon : Cell :: new ( MouseCursor :: Default ) ,
688
710
// The Window refers to this `WindowState`, so this `handler` needs to be
689
711
// initialized later
690
712
handler : RefCell :: new ( None ) ,
@@ -790,8 +812,12 @@ impl Window<'_> {
790
812
self . state . deferred_tasks . borrow_mut ( ) . push_back ( task) ;
791
813
}
792
814
793
- pub fn set_mouse_cursor ( & mut self , _mouse_cursor : MouseCursor ) {
794
- todo ! ( )
815
+ pub fn set_mouse_cursor ( & mut self , mouse_cursor : MouseCursor ) {
816
+ self . state . cursor_icon . set ( mouse_cursor) ;
817
+ unsafe {
818
+ let cursor = LoadCursorW ( null_mut ( ) , cursor_to_lpcwstr ( mouse_cursor) ) ;
819
+ SetCursor ( cursor) ;
820
+ }
795
821
}
796
822
797
823
#[ cfg( feature = "opengl" ) ]
0 commit comments