2016-06-07 3 views
0

ПРИМЕЧАНИЕ: См исправленный пост ниже: Re: Оборудование зеркалированиеSwift «Array» распределение памяти, плюс переключатель зеркального отображения

Я написал две 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» из уродливой версии смежна. Эмпирически кажется, что вызов «Array (...)» также смежный, но могу ли я полагаться на то, что всегда истинно (например, если число дисплеев растет)? Это предположение о неправильной форме инициализатора массива 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() 

ответ

0

Я модернизировал свой компьютер с новой видеокартой и драйверы NVIDIA и обнаружили, что мой код больше не работает полностью - зеркальное отображение, но не выключено. По-видимому, есть возможность для драйверов использовать зеркальное отображение аппаратного или программного обеспечения, и это изменяет кодировку. Я публикую ниже пересмотренную версию.

Он был протестирован только на моей системе (10.12.2) и на карте (GTX 980Ti), но я думаю, что логика должна учитывать зеркалирование программного обеспечения и довольно недавние версии ОС. Если у вас более двух дисплеев, вы можете, возможно, изменить его с героическим усилием, чтобы отразить произвольные комбинации. Мой код будет просто отражать все, что считается основным дисплеем (или самым низким значением в зеркалировании программного обеспечения) для всех остальных.

Хотя примечание jbandes re: ContiguousArray было информативным, в этом случае оно не работает - см. Комментарии в коде. Этот код предполагает, что выделенный массив UInt32s будет смежным. (Слишком много работы, чтобы получить представление о malloc и литье, но это не готово к производству.)

Удачи вам 2 людям, которые могут быть вам интересны!

//: 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() 
} 
1

Массивы не обязательно используют непрерывное хранение. Существует тип ContiguousArray, который вы можете использовать, если вы так склонны, но вам все равно придется иметь дело с возможной разницей между вашим максимальным размером и фактическим размером, полученным после окончательного звонка, до CGGetActiveDisplayList.

Один из способов очистки этого вверх может быть, чтобы сделать заказ удобство инициализатор для массива:

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) 
} 
+0

Большое спасибо за понимание!Я ценю, как вы 1) ответили на вопрос, с полезной ссылкой на тип «ContiguousArray» и 2) обобщили решение, которое я признаю, что не понимаю полностью. Для CGGetActiveDisplayList меня не так беспокоит, что количество активных дисплеев изменится в nsec между первым вызовом и вторым, но CGGetActiveDisplayList будет записывать в неправильно распределенную память. Действительно, код не использует activeCount, возвращенный вторым вызовом. – MDF

+0

Действительно, для этого может быть нередко меняться между вызовами, но если мое чтение API верное, возможно, это возможно. Конкретное обобщение, которое я предлагаю, может оказаться неправильным для вас, но я считаю, что обычно полезно обертывать громоздкие API с помощью какой-либо вспомогательной функции или расширения. Возможно, вы могли бы попробовать создать одну функцию, задача которой - вернуть список идентификаторов отображения. (Вы также можете обсудить настройки API в списке рассылки быстрой эволюции - наложения API - это [open-source] (https://github.com/apple/swift/blob/master/stdlib/public/SDK/CoreGraphics/CoreGraphics .swift).) – jtbandes

 Смежные вопросы

  • Нет связанных вопросов^_^