Cocoa/Cursor: fix #40515 and others, Merge branch 'cocoa/cursor'

This commit is contained in:
rich2014 2023-09-20 22:55:49 +08:00
parent 427111b63e
commit abdd01e9b9
5 changed files with 78 additions and 22 deletions

View File

@ -517,21 +517,47 @@ var
ev : NSEvent;
p : NSPoint;
wfr : NSRect;
windowNumbers : NSArray;
windowNumber : NSNumber;
begin
kw := app.keyWindow;
p := theEvent.mouseLocation;
if Assigned(kw) then
begin
wfr := kw.contentRectForFrameRect(kw.frame);
// if mouse outside of ClientFrame of keyWindow,
// Cursor should be forced to default.
// see also: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40515
if not NSPointInRect(p, wfr) then
begin
if Screen.Cursor=crDefault then
CursorHelper.ForceSetDefaultCursor
else
CursorHelper.SetScreenCursor;
end;
end;
// mouse move was consumed by the focused window
if Assigned(kw) and NSPointInRect( theEvent.mouseLocation, kw.frame) then
Exit;
if Assigned(kw) and NSPointInRect(p, kw.frame) then
exit;
for w in app.windows do
// windowNumbersWithOptions() shoulde be used here.
// because windowNumbersWithOptions() return windowsNumber of visible windows
// from front to back, and NSAPP.windows return all windows not ordered.
windowNumbers := NSWindow.windowNumbersWithOptions(0);
for windowNumber in windowNumbers do
begin
if w = kw then Continue;
if not w.isVisible then Continue;
// todo: check for enabled windows? modal windows?
w := app.windowWithWindowNumber(windowNumber.integerValue);
if not Assigned(w) then
continue;
wfr := w.frame;
if not NSPointInRect( theEvent.mouseLocation, wfr) then Continue;
if not NSPointInRect( theEvent.mouseLocation, wfr) then
continue;
if not w.isKindOfClass(TCocoaWindow) then
break;
p := theEvent.mouseLocation;
p.x := p.x - w.frame.origin.x;
@ -548,6 +574,7 @@ begin
theEvent.pressure
);
w.sendEvent(ev);
break;
end;
end;

View File

@ -2526,8 +2526,10 @@ end;
function TCocoaWidgetSet.SetCursor(ACursor: HCURSOR): HCURSOR;
begin
if ACursor = 0 then ACursor:= Screen.Cursors[crDefault];
TCocoaCursor(ACursor).SetCursor;
if (ACursor=0) or (ACursor=Screen.Cursors[crDefault]) then
CursorHelper.SetCursorAtMousePos
else
CursorHelper.SetNewCursor( TCocoaCursor(ACursor) );
Result := 0;
end;

View File

@ -1019,15 +1019,15 @@ begin
end;
// return proper focused responder by kind of class of NSResponder
function getProperFocusedResponder( const aResponder : NSResponder ): NSResponder;
function getProperFocusedResponder( const win : NSWindow; const aResponder : NSResponder ): NSResponder;
begin
if aResponder<>nil then
Result := aResponder
else
Result:= NSApp.keyWindow;
Result:= win;
if Result.isKindOfClass(NSWindow) then
Result:= TCocoaWindowContent(NSWindow(Result).contentView).documentView;
if Result.isKindOfClass(TCocoaWindow) then
Result:= TCocoaWindowContent(TCocoaWindow(Result).contentView).documentView;
end;
// return responder callback by kind of class of NSResponder
@ -1080,7 +1080,7 @@ begin
inc( makeFirstResponderCount );
try
lastResponder := self.firstResponder;
newResponder := getProperFocusedResponder( aResponder );
newResponder := getProperFocusedResponder( self, aResponder );
if lastResponder = newResponder then exit;
// do toggle Focused Control

View File

@ -24,11 +24,12 @@ type
_lastCursor: NSCursor;
public
procedure SetNewCursor( newCursor:TCocoaCursor );
procedure ForceSetDefaultCursor;
procedure SetCursorOnActive;
procedure SetScreenCursor;
procedure SetScreenCursorWhenNotDefault;
public
class procedure SetCursorOnActive;
class procedure SetCursorAtMousePos;
class procedure SetScreenCursor;
class procedure SetScreenCursorWhenNotDefault;
end;
{ TLCLCommonCallback }
@ -380,9 +381,18 @@ begin
end;
end;
class procedure TCursorHelper.SetCursorOnActive;
procedure TCursorHelper.ForceSetDefaultCursor;
var
newCursor: TCocoaCursor;
begin
CursorHelper._lastCursor:= nil;
newCursor:= TCocoaCursor(Screen.Cursors[crDefault]);
newCursor.SetCursor;
_lastCursor:= newCursor.Cursor;
end;
procedure TCursorHelper.SetCursorOnActive;
begin
_lastCursor:= NSCursor.arrowCursor;
if Screen.Cursor<>crDefault then
SetScreenCursor
else
@ -411,15 +421,16 @@ begin
rect.origin, 0, 0,
window.windowNumber, nil, 0, 0, 0);
window.lclGetCallback.MouseMove(event);
NSApp.postEvent_atStart(event, true);
end;
class procedure TCursorHelper.SetScreenCursor;
procedure TCursorHelper.SetScreenCursor;
begin
_lastCursor:= nil;
TCocoaCursor(Screen.Cursors[Screen.Cursor]).SetCursor;
end;
class procedure TCursorHelper.SetScreenCursorWhenNotDefault;
procedure TCursorHelper.SetScreenCursorWhenNotDefault;
begin
if Screen.Cursor<>crDefault then
SetScreenCursor;
@ -1887,6 +1898,7 @@ class procedure TCocoaWSWinControl.SetCursor(const AWinControl: TWinControl;
const ACursor: HCursor);
var
control: TControl;
topParent: TControl;
begin
//debugln('SetCursor '+AWinControl.name+' '+dbgs(ACursor));
@ -1894,6 +1906,19 @@ begin
if Screen.Cursor<>crDefault
then exit;
// control cursor only should be set when mouse in the keyWindow.
// for the MacOS system automatic restore cursor feature(also an issue),
// it is more appropriate to set the default cursor when the mouse is out
// of the keyWindow, which has been set in TLCLCommonCallback.MouseMove().
// the keyWindow here refers to the Client Frame, excluding TitleBar.
// see also: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40515
topParent:= AWinControl.GetTopParent;
if topParent is TCustomForm then
begin
if NSView(TCustomForm(topParent).handle).window <> NSApp.keyWindow then
exit;
end;
// control cursor only need be set when mouse in AWinControl.
// suppose there is a Button, which is to set a Cursor of a ListBox.
// without the code here, it will be set to the Cursor of the ListBox

View File

@ -793,6 +793,8 @@ begin
// events to arrive for this window, creating a second call to TCocoaWSCustomForm.CreateHandle
// while the first didn't finish yet, instead delay the call
cnt.popup_parent := AParams.WndParent;
win.makeFirstResponder(doc);
end
else
begin