插入新显示器时,NSScreen 不更新显示器计数

问题描述 投票:0回答:2

我发现即使插入额外的显示器后,NSScreen 也会返回相同数量的显示器。

制作了一个可以复制问题的简单测试应用程序。基本上无限循环并打印 NSScreen 计数和 CGDisplay 计数。

  1. 启动应用程序
  2. 打印“NSScreen = 1 CGDisplay = 1”
  3. 在不停止应用程序的情况下,插入额外的显示器
  4. 打印“NSScreen = 1 CGDisplay = 2”

但是代码应该打印“NSScreen = 2 CGDisplay = 2”

在 OS X 11 上,插入附加显示器后,我们会看到同样的问题(NSScreen = 1 CGDisplay = 2)。

测试代码在这里:

主.cpp

#include <iostream>
#include "macScreen.h"
int main(int argc, const char * argv[]) {
  getNSScreenCoordinates();
  return 0;
}

macScreen.h

#ifndef macScreen_h
#define macScreen_h
float getNSScreenCoordinates();
#endif /* macScreen_h */

macScreen.mm

#import <Foundation/Foundation.h>
#include <iostream>
#include <Cocoa/Cocoa.h>
#import <AppKit/NSScreen.h>
#define MAX_NUM_DISPLAYS 255
float getNSScreenCoordinates() {

  NSArray<NSScreen *> *arr = [NSScreen screens];
  NSUInteger numScreens = [arr count];

  CGDirectDisplayID displays[MAX_NUM_DISPLAYS];
  CGDisplayCount displayCount;
  CGGetOnlineDisplayList(MAX_NUM_DISPLAYS, displays, &displayCount);
  
  while(1) {
    std::cout << "cg num displays " << displayCount << "\n";
    std::cout << "numscreens " << numScreens << "\n";

    arr = [NSScreen screens];
    numScreens = [arr count];

    CGGetOnlineDisplayList(MAX_NUM_DISPLAYS, displays, &displayCount);
    
  }
  return 1;
}
c++ objective-c xcode macos retina-display
2个回答
2
投票

在 macOS 11.6 (Big Sur) 上的测试中,您需要做两件事才能让

[NSScreen screens]
进行更新:

  • 您需要确保单例
    NSApplication.shared
    对象存在。
  • 您需要运行主程序
    NSRunLoop

这是一个有效的示例(在 Swift 中):

import Cocoa
import Combine

// Ensure the singleton NSApplication exists.
_ = NSApplication.shared

// Arrange to print the number of screens once per second,
// while the main RunLoop is running.
let ticket = Timer.publish(every: 1, on: .main, in: .common)
    .autoconnect()
    .sink { _ in
        print("screen count = \(NSScreen.screens.count)")
    }

// Run the main RunLoop forever.
RunLoop.main.run()

// Ensure that the Timer isn't cancelled prematurely.
ticket.cancel()

但是如果你注释掉

NSApplication.shared
行,它就不再起作用了。如果将
RunLoop
的使用替换为从不调用
while
RunLoop
循环,它也不再起作用。例如,以下内容不起作用

import Cocoa
import Combine

// Ensure the singleton NSApplication exists.
_ = NSApplication.shared

while true {
    // NEVER UPDATES
    print("screen count = \(NSScreen.screens.count)")
    sleep(1)
}

所以你真的应该尝试安排你的程序,以便

RunLoop.main
处于控制之中。但如果您确实需要拥有自己的主循环,则在检查
RunLoop.main
之前运行一次
NSScreen.screens
就足够了。这个版本有效:

import Cocoa
import Combine

// Ensure the singleton NSApplication exists.
_ = NSApplication.shared

while true {
    RunLoop.main.acceptInput(forMode: .default, before: .distantPast)
    print("screen count = \(NSScreen.screens.count)")
    sleep(1)
}

0
投票

根据 NSScreen 的文档,您需要在 NSApplication 实例中运行代码,以允许 NSScreen 连接到底层显示服务。在

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
内完成你的工作就足够了。

© www.soinside.com 2019 - 2024. All rights reserved.