Post

Replies

Boosts

Views

Activity

kCGWindowListOptionOnScreenOnly wrong window order
I created an AX observer for kAXMainWindowChangedNotification. In the callback function I call CGWindowListCopyWindowInfo with kCGWindowListOptionOnScreenOnly option to get the id of the current main window (Windows are filtered by PID because I am only interested in the frontmost app). What I experienced is that the received window order reflects the previous state (before the window switch). If I delay the call of CGWindowListCopyWindowInfo with a few milliseconds then the order is perfect but it does not seem to be a stable solution. Is there any other way to wait until every API is notified about the changes then call CGWindowListCopyWindowInfo to get the most recent window information? Subscription: AXUIElementRef appElem = AXUIElementCreateApplication(processId.intValue); CFArrayRef windows; AXError copyResult = AXUIElementCopyAttributeValues(appElem, kAXWindowsAttribute, 0, 1, &windows); AXError createResult = AXObserverCreate(processId.intValue, windowSwitchedCallback, &observer);     if (copyResult != createResult != kAXErrorSuccess) {    return; }   AXObserverAddNotification(observer, appElem, kAXMainWindowChangedNotification, (__bridge void *)(self));   CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); Callback: void windowSwitchedCallback(AXObserverRef observer, AXUIElementRef element, CFStringRef notificationName, void *refCon) { if (CFStringCompare(notificationName, kAXMainWindowChangedNotification, 0) == kCFCompareEqualTo) {     NSTimeInterval delayInMSec = 10;     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInMSec * NSEC_PER_MSEC));     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){       NSDictionary *activeWindow = [(__bridge ActiveWindowObserver*)(refCon) getActiveWindow];       NSLog(@"%@ windowChanged",activeWindow);     });   } } ActiveWindowObserver: - (NSDictionary*) getActiveWindow {   CFArrayRef windowsRef = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);   NSArray *windowsArray = (NSArray *)CFBridgingRelease(windowsRef);   NSPredicate *pIdPredicate = [NSPredicate predicateWithFormat:@"kCGWindowOwnerPID == %@ && kCGWindowLayer == 0", processId];   NSArray *filteredWindows = [windowsArray filteredArrayUsingPredicate:pIdPredicate];   id activeWindow = filteredWindows.count > 0 ? filteredWindows.firstObject : nil;   return activeWindow; }
1
0
1.2k
Aug ’22