注:见以下修改后的员额:硬件镜像
我编写了两个Swift函数,用于切换OSX中的显示镜像。两者都能工作;它们之间的区别只是处理指针时的语法。为了方便那些有兴趣学习如何在Swift中切换镜像的人,我在下面包含了操场文件的文本。
我的问题是内存分配。以下是感兴趣的部分:
toggleMirroringUgly
// allocate space for array
let displayListPtr = displayIDListPtr.alloc(Int(displayCount)) //see typealias above
// fill the list
postError(CGGetActiveDisplayList(displayCount, displayListPtr, &activeCount))toggleMirroring
// allocate space for list of displays
var displayIDList = Array<CGDirectDisplayID>(count: Int(displayCount), repeatedValue: kCGNullDirectDisplay)
// fill the list
postError(CGGetActiveDisplayList(displayCount, &displayIDList, &activeCount))CGGetActiveDisplayList是一个低级函数调用,它依赖于将数据安排在连续的内存位置上。我有理由相信,丑陋版本中的“alloc”是连续的。从经验上看,“数组”(…)调用也是连续的,但我是否可以依赖于始终为真(例如,如果显示的数量增加)?这种假设是关于Swift数组初始化器糟糕的形式吗?
下面是所有的代码;对格式化问题表示歉意。请注意,应该只调用这两个函数中的一个;否则,您将结束您开始的位置。
//: Playground - noun: a place where people can play
import Cocoa
// apparently not defined in Swift version of SDK 10.11 (XCode 7.3.1), so add manually
let kCGNullDirectDisplay = CGDirectDisplayID(0)
let kCGDirectMainDisplay = CGMainDisplayID() // not used here, just for the record
let maxDisplays:UInt32 = 20 // not used
var onlineCount:UInt32 = 0 // not used
func postError(error : CGError){
if error != CGError.Success {
print("got an error")
}
}
// this toggles all active displays, online or not
func toggleMirroring(){
var displayCount:UInt32 = 0
var activeCount:UInt32 = 0
//var onlineCount:UInt32 = 0 //not used
//get count of active displays (by passing nil to CGGetActiveDisplayList
postError(CGGetActiveDisplayList(0, nil, &displayCount))
if displayCount < 2 { return } // no point in any mirroring functions
//***
// allocate space for list of displays
var displayIDList = Array<CGDirectDisplayID>(count: Int(displayCount), repeatedValue: kCGNullDirectDisplay)
// fill the list
postError(CGGetActiveDisplayList(displayCount, &displayIDList, &activeCount))
//***
// determine if mirroring is active
// hack to convert from boolean_t (aka UInt32) to swift's bool
let displaysMirrored = CGDisplayIsInMirrorSet(CGMainDisplayID()) != 0
// set master based on current mirroring state
// if mirroring, master = null, if not, master = main display
let master = (true == displaysMirrored) ? kCGNullDirectDisplay : CGMainDisplayID()
// start the configuration
var configRef:CGDisplayConfigRef = nil //swift 3 syntax
postError(CGBeginDisplayConfiguration(&configRef));
for i in 0..<Int(displayCount) {
let currentDisplay = CGDirectDisplayID(displayIDList[i])
if CGMainDisplayID() != currentDisplay {
CGConfigureDisplayMirrorOfDisplay(configRef, currentDisplay, master);
}
}
if (false){ // change to true in order to execute the toggle
postError(CGCompleteDisplayConfiguration (configRef,CGConfigureOption.Permanently))
}
// The first entry in the list of active displays is the main display. In case of mirroring, the first entry is the largest drawable display or, if all are the same size, the display with the greatest pixel depth.
// The "Permanently" option might not survive reboot when run from playground, but does when run in an application
}
func toggleMirroringUgly(){
// just to decrease eye strain
typealias displayIDListPtr = UnsafeMutablePointer<CGDirectDisplayID>
typealias configurationRefPtr = UnsafeMutablePointer<CGDisplayConfigRef>
//get count of active displays (by passing nil to CGGetActiveDisplayList
postError(CGGetActiveDisplayList(0, nil, &displayCount))
if displayCount < 2 { return } // no point in any mirroring functions
// ***
// allocate space for array
let displayListPtr = displayIDListPtr.alloc(Int(displayCount)) //see typealias above
// fill the list
postError(CGGetActiveDisplayList(displayCount, displayListPtr, &activeCount))
// ***
// determine if mirroring is active
// hack to convert from boolean_t (aka UInt32) to swift's bool
let displaysMirrored = CGDisplayIsInMirrorSet(CGMainDisplayID()) != 0
// set master based on current mirroring state
// if mirroring master = null, if not, master = main display
let master = (true == displaysMirrored) ? kCGNullDirectDisplay : CGMainDisplayID()
// make room for the configuration reference
let configRefPtr = configurationRefPtr.alloc(1) //see typealias above
// start the configuration
postError(CGBeginDisplayConfiguration (configRefPtr));
for i in 0..<displayCount {
let currentDisplay = CGDirectDisplayID(displayListPtr[Int(i)])
if CGMainDisplayID() != currentDisplay {
CGConfigureDisplayMirrorOfDisplay(configRefPtr[0], currentDisplay, master);
}
}
if (false){ //change to true in order to flip the mirroring
// make it happen
postError(CGCompleteDisplayConfiguration (configRefPtr[0],CGConfigureOption.Permanently));
}
// The first entry in the list of active displays is the main display. In case of mirroring, the first entry is the largest drawable display or, if all are the same size, the display with the greatest pixel depth.
// The "Permanently" option might not survive reboot when run from playground, but does when run in an application
}
toggleMirroring()发布于 2017-01-11 08:29:42
我用新的显卡和NVIDIA驱动程序升级了我的电脑,发现上面的代码不再完全工作--打开镜像,但不关闭。显然,驱动程序可以选择使用硬件或软件镜像,这会改变编码。我在下面贴出一份修订本。
它只在我的系统(10.12.2)和卡(GTX980Ti)上进行过测试,但我认为逻辑也应该适应软件镜像和最近的操作系统版本。如果您有两个以上的显示,您可能可以修改它,通过英勇的努力,以反映任意组合。我的代码只会镜像所有其他的主显示器(或软件镜像中的最低的rez显示器)。
尽管jbandes的备注re: ContiguousArray是信息丰富的,但在这种情况下它不起作用-参见代码中的注释。此代码假定分配的UInt32s数组将是连续的。(对malloc和铸件来说,工作量太大了,但这还没有准备好生产。)
祝两位感兴趣的人好运!
//: Playground - noun: a place where people can play
import Cocoa
import Foundation
func postError(_ error : CGError){
if error != CGError.success {
print("got an error")
}
}
func disableHardwareMirroring(){
// designed for hardware mirroring with > 1 display
// should be no penalty for running with only 1 display, using either hardware or software mirroring drivers
// but not tested
// start the configuration
var configRef:CGDisplayConfigRef? = nil
postError(CGBeginDisplayConfiguration(&configRef))
// only interested in the main display
// kCGNullDirectDisplay parameter disables hardware mirroring
CGConfigureDisplayMirrorOfDisplay(configRef, CGMainDisplayID(), kCGNullDirectDisplay)
// may not be permanent between boots using Playgroud, but is in an application
postError(CGCompleteDisplayConfiguration (configRef,CGConfigureOption.permanently))
}
func toggleMirroring(){
var displayCount:UInt32 = 0
var activeCount:UInt32 = 0 //used as a parameter, but value is ignored
//var onlineCount:UInt32 = 0 //not used
//get count of active displays (by passing nil to CGGetActiveDisplayList
postError(CGGetActiveDisplayList(0, nil, &displayCount))
if displayCount == 1 {
// either it's hardware mirroring or who cares?
disableHardwareMirroring()
return
}
// allocate space for list of displays
// tried to use ContiguousArray, but CGGetActiveDisplayList requires Array<CGDirectDisplayID> parameter
// ContiguousArrays cannot be typecast to Arrays (at least not easily)
var displayIDList = Array<CGDirectDisplayID>(repeating: kCGNullDirectDisplay, count: Int(displayCount))
// fill the list
postError(CGGetActiveDisplayList(displayCount, &(displayIDList), &activeCount))
// determine if mirroring is active (only relevant for software mirroring)
// hack to convert from boolean_t (aka UInt32) to swift's bool
let displaysMirrored = CGDisplayIsInMirrorSet(CGMainDisplayID()) != 0
// set master based on current mirroring state
// if mirroring, master = null, if not, master = main display
let master = (true == displaysMirrored) ? kCGNullDirectDisplay : CGMainDisplayID()
// start the configuration
var configRef:CGDisplayConfigRef? = nil
postError(CGBeginDisplayConfiguration(&configRef))
for i in 0..<Int(displayCount) {
let currentDisplay = CGDirectDisplayID(displayIDList[i])
if CGMainDisplayID() != currentDisplay {
CGConfigureDisplayMirrorOfDisplay(configRef, currentDisplay, master)
}
}
postError(CGCompleteDisplayConfiguration (configRef,CGConfigureOption.permanently))
// The first entry in the list of active displays is the main display. In case of mirroring, the first entry is the largest drawable display or, if all are the same size, the display with the greatest pixel depth.
// The "Permanently" option might not survive reboot when run from playground, but does when run in an application
}
if (false) { // change to true to run the code, false to edit
toggleMirroring()
}发布于 2016-06-08 00:10:14
数组不一定使用连续存储。有一个ContiguousArray类型,如果您有此倾向,您可以使用它,但是您仍然需要处理对CGGetActiveDisplayList的最后调用后返回的最大大小和实际大小之间的可能差异。
清除这种情况的一种方法可能是为Array定制一个方便的初始化程序:
extension Array {
init<Size: IntegerType>(
fillingBufferOfSize maxSize: Size,
@noescape fillBuffer: (buffer: UnsafeMutablePointer<Element>, count: inout Size) throws -> ()) rethrows
{
let maxSizeAsInt = Int(maxSize.toIntMax())
let buf = UnsafeMutablePointer<Element>.alloc(maxSizeAsInt)
defer { buf.dealloc(maxSizeAsInt) }
var actualCount: Size = 0
try fillBuffer(buffer: buf, count: &actualCount)
self.init(UnsafeBufferPointer(start: buf, count: Int(actualCount.toIntMax())))
}
}那么您可以使用Array(fillingBufferOfSize: ...)
var maxActive: UInt32 = 0
CGGetActiveDisplayList(0, nil, &maxActive)
let displays = Array(fillingBufferOfSize: maxActive) { (buffer, count) in
CGGetActiveDisplayList(maxActive, buffer, &count)
}https://stackoverflow.com/questions/37690426
复制相似问题