diff --git a/components/ideintf/idehelpintf.pas b/components/ideintf/idehelpintf.pas index 183c9d6e63..046ee29b5d 100644 --- a/components/ideintf/idehelpintf.pas +++ b/components/ideintf/idehelpintf.pas @@ -405,6 +405,9 @@ function THintWindowManager.ShowHint(ScreenPos: TPoint; TheHint: string; if NewHeight <= 0 then NewHeight := 200; + {$IFDEF LCLCOCOA} + dec(ScreenPos.Y); + {$ENDIF} HintRenderWindow.HintRectAdjust := Rect(0, 0, NewWidth, NewHeight); if MouseOffset then HintRenderWindow.OffsetHintRect(ScreenPos) diff --git a/lcl/interfaces/cocoa/cocoaint.pas b/lcl/interfaces/cocoa/cocoaint.pas index 2d07571578..646d9a1a8e 100644 --- a/lcl/interfaces/cocoa/cocoaint.pas +++ b/lcl/interfaces/cocoa/cocoaint.pas @@ -257,7 +257,7 @@ function CocoaPromptUser(const DialogCaption, DialogMessage: String; EscapeResult: Longint; sheetOfWindow: NSWindow = nil; modalSheet: Boolean = false): Longint; -function GetCocoaWindowAtPos(p: NSPoint): TCocoaWindow; +function GetCocoaWindowAtPos(p: NSPoint): NSWindow; // The function tries to initialize the proper application class. // The desired application class can be specified in info.plit @@ -520,7 +520,7 @@ end; // 3. in current App // 4. is visible window // 5. is not the misc window like Menu Bar -function GetCocoaWindowAtPos(p: NSPoint): TCocoaWindow; +function GetCocoaWindowAtPos(p: NSPoint): NSWindow; var windowNumber: NSInteger; windowNumbers: NSArray; @@ -538,14 +538,13 @@ begin // ensure 5 window := NSApp.windowWithWindowNumber(windowNumber); - if Assigned(window) and window.isKindOfClass(TCocoaWindow) then - Result := TCocoaWindow(window); + if Assigned(window) and (window.isKindOfClass(TCocoaWindow) or window.isKindOfClass(TCocoaPanel)) then + Result := window; end; procedure ForwardMouseMove(app: NSApplication; theEvent: NSEvent); var w : NSWindow; - kw : NSWindow; ev : NSEvent; p : NSPoint; wfr : NSRect; @@ -553,13 +552,13 @@ begin if not app.isActive then exit; - kw := app.keyWindow; p := theEvent.mouseLocation; + w := GetCocoaWindowAtPos(p);; - if Assigned(kw) then + if Assigned(w) then begin - wfr := kw.contentRectForFrameRect(kw.frame); - // if mouse outside of ClientFrame of keyWindow, + wfr := w.contentRectForFrameRect(w.frame); + // if mouse outside of ClientFrame of Window, // Cursor should be forced to default. // see also: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40515 if not NSPointInRect(p, wfr) then @@ -571,9 +570,8 @@ begin end; end; - w := GetCocoaWindowAtPos(p); - if (not Assigned(w)) or (w=kw) then - exit; + if (not Assigned(w)) or (not Assigned(theEvent.window)) or (w=theEvent.window) then + Exit; p.x := p.x - w.frame.origin.x; p.y := p.y - w.frame.origin.y; diff --git a/lcl/interfaces/cocoa/cocoautils.pas b/lcl/interfaces/cocoa/cocoautils.pas index cd745aa6fe..e5610161c5 100644 --- a/lcl/interfaces/cocoa/cocoautils.pas +++ b/lcl/interfaces/cocoa/cocoautils.pas @@ -42,6 +42,8 @@ function NSRectToRect(const NS: NSRect): TRect; procedure NSToLCLRect(const ns: NSRect; ParentHeight: Single; out lcl: TRect); procedure LCLToNSRect(const lcl: TRect; ParentHeight: Single; out ns: NSRect); +function GetScreenPointFromEvent(const event: NSEvent): NSPoint; + function ScreenPointFromLCLToNS(const lclPoint: TPoint): NSPoint; function ScreenPointFromNSToLCL(const cocoaPoint: NSPoint): TPoint; function ScreenRectFromLCLToNS(const lclRect: TRect): NSRect; @@ -752,6 +754,19 @@ begin ns.size.height:=lcl.Bottom-lcl.Top; end; +function GetScreenPointFromEvent(const event: NSEvent): NSPoint; +var + rect: NSRect; +begin + Result:= event.locationInWindow; + if not Assigned(event.window) then + Exit; + rect.origin:= Result; + rect.size:= NSZeroSize; + rect:= event.window.convertRectToScreen( rect ); + Result:= rect.origin; +end; + function ScreenPointFromLCLToNS(const lclPoint: TPoint): NSPoint; begin Result.x:= lclPoint.x; diff --git a/lcl/interfaces/cocoa/cocoawindows.pas b/lcl/interfaces/cocoa/cocoawindows.pas index 3f881f7649..c31a473b29 100644 --- a/lcl/interfaces/cocoa/cocoawindows.pas +++ b/lcl/interfaces/cocoa/cocoawindows.pas @@ -91,10 +91,7 @@ type procedure windowDidMove(notification: NSNotification); message 'windowDidMove:'; public callback: IWindowCallback; - function acceptsFirstResponder: LCLObjCBoolean; override; function canBecomeKeyWindow: LCLObjCBoolean; override; - function becomeFirstResponder: LCLObjCBoolean; override; - function resignFirstResponder: LCLObjCBoolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; // mouse @@ -579,28 +576,9 @@ begin callback.Move; end; -function TCocoaPanel.acceptsFirstResponder: LCLObjCBoolean; -begin - Result := True; -end; - function TCocoaPanel.canBecomeKeyWindow: LCLObjCBoolean; begin - Result := Assigned(callback) and callback.CanActivate; -end; - -function TCocoaPanel.becomeFirstResponder: LCLObjCBoolean; -begin - Result := inherited becomeFirstResponder; -// if Assigned(callback) then -// callback.BecomeFirstResponder; -end; - -function TCocoaPanel.resignFirstResponder: LCLObjCBoolean; -begin - Result := inherited resignFirstResponder; -// if Assigned(callback) then -// callback.ResignFirstResponder; + Result := false; end; function TCocoaPanel.lclGetCallback: ICommonCallback; diff --git a/lcl/interfaces/cocoa/cocoawscommon.pas b/lcl/interfaces/cocoa/cocoawscommon.pas index 993e9b721e..200b8a5c63 100644 --- a/lcl/interfaces/cocoa/cocoawscommon.pas +++ b/lcl/interfaces/cocoa/cocoawscommon.pas @@ -1109,14 +1109,13 @@ var MouseTargetLookup: Boolean; srchPt: TPoint; begin + Result:= true; + if not NSApp.isActive then exit; if Assigned(Owner) and not NSObjectIsLCLEnabled(Owner) then - begin - Result := True; // Cocoa should not handle the message. - Exit; // LCL should get the notification either. - end; + exit; // LCL should get the notification either. // If LCL control is provided and it's in designing state. // The default resolution: Notify LCL about event, but don't let Cocoa @@ -1144,6 +1143,9 @@ begin end else begin + if Event.window<>GetCocoaWindowAtPos(GetScreenPointFromEvent(Event)) then + exit( true ); + rect:=Target.BoundsRect; OffsetRect(rect, -rect.Left, -rect.Top); if (event.type_ = NSMouseMoved) and (not Types.PtInRect(rect, bndPt)) then @@ -1203,8 +1205,9 @@ begin //debugln('MouseMove x='+dbgs(MousePos.X)+' y='+dbgs(MousePos.Y)+' Target='+Target.Name); NotifyApplicationUserInput(Target, Msg.Msg); - Result := DeliverMessage(Msg) <> 0; - if BlockCocoaMouseMove then Result := true; + // LCL/LM_MOUSEMOVE always return false, so we should discard return value + DeliverMessage(Msg); + Result:= true; // if Screen.Cursor set, LCL won't call TCocoaWSWinControl.SetCursor(). // we need to set the cursor ourselves @@ -1805,14 +1808,14 @@ begin if Screen.Cursor<>crDefault then exit; - // control cursor only should be set when mouse in the keyWindow. + // control cursor only should be set when mouse in the keyWindow or hintWindow. // 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 + if (topParent is TCustomForm) and not (topParent is THintWindow) then begin if NSView(TCustomForm(topParent).handle).window <> NSApp.keyWindow then exit;