Skip to content

Instantly share code, notes, and snippets.

@CanTheAlmighty
Last active May 24, 2025 06:45
Show Gist options
  • Select an option

  • Save CanTheAlmighty/ee76fbf701a61651fe439fcd6d25f41d to your computer and use it in GitHub Desktop.

Select an option

Save CanTheAlmighty/ee76fbf701a61651fe439fcd6d25f41d to your computer and use it in GitHub Desktop.

Revisions

  1. CanTheAlmighty revised this gist Aug 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion DisplayLink.swift
    Original file line number Diff line number Diff line change
    @@ -18,7 +18,7 @@ class DisplayLink

    var callback : Optional<() -> ()> = nil

    var running : Bool { return !source.isCancelled }
    var running : Bool { return CVDisplayLinkIsRunning(timer) }

    /**
    Creates a new DisplayLink that gets executed on the given queue
  2. CanTheAlmighty created this gist Aug 19, 2016.
    114 changes: 114 additions & 0 deletions DisplayLink.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,114 @@
    //
    // DisplayLink.swift
    // MetalMac
    //
    // Created by Jose Canepa on 8/18/16.
    // Copyright © 2016 Jose Canepa. All rights reserved.
    //

    import AppKit

    /**
    Analog to the CADisplayLink in iOS.
    */
    class DisplayLink
    {
    let timer : CVDisplayLink
    let source : DispatchSourceUserDataAdd

    var callback : Optional<() -> ()> = nil

    var running : Bool { return !source.isCancelled }

    /**
    Creates a new DisplayLink that gets executed on the given queue

    - Parameters:
    - queue: Queue which will receive the callback calls
    */
    init?(onQueue queue: DispatchQueue = DispatchQueue.main)
    {
    // Source
    source = DispatchSource.makeUserDataAddSource(queue: queue)

    // Timer
    var timerRef : CVDisplayLink? = nil

    // Create timer
    var successLink = CVDisplayLinkCreateWithActiveCGDisplays(&timerRef)

    if let timer = timerRef
    {
    // Set Output
    successLink = CVDisplayLinkSetOutputCallback(timer,
    {
    (timer : CVDisplayLink, currentTime : UnsafePointer<CVTimeStamp>, outputTime : UnsafePointer<CVTimeStamp>, _ : CVOptionFlags, _ : UnsafeMutablePointer<CVOptionFlags>, sourceUnsafeRaw : UnsafeMutableRawPointer?) -> CVReturn in

    // Un-opaque the source
    if let sourceUnsafeRaw = sourceUnsafeRaw
    {
    // Update the value of the source, thus, triggering a handle call on the timer
    let sourceUnmanaged = Unmanaged<DispatchSourceUserDataAdd>.fromOpaque(sourceUnsafeRaw)
    sourceUnmanaged.takeUnretainedValue().add(data: 1)
    }

    return kCVReturnSuccess

    }, Unmanaged.passUnretained(source).toOpaque())

    guard successLink == kCVReturnSuccess else
    {
    NSLog("Failed to create timer with active display")
    return nil
    }

    // Connect to display
    successLink = CVDisplayLinkSetCurrentCGDisplay(timer, CGMainDisplayID())

    guard successLink == kCVReturnSuccess else
    {
    NSLog("Failed to connect to display")
    return nil
    }

    self.timer = timer
    }
    else
    {
    NSLog("Failed to create timer with active display")
    return nil
    }

    // Timer setup
    source.setEventHandler(handler:
    {
    [weak self] in self?.callback?()
    })
    }

    /// Starts the timer
    func start()
    {
    guard !running else { return }

    CVDisplayLinkStart(timer)
    source.resume()
    }

    /// Cancels the timer, can be restarted aftewards
    func cancel()
    {
    guard running else { return }

    CVDisplayLinkStop(timer)
    source.cancel()
    }

    deinit
    {
    if running
    {
    cancel()
    }
    }
    }