Last active
November 8, 2022 23:34
-
-
Save matthewreagan/2f3a30b8b229e9e2aa7c to your computer and use it in GitHub Desktop.
Topmost window via CGWindow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NSWindow *topmostAppWindowAtPoint(CGPoint screenPoint) | |
{ | |
const CGWindowLevel kScreensaverWindowLevel = CGWindowLevelForKey(kCGScreenSaverWindowLevelKey); | |
/* This function returns a pointer to the app's topmost NSWindow that | |
the point `screenPoint` is over. The important distinction here is that | |
this function takes _all_ system windows into consideration and will return | |
`nil` if there is a system window (or NSMenu etc.) that the cursor | |
is over which is atop the app window, which is information that | |
can't otherwise be gleaned by checking against `[NSApp orderedWindows]` etc. | |
This is useful in cases where you need to know e.g. what window the cursor is | |
*really* over, whether it is a window in your app, or a menu in the menubar, etc. | |
*/ | |
pid_t appPID = [[NSRunningApplication currentApplication] processIdentifier]; | |
NSWindow *appWindow = nil; | |
CFArrayRef windowArray = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID); | |
CFIndex windowCount = 0; | |
NSRect mainScreenRect = NSScreen.mainScreen.frame; | |
float mainScreenHeight = mainScreenRect.size.height; | |
/* Flip the screen coord point Y here to match what the CGWindow expects */ | |
screenPoint.y = mainScreenHeight - screenPoint.y; | |
if ((windowCount = CFArrayGetCount(windowArray))) | |
{ | |
for (CFIndex i = 0; i < windowCount; i++) | |
{ | |
NSDictionary *windowInfoDictionary = (__bridge NSDictionary *)((CFDictionaryRef)CFArrayGetValueAtIndex(windowArray, i)); | |
NSNumber *ownerPID = (NSNumber *)(windowInfoDictionary[(id)kCGWindowOwnerPID]); | |
NSNumber *level = (NSNumber *)(windowInfoDictionary[(id)kCGWindowLayer]); | |
if (ownerPID.intValue == appPID) | |
{ | |
/* We are concerned with menus or application windows etc., anything | |
at or above screensaver level (1000) we just assume is something special | |
that we should ignore, and skip it. */ | |
if (level.integerValue < kScreensaverWindowLevel) | |
{ | |
CGRect rect = NSZeroRect; | |
CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)(windowInfoDictionary[(id)kCGWindowBounds]), &rect); | |
if (CGRectContainsPoint(rect, screenPoint)) | |
{ | |
NSNumber *windowID = windowInfoDictionary[(id)kCGWindowNumber]; | |
appWindow = [NSApp windowWithWindowNumber:windowID.integerValue]; | |
break; | |
} | |
} | |
} | |
} | |
} | |
CFRelease(windowArray); | |
return appWindow; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My bad. Thanks.