Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/menuadvanced.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .github/menudisplay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .github/menugeneral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .github/menukeys.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed .github/menulet-outdated.png
Binary file not shown.
Binary file modified .github/menulet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ disabled_rules:
- function_body_length
- identifier_name
- trailing_comma
excluded:
- Carthage
type_body_length: 500
file_length: 500
cyclomatic_complexity:
ignores_case_statements: true
ignores_case_statements: true
opening_brace:
allow_multiline_func: true
4 changes: 0 additions & 4 deletions Cartfile

This file was deleted.

4 changes: 0 additions & 4 deletions Cartfile.resolved

This file was deleted.

243 changes: 147 additions & 96 deletions MonitorControl.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1250"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
75 changes: 34 additions & 41 deletions MonitorControl/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
import AMCoreAudio
import Cocoa
import DDC
import Foundation
import MASPreferences
import MediaKeyTap
import os.log
import Preferences
import SimplyCoreAudio

var app: AppDelegate!
let prefs = UserDefaults.standard

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet var statusMenu: NSMenu!
@IBOutlet var window: NSWindow!

let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

var monitorItems: [NSMenuItem] = []

var mediaKeyTap: MediaKeyTap?
var prefsController: NSWindowController?
var keyRepeatTimers: [MediaKey: Timer] = [:]

let coreAudio = SimplyCoreAudio()
var accessibilityObserver: NSObjectProtocol!

lazy var preferencesWindowController: PreferencesWindowController = {
let storyboard = NSStoryboard(name: "Main", bundle: Bundle.main)
let mainPrefsVc = storyboard.instantiateController(withIdentifier: "MainPrefsVC") as? MainPrefsViewController
let keyPrefsVc = storyboard.instantiateController(withIdentifier: "KeysPrefsVC") as? KeysPrefsViewController
let displayPrefsVc = storyboard.instantiateController(withIdentifier: "DisplayPrefsVC") as? DisplayPrefsViewController
let advancedPrefsVc = storyboard.instantiateController(withIdentifier: "AdvancedPrefsVC") as? AdvancedPrefsViewController
return PreferencesWindowController(
preferencePanes: [
mainPrefsVc!,
keyPrefsVc!,
displayPrefsVc!,
advancedPrefsVc!,
],
animated: false // causes glitchy animations
)
}()

func applicationDidFinishLaunching(_: Notification) {
app = self
self.setupViewControllers()
self.subscribeEventListeners()
self.setDefaultPrefs()
self.updateMediaKeyTap()
Expand All @@ -41,12 +55,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
NSApplication.shared.terminate(self)
}

@IBAction func prefsClicked(_ sender: AnyObject) {
if let prefsController = prefsController {
prefsController.showWindow(sender)
NSApp.activate(ignoringOtherApps: true)
prefsController.window?.makeKeyAndOrderFront(sender)
}
@IBAction func prefsClicked(_: AnyObject) {
self.preferencesWindowController.show()
}

/// Set the default prefs of the app
Expand Down Expand Up @@ -151,30 +161,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
}

private func setupViewControllers() {
let storyboard: NSStoryboard = NSStoryboard(name: "Main", bundle: Bundle.main)
let mainPrefsVc = storyboard.instantiateController(withIdentifier: "MainPrefsVC")
let keyPrefsVc = storyboard.instantiateController(withIdentifier: "KeysPrefsVC")
let displayPrefsVc = storyboard.instantiateController(withIdentifier: "DisplayPrefsVC")
let advancedPrefsVc = storyboard.instantiateController(withIdentifier: "AdvancedPrefsVC")
let views = [
mainPrefsVc,
keyPrefsVc,
displayPrefsVc,
advancedPrefsVc,
]
prefsController = MASPreferencesWindowController(viewControllers: views, title: NSLocalizedString("Preferences", comment: "Shown in Preferences window"))
}

