11use 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 } ;
33use winapi:: shared:: windef:: { HWND , RECT } ;
44use winapi:: um:: combaseapi:: CoCreateGuid ;
55use winapi:: um:: ole2:: { OleInitialize , RegisterDragDrop , RevokeDragDrop } ;
66use winapi:: um:: oleidl:: LPDROPTARGET ;
77use winapi:: um:: winuser:: {
88 AdjustWindowRectEx , CreateWindowExW , DefWindowProcW , DestroyWindow , DispatchMessageW ,
99 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 ,
1920} ;
2021
2122use std:: cell:: { Cell , Ref , RefCell , RefMut } ;
@@ -37,6 +38,7 @@ use crate::{
3738 WindowHandler , WindowInfo , WindowOpenOptions , WindowScalePolicy ,
3839} ;
3940
41+ use super :: cursor:: cursor_to_lpcwstr;
4042use super :: drop_target:: DropTarget ;
4143use super :: keyboard:: KeyboardState ;
4244
@@ -428,6 +430,24 @@ unsafe fn wnd_proc_inner(
428430
429431 None
430432 }
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+ }
431451 // NOTE: `WM_NCDESTROY` is handled in the outer function because this deallocates the window
432452 // state
433453 BV_WINDOW_MUST_CLOSE => {
@@ -480,6 +500,7 @@ pub(super) struct WindowState {
480500 keyboard_state : RefCell < KeyboardState > ,
481501 mouse_button_counter : Cell < usize > ,
482502 mouse_was_outside_window : RefCell < bool > ,
503+ cursor_icon : Cell < MouseCursor > ,
483504 // Initialized late so the `Window` can hold a reference to this `WindowState`
484505 handler : RefCell < Option < Box < dyn WindowHandler > > > ,
485506 _drop_target : RefCell < Option < Rc < DropTarget > > > ,
@@ -685,6 +706,7 @@ impl Window<'_> {
685706 keyboard_state : RefCell :: new ( KeyboardState :: new ( ) ) ,
686707 mouse_button_counter : Cell :: new ( 0 ) ,
687708 mouse_was_outside_window : RefCell :: new ( true ) ,
709+ cursor_icon : Cell :: new ( MouseCursor :: Default ) ,
688710 // The Window refers to this `WindowState`, so this `handler` needs to be
689711 // initialized later
690712 handler : RefCell :: new ( None ) ,
@@ -790,8 +812,12 @@ impl Window<'_> {
790812 self . state . deferred_tasks . borrow_mut ( ) . push_back ( task) ;
791813 }
792814
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+ }
795821 }
796822
797823 #[ cfg( feature = "opengl" ) ]
0 commit comments