Cocoa: TCocoaWidgetSet.MonitorFromPoint() implemented

This commit is contained in:
rich2014 2023-10-21 00:31:59 +08:00
parent 6121304a85
commit 275776771b
3 changed files with 62 additions and 24 deletions

View File

@ -42,6 +42,10 @@ 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 IndexToHMonitor(i: NSUInteger): HMonitor;
function HMonitorToIndex(h: HMonitor): NSUInteger;
function getScreenFromHMonitor(h: HMonitor): NSScreen;
function NSPrimaryScreen: NSScreen;
function NSPrimaryScreenFrame: NSRect;
function NSGlobalScreenFrame: NSRect;
@ -755,6 +759,36 @@ begin
ns.size.height:=lcl.Bottom-lcl.Top;
end;
// According to the documentation of NSScreen.screen It's recommended
// not to cache NSScreen objects stored in the array. As those might change.
// However, according to the same documentation, the objects can change
// only with a notificatio sent out. BUT while using a macincloud (remote desktop)
// services, it was identified that NSScreen object CAN change without any notification.
// So, instead of passing NSScreen as HMonitor, only INDEX+1 in NSScreen.screen
// is used.
function IndexToHMonitor(i: NSUInteger): HMonitor;
begin
if i = NSIntegerMax then Result := 0
else Result := i + 1;
end;
function HMonitorToIndex(h: HMonitor): NSUInteger;
begin
if h = 0 then Result := NSIntegerMax
else Result := NSUInteger(h)-1;
end;
function getScreenFromHMonitor(h: HMonitor): NSScreen;
var
index: NSUInteger;
begin
Result:= nil;
index:= HMonitorToIndex( h );
if index>=NSScreen.screens.count then
Exit;
Result:= NSScreen( NSScreen.screens.objectAtIndex(index) );
end;
// primary display
function NSPrimaryScreen: NSScreen;
begin

View File

@ -740,25 +740,6 @@ begin
end;
end;
// According to the documentation of NSScreen.screen It's recommended
// not to cache NSScreen objects stored in the array. As those might change.
// However, according to the same documentation, the objects can change
// only with a notificatio sent out. BUT while using a macincloud (remote desktop)
// services, it was identified that NSScreen object CAN change without any notification.
// So, instead of passing NSScreen as HMonitor, only INDEX+1 in NSScreen.screen
// is used.
function IndexToHMonitor(i: NSUInteger): HMonitor;
begin
if i = NSIntegerMax then Result := 0
else Result := i + 1;
end;
function HMonitorToIndex(h: HMonitor): NSUInteger;
begin
if h = 0 then Result := NSIntegerMax
else Result := NSUInteger(h)-1;
end;
function TCocoaWidgetSet.EnumDisplayMonitors(hdc: HDC; lprcClip: PRect;
lpfnEnum: MonitorEnumProc; dwData: LPARAM): LongBool;
var
@ -1174,21 +1155,19 @@ function TCocoaWidgetSet.GetMonitorInfo(hMonitor: HMONITOR; lpmi: PMonitorInfo):
var
globalScreenHeight: CGFloat;
ScreenID: NSScreen;
idx : NSUInteger;
begin
Result := (lpmi <> nil) and (lpmi^.cbSize >= SizeOf(TMonitorInfo));
if not Result then Exit;
idx := HMonitorToIndex(hMonitor);
Result := (idx < NSScreen.screens.count);
ScreenID := getScreenFromHMonitor( hMonitor );
Result := Assigned(ScreenID);
if not Result then Exit;
globalScreenHeight := NSGlobalScreenHeight;
ScreenID := NSScreen(NSScreen.screens.objectAtIndex(idx));
NSToLCLRect(ScreenID.frame, globalScreenHeight, lpmi^.rcMonitor);
NSToLCLRect(ScreenID.visibleFrame, globalScreenHeight, lpmi^.rcWork);
// according to the documentation the primary (0,0 coord screen)
// is always and index 0
if idx = 0 then
if HMonitorToIndex(hMonitor) = 0 then
lpmi^.dwFlags := MONITORINFOF_PRIMARY
else
lpmi^.dwFlags := 0;
@ -1893,6 +1872,29 @@ begin
Result := CocoaRegionTypeToWin32Map[TCocoaRegion(RGN).GetType];
end;
function TCocoaWidgetSet.MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWord): HMONITOR;
var
point: NSPoint;
screen: NSScreen;
i: Integer;
begin
Result:= 0;
point:= LCLToNSPoint( ptScreenCoords, NSGlobalScreenHeight );
if point.y>=1 then // NSPointInRect is (upper,left) inside
point.y:= point.y-1; // (lower,right) outside
for i := 0 to NSScreen.screens.count - 1 do begin
screen:= NSScreen( NSScreen.screens.objectAtIndex(i) );
if NSPointInRect(point, screen.frame) then begin
Result:= IndexToHMonitor( i );
Exit;
end;
end;
if dwFlags<>MONITOR_DEFAULTTONULL then
Result:= IndexToHMonitor( 0 );
end;
function TCocoaWidgetSet.MoveToEx(DC: HDC; X, Y: Integer; OldPoint: PPoint): Boolean;
var
ctx: TCocoaContext;

View File

@ -140,6 +140,8 @@ function LPtoDP(DC: HDC; var Points; Count: Integer): BOOL; override;
function OffsetRgn(RGN: HRGN; nXOffset, nYOffset: Integer): Integer; override;
function MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWord): HMONITOR; override;
{function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: Cardinal): integer; override;}
function MoveToEx(DC: HDC; X, Y: Integer; OldPoint: PPoint): Boolean; override;