├── .gitignore ├── .gitmodules ├── AppDelegate.h ├── AppDelegate.m ├── BrightnessMenulet.xcodeproj ├── TemplateIcon.icns ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── DDCControls ├── DDCControls.h ├── DDCControls.m ├── Screen.h └── Screen.m ├── LMU ├── LMUController.h ├── LMUController.m └── LMUDelegate.h ├── Menu ├── MainMenuController.h ├── MainMenuController.m └── Menu.xib ├── Preferences ├── Preferences.xib ├── PreferencesController.h └── PreferencesController.m ├── README.rst ├── Resources ├── brightness-sun-transparent-black.icns ├── icon-alt.png ├── icon.png ├── mccsV3.pdf └── screenshot.png └── Supporting Files ├── BrightnessMenulet_Prefix.pch ├── Info.plist └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | *.xcscheme 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 52 | 53 | fastlane/report.xml 54 | fastlane/screenshots 55 | 56 | .DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ddcctl"] 2 | path = ddcctl 3 | url = https://github.com/kfix/ddcctl 4 | -------------------------------------------------------------------------------- /AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 10/10/14. 6 | // 7 | // 8 | 9 | #import 10 | #import "MainMenuController.h" 11 | 12 | @interface AppDelegate : NSObject 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 10/10/14. 6 | // 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @property NSStatusItem *statusItem; 14 | 15 | @property (strong) IBOutlet MainMenuController *mainMenu; 16 | 17 | @end 18 | 19 | @implementation AppDelegate 20 | 21 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 22 | // Set Menulet Icon 23 | NSBundle *bundle = [NSBundle mainBundle]; 24 | NSImage *statusImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"icon" ofType:@"png"]]; 25 | NSImage *statusHighlightImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"icon-alt" ofType:@"png"]]; 26 | statusImage.template = YES; // Set icon as template for dark mode 27 | statusHighlightImage.template = YES; 28 | 29 | _statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; 30 | _statusItem.image = statusImage; 31 | _statusItem.alternateImage = statusHighlightImage; 32 | _statusItem.toolTip = @"Brightness Menulet"; 33 | _statusItem.highlightMode = YES; 34 | _statusItem.menu = _mainMenu; 35 | 36 | // init _mainMenu 37 | [_mainMenu refreshMenuScreens]; 38 | _mainMenu.delegate = _mainMenu; 39 | 40 | lmuCon.delegate = _mainMenu; 41 | 42 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 43 | 44 | if (![[[defaults dictionaryRepresentation] allKeys] containsObject:@"LMUUpdateInterval"]) 45 | [defaults setFloat:0.5 forKey:@"LMUUpdateInterval"]; 46 | 47 | if ([defaults boolForKey:@"autoBrightOnStartup"]) 48 | [lmuCon startMonitoring]; 49 | } 50 | 51 | - (void)applicationDidChangeScreenParameters:(NSNotification *)notification { 52 | NSLog(@"AppDelegate: DidChangeScreenParameters"); 53 | 54 | [_mainMenu refreshMenuScreens]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /BrightnessMenulet.xcodeproj/TemplateIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kalvin126/BrightnessMenulet/b93e34068cea751ab6e40c4e4628018e5f47bf52/BrightnessMenulet.xcodeproj/TemplateIcon.icns -------------------------------------------------------------------------------- /BrightnessMenulet.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0B38B5E619E8EF9200D72911 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B38B5E519E8EF9200D72911 /* AppDelegate.m */; }; 11 | 7D2FF9FC1140B94600707C79 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D2FF9FB1140B94600707C79 /* IOKit.framework */; }; 12 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 13 | C0391E771E6E81EC00AF4839 /* MainMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = C0391E751E6E81EC00AF4839 /* MainMenuController.m */; }; 14 | C0391E781E6E81EC00AF4839 /* Menu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C0391E761E6E81EC00AF4839 /* Menu.xib */; }; 15 | C0391E7C1E6E820200AF4839 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = C0391E791E6E820200AF4839 /* Preferences.xib */; }; 16 | C0391E7D1E6E820200AF4839 /* PreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = C0391E7B1E6E820200AF4839 /* PreferencesController.m */; }; 17 | C0391E811E6E820E00AF4839 /* LMUController.m in Sources */ = {isa = PBXBuildFile; fileRef = C0391E7F1E6E820E00AF4839 /* LMUController.m */; }; 18 | C0391E861E6E821E00AF4839 /* DDCControls.m in Sources */ = {isa = PBXBuildFile; fileRef = C0391E831E6E821E00AF4839 /* DDCControls.m */; }; 19 | C0391E871E6E821E00AF4839 /* Screen.m in Sources */ = {isa = PBXBuildFile; fileRef = C0391E851E6E821E00AF4839 /* Screen.m */; }; 20 | C0391E8C1E6E823500AF4839 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0391E8A1E6E823500AF4839 /* main.m */; }; 21 | C0391E901E6E824D00AF4839 /* brightness-sun-transparent-black.icns in Resources */ = {isa = PBXBuildFile; fileRef = C0391E8D1E6E824D00AF4839 /* brightness-sun-transparent-black.icns */; }; 22 | C0391E911E6E824D00AF4839 /* icon-alt.png in Resources */ = {isa = PBXBuildFile; fileRef = C0391E8E1E6E824D00AF4839 /* icon-alt.png */; }; 23 | C0391E921E6E824D00AF4839 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = C0391E8F1E6E824D00AF4839 /* icon.png */; }; 24 | C0391E951E6E841F00AF4839 /* DDC.c in Sources */ = {isa = PBXBuildFile; fileRef = C0391E931E6E841F00AF4839 /* DDC.c */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 0B38B5E419E8EF9200D72911 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 29 | 0B38B5E519E8EF9200D72911 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 30 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 31 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 32 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 33 | 7D2FF9FB1140B94600707C79 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; 34 | 7DECCAE1114E12DD0068E5DB /* Brightness Menulet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Brightness Menulet.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | C0391E741E6E81EC00AF4839 /* MainMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MainMenuController.h; path = Menu/MainMenuController.h; sourceTree = ""; }; 36 | C0391E751E6E81EC00AF4839 /* MainMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MainMenuController.m; path = Menu/MainMenuController.m; sourceTree = ""; }; 37 | C0391E761E6E81EC00AF4839 /* Menu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = Menu.xib; path = Menu/Menu.xib; sourceTree = ""; }; 38 | C0391E791E6E820200AF4839 /* Preferences.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = Preferences.xib; path = Preferences/Preferences.xib; sourceTree = ""; }; 39 | C0391E7A1E6E820200AF4839 /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PreferencesController.h; path = Preferences/PreferencesController.h; sourceTree = ""; }; 40 | C0391E7B1E6E820200AF4839 /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PreferencesController.m; path = Preferences/PreferencesController.m; sourceTree = ""; }; 41 | C0391E7E1E6E820E00AF4839 /* LMUController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LMUController.h; path = LMU/LMUController.h; sourceTree = ""; }; 42 | C0391E7F1E6E820E00AF4839 /* LMUController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LMUController.m; path = LMU/LMUController.m; sourceTree = ""; }; 43 | C0391E801E6E820E00AF4839 /* LMUDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LMUDelegate.h; path = LMU/LMUDelegate.h; sourceTree = ""; }; 44 | C0391E821E6E821E00AF4839 /* DDCControls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDCControls.h; path = DDCControls/DDCControls.h; sourceTree = ""; }; 45 | C0391E831E6E821E00AF4839 /* DDCControls.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDCControls.m; path = DDCControls/DDCControls.m; sourceTree = ""; }; 46 | C0391E841E6E821E00AF4839 /* Screen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Screen.h; path = DDCControls/Screen.h; sourceTree = ""; }; 47 | C0391E851E6E821E00AF4839 /* Screen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Screen.m; path = DDCControls/Screen.m; sourceTree = ""; }; 48 | C0391E881E6E823500AF4839 /* BrightnessMenulet_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BrightnessMenulet_Prefix.pch; path = "Supporting Files/BrightnessMenulet_Prefix.pch"; sourceTree = ""; }; 49 | C0391E891E6E823500AF4839 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Supporting Files/Info.plist"; sourceTree = ""; }; 50 | C0391E8A1E6E823500AF4839 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = "Supporting Files/main.m"; sourceTree = ""; }; 51 | C0391E8D1E6E824D00AF4839 /* brightness-sun-transparent-black.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = "brightness-sun-transparent-black.icns"; path = "Resources/brightness-sun-transparent-black.icns"; sourceTree = ""; }; 52 | C0391E8E1E6E824D00AF4839 /* icon-alt.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon-alt.png"; path = "Resources/icon-alt.png"; sourceTree = ""; }; 53 | C0391E8F1E6E824D00AF4839 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon.png; path = Resources/icon.png; sourceTree = ""; }; 54 | C0391E931E6E841F00AF4839 /* DDC.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DDC.c; path = ddcctl/DDC.c; sourceTree = ""; }; 55 | C0391E941E6E841F00AF4839 /* DDC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDC.h; path = ddcctl/DDC.h; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 64 | 7D2FF9FC1140B94600707C79 /* IOKit.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 0B8CF6C819E7172800F3FD6F /* Preferences */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | C0391E791E6E820200AF4839 /* Preferences.xib */, 75 | C0391E7A1E6E820200AF4839 /* PreferencesController.h */, 76 | C0391E7B1E6E820200AF4839 /* PreferencesController.m */, 77 | ); 78 | name = Preferences; 79 | sourceTree = ""; 80 | }; 81 | 0B8CF6CC19E71BA400F3FD6F /* Menu */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | C0391E761E6E81EC00AF4839 /* Menu.xib */, 85 | C0391E741E6E81EC00AF4839 /* MainMenuController.h */, 86 | C0391E751E6E81EC00AF4839 /* MainMenuController.m */, 87 | ); 88 | name = Menu; 89 | sourceTree = ""; 90 | }; 91 | 0BCFE67419C9F1B90094B561 /* DDCControls */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | C0391E821E6E821E00AF4839 /* DDCControls.h */, 95 | C0391E831E6E821E00AF4839 /* DDCControls.m */, 96 | C0391E841E6E821E00AF4839 /* Screen.h */, 97 | C0391E851E6E821E00AF4839 /* Screen.m */, 98 | ); 99 | name = DDCControls; 100 | sourceTree = ""; 101 | }; 102 | 0BCFE67519C9F1EC0094B561 /* Supporting Files */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | C0391E881E6E823500AF4839 /* BrightnessMenulet_Prefix.pch */, 106 | C0391E891E6E823500AF4839 /* Info.plist */, 107 | C0391E8A1E6E823500AF4839 /* main.m */, 108 | ); 109 | name = "Supporting Files"; 110 | sourceTree = ""; 111 | }; 112 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 116 | ); 117 | name = "Linked Frameworks"; 118 | sourceTree = ""; 119 | }; 120 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 7D2FF9FB1140B94600707C79 /* IOKit.framework */, 124 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 125 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 126 | ); 127 | name = "Other Frameworks"; 128 | sourceTree = ""; 129 | }; 130 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 7DECCAE1114E12DD0068E5DB /* Brightness Menulet.app */, 134 | ); 135 | name = Products; 136 | sourceTree = ""; 137 | }; 138 | 29B97314FDCFA39411CA2CEA /* MyStatusItem */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 0B38B5E419E8EF9200D72911 /* AppDelegate.h */, 142 | 0B38B5E519E8EF9200D72911 /* AppDelegate.m */, 143 | 0B8CF6CC19E71BA400F3FD6F /* Menu */, 144 | 0B8CF6C819E7172800F3FD6F /* Preferences */, 145 | 863E61651C5C518D00C2419C /* LMU */, 146 | 0BCFE67419C9F1B90094B561 /* DDCControls */, 147 | 0BCFE67519C9F1EC0094B561 /* Supporting Files */, 148 | 29B97317FDCFA39411CA2CEA /* Resources */, 149 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 150 | 19C28FACFE9D520D11CA2CBB /* Products */, 151 | ); 152 | name = MyStatusItem; 153 | sourceTree = ""; 154 | }; 155 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | C0391E8D1E6E824D00AF4839 /* brightness-sun-transparent-black.icns */, 159 | C0391E8E1E6E824D00AF4839 /* icon-alt.png */, 160 | C0391E8F1E6E824D00AF4839 /* icon.png */, 161 | ); 162 | name = Resources; 163 | sourceTree = ""; 164 | }; 165 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | C0391E961E6E842300AF4839 /* DDC */, 169 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 170 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, 171 | ); 172 | name = Frameworks; 173 | sourceTree = ""; 174 | }; 175 | 863E61651C5C518D00C2419C /* LMU */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | C0391E7E1E6E820E00AF4839 /* LMUController.h */, 179 | C0391E7F1E6E820E00AF4839 /* LMUController.m */, 180 | C0391E801E6E820E00AF4839 /* LMUDelegate.h */, 181 | ); 182 | name = LMU; 183 | sourceTree = ""; 184 | }; 185 | C0391E961E6E842300AF4839 /* DDC */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | C0391E931E6E841F00AF4839 /* DDC.c */, 189 | C0391E941E6E841F00AF4839 /* DDC.h */, 190 | ); 191 | name = DDC; 192 | sourceTree = ""; 193 | }; 194 | /* End PBXGroup section */ 195 | 196 | /* Begin PBXNativeTarget section */ 197 | 8D1107260486CEB800E47090 /* BrightnessMenulet */ = { 198 | isa = PBXNativeTarget; 199 | buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "BrightnessMenulet" */; 200 | buildPhases = ( 201 | 8D1107290486CEB800E47090 /* Resources */, 202 | 8D11072C0486CEB800E47090 /* Sources */, 203 | 8D11072E0486CEB800E47090 /* Frameworks */, 204 | ); 205 | buildRules = ( 206 | ); 207 | dependencies = ( 208 | ); 209 | name = BrightnessMenulet; 210 | productInstallPath = "$(HOME)/Applications"; 211 | productName = MyStatusItem; 212 | productReference = 7DECCAE1114E12DD0068E5DB /* Brightness Menulet.app */; 213 | productType = "com.apple.product-type.application"; 214 | }; 215 | /* End PBXNativeTarget section */ 216 | 217 | /* Begin PBXProject section */ 218 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 219 | isa = PBXProject; 220 | attributes = { 221 | LastUpgradeCheck = 1010; 222 | TargetAttributes = { 223 | 8D1107260486CEB800E47090 = { 224 | DevelopmentTeam = N6A2S4TCDQ; 225 | }; 226 | }; 227 | }; 228 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "BrightnessMenulet" */; 229 | compatibilityVersion = "Xcode 8.0"; 230 | developmentRegion = English; 231 | hasScannedForEncodings = 1; 232 | knownRegions = ( 233 | en, 234 | ); 235 | mainGroup = 29B97314FDCFA39411CA2CEA /* MyStatusItem */; 236 | projectDirPath = ""; 237 | projectRoot = ""; 238 | targets = ( 239 | 8D1107260486CEB800E47090 /* BrightnessMenulet */, 240 | ); 241 | }; 242 | /* End PBXProject section */ 243 | 244 | /* Begin PBXResourcesBuildPhase section */ 245 | 8D1107290486CEB800E47090 /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | C0391E781E6E81EC00AF4839 /* Menu.xib in Resources */, 250 | C0391E901E6E824D00AF4839 /* brightness-sun-transparent-black.icns in Resources */, 251 | C0391E921E6E824D00AF4839 /* icon.png in Resources */, 252 | C0391E7C1E6E820200AF4839 /* Preferences.xib in Resources */, 253 | C0391E911E6E824D00AF4839 /* icon-alt.png in Resources */, 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | /* End PBXResourcesBuildPhase section */ 258 | 259 | /* Begin PBXSourcesBuildPhase section */ 260 | 8D11072C0486CEB800E47090 /* Sources */ = { 261 | isa = PBXSourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | C0391E7D1E6E820200AF4839 /* PreferencesController.m in Sources */, 265 | C0391E951E6E841F00AF4839 /* DDC.c in Sources */, 266 | C0391E861E6E821E00AF4839 /* DDCControls.m in Sources */, 267 | C0391E871E6E821E00AF4839 /* Screen.m in Sources */, 268 | C0391E811E6E820E00AF4839 /* LMUController.m in Sources */, 269 | C0391E771E6E81EC00AF4839 /* MainMenuController.m in Sources */, 270 | C0391E8C1E6E823500AF4839 /* main.m in Sources */, 271 | 0B38B5E619E8EF9200D72911 /* AppDelegate.m in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXSourcesBuildPhase section */ 276 | 277 | /* Begin XCBuildConfiguration section */ 278 | C01FCF4B08A954540054247B /* Debug */ = { 279 | isa = XCBuildConfiguration; 280 | buildSettings = { 281 | COMBINE_HIDPI_IMAGES = YES; 282 | GCC_MODEL_TUNING = G5; 283 | GCC_PREFIX_HEADER = "Supporting Files/BrightnessMenulet_Prefix.pch"; 284 | INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; 285 | INSTALL_PATH = "$(HOME)/Applications"; 286 | PRODUCT_BUNDLE_IDENTIFIER = com.redpanda.BrightnessMenulet; 287 | PRODUCT_NAME = "Brightness Menulet"; 288 | PROVISIONING_PROFILE = ""; 289 | }; 290 | name = Debug; 291 | }; 292 | C01FCF4C08A954540054247B /* Release */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | COMBINE_HIDPI_IMAGES = YES; 296 | GCC_MODEL_TUNING = G5; 297 | GCC_PREFIX_HEADER = "Supporting Files/BrightnessMenulet_Prefix.pch"; 298 | INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; 299 | INSTALL_PATH = "$(HOME)/Applications"; 300 | PRODUCT_BUNDLE_IDENTIFIER = com.redpanda.BrightnessMenulet; 301 | PRODUCT_NAME = "Brightness Menulet"; 302 | PROVISIONING_PROFILE = ""; 303 | }; 304 | name = Release; 305 | }; 306 | C01FCF4F08A954540054247B /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ALWAYS_SEARCH_USER_PATHS = NO; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 324 | CLANG_WARN_STRICT_PROTOTYPES = YES; 325 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 326 | CLANG_WARN_UNREACHABLE_CODE = YES; 327 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 328 | CODE_SIGN_IDENTITY = "Mac Developer"; 329 | COPY_PHASE_STRIP = NO; 330 | DEBUG_INFORMATION_FORMAT = dwarf; 331 | ENABLE_STRICT_OBJC_MSGSEND = YES; 332 | ENABLE_TESTABILITY = YES; 333 | GCC_C_LANGUAGE_STANDARD = c99; 334 | GCC_NO_COMMON_BLOCKS = YES; 335 | GCC_OPTIMIZATION_LEVEL = 0; 336 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 337 | GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; 338 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 339 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 340 | GCC_WARN_UNDECLARED_SELECTOR = YES; 341 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 342 | GCC_WARN_UNUSED_FUNCTION = YES; 343 | GCC_WARN_UNUSED_VARIABLE = YES; 344 | MACOSX_DEPLOYMENT_TARGET = 10.8; 345 | ONLY_ACTIVE_ARCH = YES; 346 | PRODUCT_NAME = "Brightness Menulet"; 347 | SDKROOT = macosx; 348 | }; 349 | name = Debug; 350 | }; 351 | C01FCF5008A954540054247B /* Release */ = { 352 | isa = XCBuildConfiguration; 353 | buildSettings = { 354 | ALWAYS_SEARCH_USER_PATHS = NO; 355 | CLANG_ENABLE_OBJC_ARC = YES; 356 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 357 | CLANG_WARN_BOOL_CONVERSION = YES; 358 | CLANG_WARN_COMMA = YES; 359 | CLANG_WARN_CONSTANT_CONVERSION = YES; 360 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 361 | CLANG_WARN_EMPTY_BODY = YES; 362 | CLANG_WARN_ENUM_CONVERSION = YES; 363 | CLANG_WARN_INFINITE_RECURSION = YES; 364 | CLANG_WARN_INT_CONVERSION = YES; 365 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 366 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 367 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 368 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 369 | CLANG_WARN_STRICT_PROTOTYPES = YES; 370 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 371 | CLANG_WARN_UNREACHABLE_CODE = YES; 372 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 373 | CODE_SIGN_IDENTITY = "Mac Developer"; 374 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 375 | ENABLE_STRICT_OBJC_MSGSEND = YES; 376 | GCC_C_LANGUAGE_STANDARD = c99; 377 | GCC_NO_COMMON_BLOCKS = YES; 378 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 379 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 380 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 381 | GCC_WARN_UNDECLARED_SELECTOR = YES; 382 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 383 | GCC_WARN_UNUSED_FUNCTION = YES; 384 | GCC_WARN_UNUSED_VARIABLE = YES; 385 | MACOSX_DEPLOYMENT_TARGET = 10.8; 386 | PRODUCT_NAME = "Brightness Menulet"; 387 | SDKROOT = macosx; 388 | }; 389 | name = Release; 390 | }; 391 | /* End XCBuildConfiguration section */ 392 | 393 | /* Begin XCConfigurationList section */ 394 | C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "BrightnessMenulet" */ = { 395 | isa = XCConfigurationList; 396 | buildConfigurations = ( 397 | C01FCF4B08A954540054247B /* Debug */, 398 | C01FCF4C08A954540054247B /* Release */, 399 | ); 400 | defaultConfigurationIsVisible = 0; 401 | defaultConfigurationName = Release; 402 | }; 403 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "BrightnessMenulet" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | C01FCF4F08A954540054247B /* Debug */, 407 | C01FCF5008A954540054247B /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | /* End XCConfigurationList section */ 413 | }; 414 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 415 | } 416 | -------------------------------------------------------------------------------- /BrightnessMenulet.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BrightnessMenulet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DDCControls/DDCControls.h: -------------------------------------------------------------------------------- 1 | // 2 | // DDCControls.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 9/17/14. 6 | // 7 | // 8 | 9 | #import 10 | #import "DDC.h" 11 | 12 | #import "Screen.h" 13 | 14 | @interface DDCControls : NSObject 15 | 16 | @property NSArray* screens; 17 | @property NSMutableDictionary* profiles; 18 | 19 | + (DDCControls*)singleton; 20 | 21 | - (NSString*)EDIDString:(char*) string; 22 | - (struct DDCReadCommand)readDisplay:(CGDirectDisplayID)display_id controlValue:(int)control; 23 | - (void)changeDisplay:(CGDirectDisplayID)display_id control:(int)control withValue:(int)value; 24 | 25 | - (void)refreshScreens; 26 | - (void)refreshScreenValues; 27 | 28 | - (Screen*)screenForDisplayName:(NSString*)name; 29 | - (Screen*)screenForDisplayID:(CGDirectDisplayID)display_id; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /DDCControls/DDCControls.m: -------------------------------------------------------------------------------- 1 | // 2 | // DDCControls.m 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 9/17/14. 6 | // 7 | // 8 | 9 | #import "DDCControls.h" 10 | 11 | @implementation DDCControls 12 | 13 | + (DDCControls*)singleton { 14 | static dispatch_once_t pred = 0; 15 | static DDCControls* shared; 16 | dispatch_once(&pred, ^{ 17 | shared = [[self alloc] init]; 18 | }); 19 | 20 | return shared; 21 | } 22 | 23 | // EDID credits to https://github.com/kfix/ddcctl 24 | - (NSString*)EDIDString:(char*)string { 25 | NSString *temp = [[NSString alloc] initWithBytes:string length:13 encoding:NSASCIIStringEncoding]; 26 | return ([temp rangeOfString:@"\n"].location != NSNotFound) ? [[temp componentsSeparatedByString:@"\n"] objectAtIndex:0] : temp; 27 | } 28 | 29 | - (struct DDCReadCommand)readDisplay:(CGDirectDisplayID)display_id controlValue:(int)control { 30 | struct DDCReadCommand read_command = (struct DDCReadCommand) { .control_id = control }; 31 | 32 | if (!DDCRead(display_id, &read_command)) { 33 | #ifdef DEBUG 34 | NSLog(@"readDisplay:%u controlValue: failed need to retry...", display_id); 35 | #endif 36 | } 37 | 38 | return read_command; 39 | } 40 | 41 | - (void)changeDisplay:(CGDirectDisplayID)display_id control:(int)control withValue:(int)value { 42 | struct DDCWriteCommand write_command = (struct DDCWriteCommand) { .control_id = control, .new_value = value }; 43 | 44 | if (!DDCWrite(display_id, &write_command)) { 45 | #ifdef DEBUG 46 | NSLog(@"writeDisplay:%u withValue: failed need to retry...", display_id); 47 | #endif 48 | } 49 | } 50 | 51 | - (void)refreshScreens { 52 | NSLog(@"DDCControls: Refreshing Screens"); 53 | NSMutableArray* newScreens = [NSMutableArray array]; 54 | 55 | for (NSScreen* screen in [NSScreen screens]) { 56 | // Must call unsignedIntValue to get val 57 | NSNumber* screenNumber = screen.deviceDescription[@"NSScreenNumber"]; 58 | 59 | // Fetch Monitor info via EDID 60 | struct EDID edid = {}; 61 | NSString* name; 62 | NSString* serial; 63 | 64 | if (EDIDTest([screenNumber unsignedIntValue], &edid)) { 65 | for (union descriptor *des = edid.descriptors; des < edid.descriptors + sizeof(edid.descriptors); des++) { 66 | switch (des->text.type) { 67 | case 0xFF: 68 | serial = [self EDIDString:des->text.data]; 69 | break; 70 | case 0xFC: 71 | name = [self EDIDString:des->text.data]; 72 | break; 73 | } 74 | } 75 | } 76 | 77 | // don't want to manage invalid screen or integrated LCD 78 | if (!name || [name isEqualToString:@"Color LCD"] || [name isEqualToString:@"iMac"]) 79 | continue; 80 | 81 | // Build screen instance 82 | NSLog(@"DDCControls: Found %@ - %@", name, screenNumber); 83 | Screen* screen = [[Screen alloc] initWithModel:name screenID:[screenNumber unsignedIntValue] serial:serial]; 84 | [screen refreshValues]; 85 | 86 | [newScreens addObject:screen]; 87 | } 88 | 89 | _screens = [newScreens copy]; 90 | 91 | if ([newScreens count] == 0) 92 | NSLog(@"DDCControls: No screens found"); 93 | } 94 | 95 | - (void)refreshScreenValues{ 96 | [_screens makeObjectsPerformSelector:@selector(refreshValues)]; 97 | } 98 | 99 | - (Screen*)screenForDisplayName:(NSString*)name { 100 | for (Screen* screen in _screens) 101 | if ([screen.model isEqualToString:name]) 102 | return screen; 103 | 104 | return nil; 105 | } 106 | 107 | - (Screen*)screenForDisplayID:(CGDirectDisplayID)display_id { 108 | for (Screen* screen in _screens) 109 | if (screen.screenNumber == display_id) 110 | return screen; 111 | 112 | return nil; 113 | } 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /DDCControls/Screen.h: -------------------------------------------------------------------------------- 1 | // 2 | // Screen.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 1/30/16. 6 | // 7 | // 8 | 9 | #import 10 | #import "DDC.h" 11 | 12 | @interface Screen : NSObject 13 | 14 | @property (strong, readonly) NSString* model; 15 | @property (readonly) CGDirectDisplayID screenNumber; 16 | @property (strong, readonly) NSString* serial; 17 | 18 | @property (readonly) NSInteger currentBrightness; 19 | @property (readonly) NSInteger maxBrightness; 20 | 21 | @property (readonly) NSInteger currentContrast; 22 | @property (readonly) NSInteger maxContrast; 23 | 24 | @property (strong) NSMutableArray* brightnessOutlets; 25 | @property (strong) NSMutableArray* contrastOutlets; 26 | 27 | - (instancetype)initWithModel:(NSString*)model screenID:(CGDirectDisplayID)screenID serial:(NSString*)serial; 28 | 29 | - (void)refreshValues; 30 | - (void)ddcReadOut; 31 | 32 | - (void)setBrightnessWithPercentage:(NSInteger)percentage byOutlet:(NSView*)outlet; 33 | - (void)setBrightness:(NSInteger)brightness byOutlet:(NSView*)outlet; 34 | 35 | - (void)setContrastWithPercentage:(NSInteger)percentage byOutlet:(NSView*)outlet; 36 | - (void)setContrast:(NSInteger)contrast byOutlet:(NSView*)outlet; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /DDCControls/Screen.m: -------------------------------------------------------------------------------- 1 | // 2 | // Screen.m 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 1/30/16. 6 | // 7 | // 8 | 9 | #import "Screen.h" 10 | 11 | @interface Screen () 12 | 13 | @property (strong, readwrite) NSString* model; 14 | @property (readwrite) CGDirectDisplayID screenNumber; 15 | @property (strong, readwrite) NSString* serial; 16 | 17 | @property (readwrite) NSInteger currentBrightness; 18 | @property (readwrite) NSInteger maxBrightness; 19 | 20 | @property (readwrite) NSInteger currentContrast; 21 | @property (readwrite) NSInteger maxContrast; 22 | 23 | @end 24 | 25 | @implementation Screen 26 | 27 | - (instancetype)initWithModel:(NSString*)model screenID:(CGDirectDisplayID)screenID serial:(NSString*)serial { 28 | if ((self = [super init])) { 29 | _model = [model copy]; 30 | _screenNumber = screenID; 31 | _serial = [serial copy]; 32 | 33 | _brightnessOutlets = [NSMutableArray array]; 34 | _contrastOutlets = [NSMutableArray array]; 35 | } 36 | 37 | return self; 38 | } 39 | 40 | - (void)refreshValues { 41 | struct DDCReadCommand cBrightness = [controls readDisplay:self.screenNumber controlValue:BRIGHTNESS]; 42 | struct DDCReadCommand cContrast = [controls readDisplay:self.screenNumber controlValue:CONTRAST]; 43 | 44 | if (!cBrightness.success && !cContrast.success) 45 | return; 46 | 47 | self.currentBrightness = cBrightness.current_value; 48 | self.maxBrightness = cBrightness.max_value; 49 | 50 | self.currentContrast = cContrast.current_value; 51 | self.maxContrast = cContrast.max_value; 52 | 53 | [self updateBrightnessOutlets:_brightnessOutlets]; 54 | [self updateContrastOutlets:_contrastOutlets]; 55 | 56 | NSLog(@"Screen: %@ outlets set to BR %ld / CON %ld", _model , (long)self.currentBrightness, (long)self.currentContrast); 57 | } 58 | 59 | - (void)ddcReadOut { 60 | for (int i=0x00; i<=255; i++) { 61 | struct DDCReadCommand response = [controls readDisplay:self.screenNumber controlValue:i]; 62 | NSLog(@"VCP: %x - %d / %d \n", i, response.current_value, response.max_value); 63 | } 64 | } 65 | 66 | - (void)setBrightness:(NSInteger)brightness { 67 | if (brightness > self.maxBrightness) 68 | brightness = self.maxBrightness; 69 | 70 | [controls changeDisplay:self.screenNumber control:BRIGHTNESS withValue:(int)brightness]; 71 | self.currentBrightness = brightness; 72 | 73 | #ifdef DEBUG 74 | NSLog(@"Screen: %@ - %ud Brightness changed to %ld", _model, self.screenNumber, (long)self.currentBrightness); 75 | #endif 76 | } 77 | 78 | - (void)setBrightnessWithPercentage:(NSInteger)percentage byOutlet:(NSView*)outlet { 79 | [self setBrightness:((self.maxBrightness) * ((double)(percentage)/100)) byOutlet:outlet]; 80 | } 81 | 82 | - (void)setBrightness:(NSInteger)brightness byOutlet:(NSView*)outlet { 83 | if (brightness == self.currentBrightness) 84 | return; 85 | else 86 | [self setBrightness:brightness]; 87 | 88 | NSMutableArray* dirtyOutlets = [_brightnessOutlets mutableCopy]; 89 | if (outlet) 90 | [dirtyOutlets removeObject:outlet]; 91 | 92 | [self updateBrightnessOutlets:dirtyOutlets]; 93 | } 94 | 95 | - (void)updateBrightnessOutlets:(NSArray*)outlets { 96 | dispatch_async(dispatch_get_main_queue(), ^{ 97 | for (id outlet in outlets) { 98 | if (![outlet isKindOfClass:[NSTextField class]]) 99 | [outlet setMaxValue:self.maxBrightness]; 100 | 101 | [outlet setIntegerValue:self.currentBrightness]; 102 | } 103 | }); 104 | } 105 | 106 | - (void)setContrast:(NSInteger)contrast { 107 | if (contrast > self.maxContrast) 108 | contrast = self.maxContrast; 109 | 110 | [controls changeDisplay:self.screenNumber control:CONTRAST withValue:(int)contrast]; 111 | self.currentContrast = contrast; 112 | 113 | #ifdef DEBUG 114 | NSLog(@"Screen: %@ - %ud Contrast changed to %ld", _model, self.screenNumber, (long)self.currentContrast); 115 | #endif 116 | } 117 | 118 | - (void)setContrastWithPercentage:(NSInteger)percentage byOutlet:(NSView*)outlet { 119 | [self setContrast:(self.maxContrast * ((double)(percentage)/100)) byOutlet:outlet]; 120 | } 121 | 122 | - (void)setContrast:(NSInteger)contrast byOutlet:(NSView*)outlet { 123 | if (contrast == self.currentContrast) 124 | return; 125 | else 126 | [self setContrast:contrast]; 127 | 128 | NSMutableArray* dirtyOutlets = [_contrastOutlets mutableCopy]; 129 | if (outlet) 130 | [dirtyOutlets removeObject:outlet]; 131 | 132 | [self updateContrastOutlets:dirtyOutlets]; 133 | } 134 | 135 | - (void)updateContrastOutlets:(NSArray*)outlets { 136 | dispatch_async(dispatch_get_main_queue(), ^{ 137 | for (id outlet in outlets) { 138 | if (![outlet isKindOfClass:[NSTextField class]]) 139 | [outlet setMaxValue:self.maxContrast]; 140 | 141 | [outlet setIntegerValue:self.currentContrast]; 142 | } 143 | }); 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /LMU/LMUController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LMUController.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 1/29/16. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | #include 12 | 13 | #import "LMUDelegate.h" 14 | 15 | @interface LMUController : NSObject 16 | 17 | @property (weak) id delegate; 18 | 19 | @property BOOL monitoring; 20 | 21 | + (LMUController*)singleton; 22 | 23 | - (instancetype)init; 24 | 25 | - (void)startMonitoring; 26 | - (void)stopMonitoring; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /LMU/LMUController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LMUController.m 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 1/29/16. 6 | // 7 | // 8 | 9 | #import "LMUController.h" 10 | 11 | @interface LMUController () 12 | 13 | @property CFRunLoopTimerRef updateTimer; 14 | @property io_connect_t lmuDataPort; 15 | 16 | @property (weak) NSTimer* callbackTimer; 17 | 18 | @property (strong) NSMutableArray* percentHistory; 19 | 20 | @end 21 | 22 | @implementation LMUController 23 | 24 | + (LMUController*)singleton{ 25 | static dispatch_once_t pred = 0; 26 | static LMUController* shared; 27 | dispatch_once(&pred, ^{ 28 | shared = [[self alloc] init]; 29 | }); 30 | 31 | return shared; 32 | } 33 | 34 | - (instancetype)init { 35 | if ((self = [super init])) { 36 | _lmuDataPort = 0; 37 | 38 | [self getLMUDataPort]; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (void)dealloc { 45 | [self closeLMUPort]; 46 | } 47 | 48 | - (io_connect_t)getLMUDataPort { 49 | kern_return_t kr; 50 | io_service_t serviceObject; 51 | 52 | if (_lmuDataPort) return _lmuDataPort; 53 | 54 | serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController")); 55 | 56 | if (!serviceObject) { 57 | NSLog(@"LMUController: Failed to find LMU\n"); 58 | return 0; 59 | } 60 | 61 | // Create a connection to the IOService object 62 | kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &_lmuDataPort); 63 | IOObjectRelease(serviceObject); 64 | 65 | if (kr != KERN_SUCCESS) { 66 | NSLog(@"LMUController: Failed to open LMU IOService object"); 67 | return 0; 68 | } 69 | 70 | return _lmuDataPort; 71 | } 72 | 73 | - (void)closeLMUPort { 74 | IOServiceClose(_lmuDataPort); 75 | _lmuDataPort = 0; 76 | } 77 | 78 | - (void)startMonitoring { 79 | // Check if timer already exists of if any screens exist 80 | if (_callbackTimer && ([controls.screens count] == 0)) return; 81 | 82 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 83 | 84 | // NSTimer objects cannot be reused after invalidation 85 | _callbackTimer = [NSTimer scheduledTimerWithTimeInterval:[defaults floatForKey:@"LMUUpdateInterval"] 86 | target:self 87 | selector:@selector(updateTimerCallBack) 88 | userInfo:nil 89 | repeats:YES]; 90 | self.monitoring = YES; 91 | [_delegate LMUControllerDidStartMonitoring]; 92 | NSLog(@"LMUController: Started Monitoring"); 93 | } 94 | 95 | - (void)stopMonitoring { 96 | [_callbackTimer invalidate]; 97 | _callbackTimer = nil; 98 | 99 | self.monitoring = NO; 100 | [_delegate LMUControllerDidStopMonitoring]; 101 | NSLog(@"LMUController: Stopped Monitoring"); 102 | } 103 | 104 | // MODIFY caluclated percent here 105 | - (NSInteger)percentForSensorValue:(double)sensorVal { 106 | // log10(x+1) scale (Weber-Fechner Law) 107 | NSInteger percent = log10(sensorVal + 1) * 10; 108 | 109 | if (percent < 0) 110 | percent = 0; 111 | 112 | return percent; 113 | } 114 | 115 | - (void)updateTimerCallBack { 116 | uint64_t inputValues[0], outputValues[2]; 117 | uint32_t inputCount = 0, outputCount = 2; 118 | kern_return_t kr; 119 | 120 | // 0 = Sensor Reading 121 | kr = IOConnectCallScalarMethod(_lmuDataPort, 0, inputValues, inputCount, outputValues, &outputCount); 122 | 123 | if (kr != KERN_SUCCESS) { 124 | //printf("error getting light sensor values\n"); 125 | return; 126 | } 127 | 128 | double max = 67092480.0; 129 | double avgSensorValue = ((double)(outputValues[0] + outputValues[1]))/2; 130 | 131 | // Check if fetched sensor value is over max. If so, lid must be closed 132 | if (avgSensorValue > max) { 133 | NSLog(@"LMUController: No sensor found or Lid closed"); 134 | //[self stopMonitoring]; 135 | return; 136 | } 137 | 138 | NSInteger percent = [self percentForSensorValue:avgSensorValue]; 139 | 140 | // Add percent to history queue 141 | if (_percentHistory.count == 4) 142 | [_percentHistory removeObjectAtIndex:0]; 143 | [_percentHistory addObject:[NSNumber numberWithInteger:percent]]; 144 | 145 | BOOL needsUpdate = NO; 146 | if (_percentHistory.count == 4) { 147 | NSInteger stableReadingCount = 0; 148 | 149 | for (int i=1; i<4; i++) 150 | if ([_percentHistory[i] integerValue] == percent) 151 | stableReadingCount++; 152 | 153 | if (stableReadingCount == 3) needsUpdate = YES; 154 | } else 155 | needsUpdate = YES; 156 | 157 | if (needsUpdate) 158 | for (Screen* screen in controls.screens) 159 | [screen setBrightnessWithPercentage:percent byOutlet:nil]; 160 | } 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /LMU/LMUDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // LMUDelegate.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 2/7/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @protocol LMUDelegate 12 | 13 | - (void)LMUControllerDidStartMonitoring; 14 | - (void)LMUControllerDidStopMonitoring; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Menu/MainMenuController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainMenuController.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 10/10/14. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "LMUDelegate.h" 13 | @interface MainMenuController : NSMenu 14 | 15 | - (void)refreshMenuScreens; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Menu/MainMenuController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainMenuController.m 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 10/10/14. 6 | // 7 | // 8 | 9 | #import "Screen.h" 10 | 11 | #import "MainMenuController.h" 12 | #import "PreferencesController.h" 13 | 14 | @interface MainMenuController () 15 | 16 | @property PreferencesController* preferencesController; 17 | 18 | @property (weak) IBOutlet NSMenuItem *autoBrightnessItem; 19 | 20 | @end 21 | 22 | @implementation MainMenuController 23 | 24 | - (void)refreshMenuScreens { 25 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 26 | [controls refreshScreens]; 27 | 28 | dispatch_async(dispatch_get_main_queue(), ^{ 29 | [self setupDisplayLabels]; 30 | }); 31 | }); 32 | } 33 | 34 | - (void)setupDisplayLabels { 35 | while (!(self.itemArray[0].isSeparatorItem)) // Remove all current display menu items 36 | [self removeItemAtIndex:0]; 37 | 38 | if ([controls.screens count] == 0) { 39 | // No screen connected, so disable outlets 40 | NSMenuItem* noDispItem = [[NSMenuItem alloc] init]; 41 | noDispItem.title = @"No displays found"; 42 | 43 | [self insertItem:noDispItem atIndex:0]; 44 | 45 | if (lmuCon.monitoring) 46 | [lmuCon stopMonitoring]; 47 | return; 48 | } 49 | 50 | // add new outlets for screens 51 | for (Screen* screen in controls.screens) { 52 | NSString* title = [NSString stringWithFormat:@"%@", screen.model]; 53 | NSMenuItem* scrDesc = [[NSMenuItem alloc] init]; 54 | scrDesc.title = title; 55 | scrDesc.enabled = NO; 56 | 57 | NSSlider* slider = [[NSSlider alloc] initWithFrame:NSRectFromCGRect(CGRectMake(18, 0, 100, 20))]; 58 | slider.target = self; 59 | slider.action = @selector(sliderUpdate:); 60 | slider.tag = screen.screenNumber; 61 | slider.minValue = 0; 62 | slider.maxValue = screen.maxBrightness; 63 | slider.integerValue = screen.currentBrightness; 64 | 65 | NSTextField* brightLevelLabel = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(118, 0, 30, 19))]; 66 | brightLevelLabel.backgroundColor = [NSColor clearColor]; 67 | brightLevelLabel.alignment = NSTextAlignmentLeft; 68 | [[brightLevelLabel cell] setTitle:[NSString stringWithFormat:@"%ld", (long)screen.currentBrightness]]; 69 | [[brightLevelLabel cell] setBezeled:NO]; 70 | 71 | NSMenuItem* scrSlider = [[NSMenuItem alloc] init]; 72 | 73 | NSView* view = [[NSView alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 0, 140, 20))]; 74 | [view addSubview:slider]; 75 | [view addSubview:brightLevelLabel]; 76 | 77 | [scrSlider setView:view]; 78 | [self insertItem:scrSlider atIndex:0]; 79 | [self insertItem:scrDesc atIndex:0]; 80 | 81 | [screen.brightnessOutlets addObjectsFromArray:@[ slider, brightLevelLabel ]]; 82 | } 83 | } 84 | 85 | - (IBAction)toggledAutoBrightness:(NSMenuItem*)sender { 86 | if (sender.state == NSOffState) { 87 | [sender setState:NSOnState]; 88 | [lmuCon startMonitoring]; 89 | } else { 90 | [sender setState:NSOffState]; 91 | [lmuCon stopMonitoring]; 92 | } 93 | } 94 | 95 | - (IBAction)preferences:(id)sender { 96 | if (!_preferencesController) 97 | _preferencesController = [[PreferencesController alloc] init]; 98 | 99 | [_preferencesController showWindow]; 100 | } 101 | 102 | - (void)sliderUpdate:(NSSlider*)slider { 103 | [[controls screenForDisplayID:(int)slider.tag] setBrightness:[slider integerValue] byOutlet:slider]; 104 | } 105 | 106 | - (IBAction)quit:(id)sender { 107 | exit(1); 108 | } 109 | 110 | #pragma mark - NSMenuDelegate 111 | 112 | - (void)menuWillOpen:(NSMenu *)menu { 113 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 114 | [controls refreshScreenValues]; 115 | }); 116 | } 117 | 118 | #pragma mark - LMUDelegate 119 | 120 | - (void)LMUControllerDidStartMonitoring { 121 | [_autoBrightnessItem setState:NSOnState]; 122 | } 123 | 124 | - (void)LMUControllerDidStopMonitoring { 125 | [_autoBrightnessItem setState:NSOffState]; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /Menu/Menu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Preferences/Preferences.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Preferences/PreferencesController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesController.h 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 10/8/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface PreferencesController : NSWindowController 12 | 13 | - (void)showWindow; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Preferences/PreferencesController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesController.m 3 | // BrightnessMenulet 4 | // 5 | // Created by Kalvin Loc on 10/8/14. 6 | // 7 | // 8 | 9 | #import "Screen.h" 10 | #import "PreferencesController.h" 11 | 12 | @interface PreferencesController () 13 | 14 | @property IBOutlet NSWindow *preferenceWindow; 15 | 16 | @property Screen* currentScreen; 17 | @property (weak) IBOutlet NSPopUpButton *displayPopUpButton; 18 | 19 | // Brightness and Contrast IBOutlets 20 | @property (weak) IBOutlet NSSlider* brightCSlider; 21 | @property (weak) IBOutlet NSTextField* brightCTextField; 22 | @property (weak) IBOutlet NSStepper* brightCStepper; 23 | @property (weak) IBOutlet NSSlider* contCSlider; 24 | @property (weak) IBOutlet NSTextField* contCTextField; 25 | @property (weak) IBOutlet NSStepper* contCStepper; 26 | 27 | // If only OSX supported IBOutlet​Collection... 28 | @property (strong) NSArray* brightnessOutlets; 29 | @property (strong) NSArray* contrastOutlets; 30 | 31 | // Auto-Brightness IBOutlets 32 | @property (weak) IBOutlet NSButton *autoBrightOnStartupButton; 33 | 34 | @property (weak) IBOutlet NSSlider *updateIntervalSlider; 35 | @property (weak) IBOutlet NSTextField *updateIntTextField; 36 | @property (weak) IBOutlet NSStepper *updateIntStepper; 37 | 38 | @property (strong) NSArray* updateIntervalOutlets; 39 | 40 | @end 41 | 42 | @implementation PreferencesController 43 | 44 | - (void)showWindow { 45 | // Must support atleast OSX 10.8 because of loadNibNamed:owner:topLevelObjects 46 | if (!_preferenceWindow) { 47 | [[NSBundle mainBundle] loadNibNamed:@"Preferences" owner:self topLevelObjects:nil]; 48 | 49 | _preferenceWindow.delegate = self; 50 | 51 | NSNumberFormatter* decFormater = [[NSNumberFormatter alloc] init]; 52 | [decFormater setNumberStyle:NSNumberFormatterDecimalStyle]; 53 | 54 | [_brightCTextField setFormatter:decFormater]; 55 | [_contCTextField setFormatter:decFormater]; 56 | 57 | _brightnessOutlets = @[_brightCSlider, _brightCTextField, _brightCStepper]; 58 | _contrastOutlets = @[_contCSlider, _contCTextField, _contCStepper]; 59 | 60 | _updateIntervalOutlets = @[_updateIntervalSlider, _updateIntTextField, _updateIntStepper]; 61 | 62 | _updateIntervalSlider.maxValue = 4.0; 63 | _updateIntervalSlider.minValue = 0.1; 64 | _updateIntStepper.maxValue = _updateIntervalSlider.maxValue; 65 | _updateIntStepper.minValue = _updateIntervalSlider.minValue; 66 | _updateIntStepper.increment = 0.5; 67 | 68 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 69 | float updateInterval = [defaults floatForKey:@"LMUUpdateInterval"]; 70 | 71 | if (updateInterval <= 0) 72 | updateInterval = 0.1; 73 | 74 | for (id outlet in _updateIntervalOutlets) 75 | [outlet setFloatValue:updateInterval]; 76 | } 77 | 78 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 79 | [_autoBrightOnStartupButton setState:([defaults boolForKey:@"autoBrightOnStartup"])]; 80 | 81 | [self refreshScreenPopUpList]; 82 | 83 | [self updateBrightnessControls]; 84 | [self updateContrastControls]; 85 | 86 | [[self preferenceWindow] makeKeyAndOrderFront:self]; // does not order front? 87 | 88 | // TODO: find a better way to actually make window Key AND Front 89 | [NSApp activateIgnoringOtherApps:YES]; 90 | } 91 | 92 | - (void)updateBrightnessControls { 93 | NSInteger currentBrightness = _currentScreen.currentBrightness; 94 | 95 | for (id brightnessOutlet in _brightnessOutlets) { 96 | if (![brightnessOutlet isKindOfClass:[NSTextField class]]) 97 | [brightnessOutlet setMaxValue:_currentScreen.maxBrightness]; 98 | 99 | [brightnessOutlet setIntegerValue:currentBrightness]; 100 | } 101 | } 102 | 103 | - (void)updateContrastControls { 104 | NSInteger currentContrast = _currentScreen.currentContrast; 105 | 106 | for (id contrastOutlet in _contrastOutlets) { 107 | if (![contrastOutlet isKindOfClass:[NSTextField class]]) 108 | [contrastOutlet setMaxValue:_currentScreen.maxContrast]; 109 | 110 | [contrastOutlet setIntegerValue:currentContrast]; 111 | } 112 | } 113 | 114 | - (void)refreshScreenPopUpList { 115 | // Reset Variables 116 | [_displayPopUpButton removeAllItems]; 117 | [_currentScreen.brightnessOutlets removeObjectsInArray:_brightnessOutlets]; 118 | [_currentScreen.contrastOutlets removeObjectsInArray:_contrastOutlets]; 119 | 120 | [controls refreshScreenValues]; 121 | 122 | if ([controls.screens count] == 0) { 123 | // no screens so disable outlets 124 | [_displayPopUpButton setEnabled:NO]; 125 | 126 | // makeObjectsPerformSelector:withObject: only allows NO because it is same as nil lol... 127 | [_brightnessOutlets makeObjectsPerformSelector:@selector(setEnabled:) withObject:NO]; 128 | [_contrastOutlets makeObjectsPerformSelector:@selector(setEnabled:) withObject:NO]; 129 | 130 | return; 131 | } 132 | 133 | // Add new screens 134 | for (Screen* screen in controls.screens) 135 | [_displayPopUpButton addItemWithTitle:screen.model]; 136 | 137 | if (!_brightCStepper.enabled) 138 | for (id outlet in [_brightnessOutlets arrayByAddingObjectsFromArray:_contrastOutlets]) 139 | [outlet setEnabled:YES]; 140 | 141 | [_displayPopUpButton selectItemAtIndex:0]; 142 | NSString* cselect = [_displayPopUpButton titleOfSelectedItem]; 143 | _currentScreen = [controls screenForDisplayName:cselect]; 144 | 145 | // Add outlets to new _currentScreen 146 | [_currentScreen.brightnessOutlets addObjectsFromArray:_brightnessOutlets]; 147 | [_currentScreen.contrastOutlets addObjectsFromArray:_contrastOutlets]; 148 | 149 | [self updateBrightnessControls]; 150 | [self updateContrastControls]; 151 | } 152 | 153 | #pragma mark - Brightness and Contrast IBActions 154 | 155 | - (IBAction)didChangeDisplayMenu:(id)sender { 156 | NSString* selectedItem = _displayPopUpButton.titleOfSelectedItem; 157 | 158 | // remove outlets from old screen 159 | [_currentScreen.brightnessOutlets removeObjectsInArray:_brightnessOutlets]; 160 | [_currentScreen.contrastOutlets removeObjectsInArray:_contrastOutlets]; 161 | 162 | _currentScreen = [controls screenForDisplayName:selectedItem]; 163 | 164 | // Add outlets to new _currentScreen 165 | [_currentScreen.brightnessOutlets addObjectsFromArray:_brightnessOutlets]; 166 | [_currentScreen.contrastOutlets addObjectsFromArray:_contrastOutlets]; 167 | 168 | [self updateBrightnessControls]; 169 | [self updateContrastControls]; 170 | } 171 | 172 | - (IBAction)pressedDebug:(NSButton *)sender { 173 | [_currentScreen ddcReadOut]; 174 | } 175 | 176 | - (IBAction)pressedRefreshDisp:(id)sender { 177 | [self refreshScreenPopUpList]; 178 | } 179 | 180 | - (IBAction)brightnessOutletValueChanged:(id)sender{ 181 | [_currentScreen setBrightness:[sender integerValue] byOutlet:sender]; 182 | 183 | NSMutableArray* dirtyOutlets = [_brightnessOutlets mutableCopy]; 184 | [dirtyOutlets removeObject:sender]; 185 | 186 | for (id outlet in dirtyOutlets) 187 | [outlet setIntegerValue:[sender integerValue]]; 188 | } 189 | 190 | - (IBAction)contrastOutletValueChanged:(id)sender{ 191 | [_currentScreen setContrast:[sender integerValue] byOutlet:sender]; 192 | 193 | NSMutableArray* dirtyOutlets = [_contrastOutlets mutableCopy]; 194 | [dirtyOutlets removeObject:sender]; 195 | 196 | for (id outlet in dirtyOutlets) 197 | [outlet setIntegerValue:[sender integerValue]]; 198 | } 199 | 200 | #pragma mark - Auto-Brightness IBActions 201 | 202 | - (IBAction)didToggleAutoBrightOnStartupButton:(NSButton*)sender { 203 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 204 | 205 | [defaults setBool:(sender.state == NSOnState ? YES : NO) forKey:@"autoBrightOnStartup"]; 206 | } 207 | 208 | - (IBAction)updateIntOutletValueChanged:(id)sender { 209 | NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 210 | float value = [sender floatValue]; 211 | 212 | if (value > _updateIntervalSlider.maxValue) 213 | value = _updateIntervalSlider.maxValue; 214 | else if (value <= 0) 215 | value = 0.1; 216 | 217 | [defaults setFloat:value forKey:@"LMUUpdateInterval"]; 218 | 219 | NSMutableArray* dirtyOutlets = [_updateIntervalOutlets mutableCopy]; 220 | [dirtyOutlets removeObject:sender]; 221 | 222 | for (id outlet in dirtyOutlets) 223 | [outlet setFloatValue:value]; 224 | } 225 | 226 | #pragma mark - NSWindowDelegate 227 | 228 | - (void)windowWillClose:(NSNotification *)notification { 229 | _brightnessOutlets = nil; 230 | _contrastOutlets = nil; 231 | _updateIntervalOutlets = nil; 232 | _preferenceWindow = nil; 233 | 234 | // RestartLMU Controller to apply any interval changes 235 | if (lmuCon.monitoring) { 236 | [lmuCon stopMonitoring]; 237 | [lmuCon startMonitoring]; 238 | } 239 | } 240 | 241 | @end 242 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Brightness Menulet 2 | ================== 3 | 4 | Allows you to control monitor brigthness via menu in status bar. 5 | 6 | Download latest app build in the releases tab. 7 | 8 | .. _BrightnessMenulet.zip: 9 | https://raw.github.com/kalvin126/BrightnessMenulet/master/Resources/Brightness_Menulet.zip 10 | 11 | .. image:: https://raw.github.com/kalvin126/BrightnessMenulet/master/Resources/screenshot.png 12 | 13 | Features: 14 | ............ 15 | 16 | - Automatic Brightness using built in light sensor 17 | - Multi-Monitor support (no limit to amount of monitors!) 18 | - *Runnable* with OSX 10.8+ (Mileage will vary per monitor/GPU combination) 19 | - Logs VCP codes to console 20 | 21 | Roadmap: 22 | ........ 23 | 24 | - Time based settings 25 | - Add keyboard bindings 26 | 27 | Credits: 28 | ........ 29 | 30 | - `Alec Jacobson`_ - `original Brightness Menulet app`_ creator 31 | - Jon Taylor - `DDC/CI bindings`_ 32 | - Victor Miroshnikov - copy&paste&debug job 33 | - `Joey Korkames`_: DDC / ddcctl 34 | 35 | .. _DDC/CI bindings: 36 | https://github.com/jontaylor/DDC-CI-Tools-for-OS-X 37 | 38 | .. _Alec Jacobson: 39 | http://www.alecjacobson.com/weblog/ 40 | 41 | .. _Joey Korkames: 42 | https://github.com/kfix/ddcctl 43 | 44 | .. _original Brightness Menulet app: 45 | http://www.alecjacobson.com/weblog/?p=1127 46 | -------------------------------------------------------------------------------- /Resources/brightness-sun-transparent-black.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kalvin126/BrightnessMenulet/b93e34068cea751ab6e40c4e4628018e5f47bf52/Resources/brightness-sun-transparent-black.icns -------------------------------------------------------------------------------- /Resources/icon-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kalvin126/BrightnessMenulet/b93e34068cea751ab6e40c4e4628018e5f47bf52/Resources/icon-alt.png -------------------------------------------------------------------------------- /Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kalvin126/BrightnessMenulet/b93e34068cea751ab6e40c4e4628018e5f47bf52/Resources/icon.png -------------------------------------------------------------------------------- /Resources/mccsV3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kalvin126/BrightnessMenulet/b93e34068cea751ab6e40c4e4628018e5f47bf52/Resources/mccsV3.pdf -------------------------------------------------------------------------------- /Resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kalvin126/BrightnessMenulet/b93e34068cea751ab6e40c4e4628018e5f47bf52/Resources/screenshot.png -------------------------------------------------------------------------------- /Supporting Files/BrightnessMenulet_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'MyStatusItem' target in the 'MyStatusItem' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import "DDCControls.h" 8 | #import "LMUController.h" 9 | 10 | #define controls [DDCControls singleton] 11 | #define lmuCon [LMUController singleton] 12 | #endif 13 | -------------------------------------------------------------------------------- /Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | brightness-sun-transparent-black.icns 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.1 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSBackgroundOnly 28 | 29 | LSUIElement 30 | 31 | NSMainNibFile 32 | Menu 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MyStatusItem 4 | // 5 | // Created by Alec Jacobson on 3/4/10. 6 | // Copyright New York University 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | --------------------------------------------------------------------------------