private func subscribeEventListeners() {
// subscribe KeyTap event listener
NotificationCenter.default.addObserver(self, selector: #selector(handleListenForChanged), name: .listenFor, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleShowContrastChanged), name: .showContrast, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleFriendlyNameChanged), name: .friendlyName, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handlePreferenceReset), name: .preferenceReset, object: nil)

// subscribe Audio output detector (AMCoreAudio)
AMCoreAudio.NotificationCenter.defaultCenter.subscribe(self, eventType: AudioHardwareEvent.self, dispatchQueue: DispatchQueue.main)
// subscribe Audio output detector (SimplyCoreAudio)
NotificationCenter.default.addObserver(self, selector: #selector(audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil)

// listen for accessibility status changes
_ = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in
Expand Down Expand Up @@ -322,29 +317,27 @@ extension AppDelegate: MediaKeyTapDelegate {
keys = [.brightnessUp, .brightnessDown, .mute, .volumeUp, .volumeDown]
}

if let audioDevice = AudioDevice.defaultOutputDevice(), audioDevice.canSetVirtualMasterVolume(direction: .playback) {
if self.coreAudio.defaultOutputDevice?.canSetVirtualMasterVolume(scope: .output) == true {
// Remove volume related keys.
let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute]
keys.removeAll { keysToDelete.contains($0) }
}

self.mediaKeyTap?.stop()
// returning an empty array listens for all mediakeys in MediaKeyTap
if keys.count > 0 {
self.mediaKeyTap = MediaKeyTap(delegate: self, for: keys, observeBuiltIn: true)
self.mediaKeyTap?.start()
}
}
}

extension AppDelegate: EventSubscriber {
/// Fires off when the default audio device changes.
func eventReceiver(_ event: Event) {
if case let .defaultOutputDeviceChanged(audioDevice)? = event as? AudioHardwareEvent {
#if DEBUG
os_log("Default output device changed to “%{public}@”.", type: .info, audioDevice.name)
os_log("Can device set its own volume? %{public}@", type: .info, audioDevice.canSetVirtualMasterVolume(direction: .playback).description)
#endif
self.updateMediaKeyTap()
}
@objc private func audioDeviceChanged() {
#if DEBUG
if let defaultDevice = self.coreAudio.defaultOutputDevice {
os_log("Default output device changed to “%{public}@”.", type: .info, defaultDevice.name)
os_log("Can device set its own volume? %{public}@", type: .info, defaultDevice.canSetVirtualMasterVolume(scope: .output).description)
}
#endif
self.updateMediaKeyTap()
}
}
8 changes: 4 additions & 4 deletions MonitorControl/Extensions/CGDirectDisplayID+Extension.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Cocoa

extension CGDirectDisplayID {
public var vendorNumber: UInt32? {
public extension CGDirectDisplayID {
var vendorNumber: UInt32? {
return CGDisplayVendorNumber(self)
}

public var modelNumber: UInt32? {
var modelNumber: UInt32? {
return CGDisplayModelNumber(self)
}

public var serialNumber: UInt32? {
var serialNumber: UInt32? {
return CGDisplaySerialNumber(self)
}
}
6 changes: 3 additions & 3 deletions MonitorControl/Extensions/EDID+Extension.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DDC

extension EDID {
public func displayName() -> String? {
public extension EDID {
func displayName() -> String? {
let descriptors = [self.descriptors.0, self.descriptors.1, self.descriptors.2, self.descriptors.3]

for descriptor in descriptors {
Expand All @@ -16,7 +16,7 @@ extension EDID {
return nil
}

public func serialNumber() -> String? {
func serialNumber() -> String? {
let descriptors = [self.descriptors.0, self.descriptors.1, self.descriptors.2, self.descriptors.3]

for descriptor in descriptors {
Expand Down
24 changes: 13 additions & 11 deletions MonitorControl/Extensions/NSScreen+Extension.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Cocoa

extension NSScreen {
public var displayID: CGDirectDisplayID {
public extension NSScreen {
var displayID: CGDirectDisplayID {
return (self.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? CGDirectDisplayID)!
}

public var vendorNumber: UInt32? {
var vendorNumber: UInt32? {
switch self.displayID.vendorNumber {
case 0xFFFF_FFFF:
return nil
Expand All @@ -14,7 +14,7 @@ extension NSScreen {
}
}

public var modelNumber: UInt32? {
var modelNumber: UInt32? {
switch self.displayID.modelNumber {
case 0xFFFF_FFFF:
return nil
Expand All @@ -23,7 +23,7 @@ extension NSScreen {
}
}

public var serialNumber: UInt32? {
var serialNumber: UInt32? {
switch self.displayID.serialNumber {
case 0x0000_0000:
return nil
Expand All @@ -32,7 +32,7 @@ extension NSScreen {
}
}

public var displayName: String? {
var displayName: String? {
var servicePortIterator = io_iterator_t()

let status = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"), &servicePortIterator)
Expand All @@ -48,10 +48,12 @@ extension NSScreen {
let dict = (IODisplayCreateInfoDictionary(object, UInt32(kIODisplayOnlyPreferredName)).takeRetainedValue() as NSDictionary as? [String: AnyObject])!

if dict[kDisplayVendorID] as? UInt32 == self.vendorNumber,
dict[kDisplayProductID] as? UInt32 == self.modelNumber,
dict[kDisplaySerialNumber] as? UInt32 == self.serialNumber {
dict[kDisplayProductID] as? UInt32 == self.modelNumber,
dict[kDisplaySerialNumber] as? UInt32 == self.serialNumber
{
if let productName = dict["DisplayProductName"] as? [String: String],
let firstKey = Array(productName.keys).first {
let firstKey = Array(productName.keys).first
{
return productName[firstKey]!
}
}
Expand All @@ -60,11 +62,11 @@ extension NSScreen {
return nil
}

public var isBuiltin: Bool {
var isBuiltin: Bool {
return CGDisplayIsBuiltin(self.displayID) != 0
}

public static func getByDisplayID(displayID: CGDirectDisplayID) -> NSScreen? {
static func getByDisplayID(displayID: CGDirectDisplayID) -> NSScreen? {
return NSScreen.screens.first { $0.displayID == displayID }
}
}
16 changes: 16 additions & 0 deletions MonitorControl/Extensions/Preferences+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Preferences+Extension.swift
// MonitorControl
//
// Created by Joni Van Roost on 22/11/2020.
// Copyright © 2020 MonitorControl. All rights reserved.
//

import Preferences

extension Preferences.PaneIdentifier {
static let main = Self("Main")
static let keys = Self("Keys")
static let advanced = Self("Advanced")
static let display = Self("Display")
}
2 changes: 1 addition & 1 deletion MonitorControl/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>721</string>
<string>946</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
Expand Down
2 changes: 1 addition & 1 deletion MonitorControl/Manager/DisplayManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class DisplayManager {
}

func getDdcCapableDisplays() -> [ExternalDisplay] {
return self.displays.compactMap { (display) -> ExternalDisplay? in
return self.displays.compactMap { display -> ExternalDisplay? in
if let externalDisplay = display as? ExternalDisplay, externalDisplay.ddc != nil {
return externalDisplay
} else { return nil }
Expand Down
2 changes: 1 addition & 1 deletion MonitorControl/Model/Display.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// MonitorControl
//
// Created by Joni Van Roost on 24/01/2020.
// Copyright © 2020 Guillaume Broder. All rights reserved.
// Copyright © 2020 MonitorControl. All rights reserved.
//

import DDC
Expand Down
5 changes: 3 additions & 2 deletions MonitorControl/Model/ExternalDisplay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,9 @@ class ExternalDisplay: Display {

// Check if user has enabled "Play feedback when volume is changed" in Sound Preferences
guard let preferences = Utils.getSystemPreferences(),
let hasSoundEnabled = preferences["com.apple.sound.beep.feedback"] as? Int,
hasSoundEnabled == 1 else {
let hasSoundEnabled = preferences["com.apple.sound.beep.feedback"] as? Int,
hasSoundEnabled == 1
else {
os_log("sound not enabled", type: .info)
return
}
Expand Down
2 changes: 1 addition & 1 deletion MonitorControl/Model/InternalDisplay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// MonitorControl
//
// Created by Joni Van Roost on 24/01/2020.
// Copyright © 2020 Guillaume Broder. All rights reserved.
// Copyright © 2020 MonitorControl. All rights reserved.
//
// Most of the code in this file was sourced from:
// https://github.com/fnesveda/ExternalDisplayBrightness
Expand Down
2 changes: 1 addition & 1 deletion MonitorControl/Support/OSDUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// MonitorControl
//
// Created by Victor Chabbert on 19/06/2020.
// Copyright © 2020 Guillaume Broder. All rights reserved.
// Copyright © 2020 MonitorControl. All rights reserved.
//

import Cocoa
Expand Down
1 change: 0 additions & 1 deletion MonitorControl/Support/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ class Utils: NSObject {
alert.alertStyle = .warning
alert.runModal()
}
return
}

static func readPrivileges(prompt: Bool) -> Bool {
Expand Down
Loading