From 672c8d44318be901e54b8be3d71ab05697b93916 Mon Sep 17 00:00:00 2001 From: Eun Date: Thu, 17 Apr 2014 12:25:16 +0200 Subject: [PATCH] Initial Release of gui --- DisableMonitor-Info.plist | 34 ++ DisableMonitor.c | 230 ------------- DisableMonitor.xcodeproj/project.pbxproj | 306 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + DisableMonitorAppDelegate.h | 20 ++ DisableMonitorAppDelegate.m | 216 +++++++++++++ DisableMonitor_Prefix.pch | 7 + English.lproj/InfoPlist.strings | 2 + English.lproj/MainMenu.xib | 23 ++ GLFW.m | 106 ++++++ Makefile | 16 - README.md | 2 - icon.icns | Bin 0 -> 29701 bytes status_icon.png | Bin 0 -> 306 bytes 14 files changed, 721 insertions(+), 248 deletions(-) create mode 100644 DisableMonitor-Info.plist delete mode 100644 DisableMonitor.c create mode 100644 DisableMonitor.xcodeproj/project.pbxproj create mode 100644 DisableMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 DisableMonitorAppDelegate.h create mode 100644 DisableMonitorAppDelegate.m create mode 100644 DisableMonitor_Prefix.pch create mode 100644 English.lproj/InfoPlist.strings create mode 100644 English.lproj/MainMenu.xib create mode 100644 GLFW.m delete mode 100644 Makefile create mode 100644 icon.icns create mode 100644 status_icon.png diff --git a/DisableMonitor-Info.plist b/DisableMonitor-Info.plist new file mode 100644 index 0000000..ef50209 --- /dev/null +++ b/DisableMonitor-Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + icon + CFBundleIdentifier + eun.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + LSUIElement + + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/DisableMonitor.c b/DisableMonitor.c deleted file mode 100644 index 0587491..0000000 --- a/DisableMonitor.c +++ /dev/null @@ -1,230 +0,0 @@ -/** - * DisableMonitor, Disable Monitors on Mac - * - * Copyright (C) 2014 Tobias Salzmann - * - * DisableMonitor is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * DisableMonitor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * See the GNU General Public License for more details. You should have received a copy of the GNU - * General Public License along with DisableMonitor. If not, see . - * - * Authors: Tobias Salzmann - */ -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - // for old macs? - //extern CGError CGConfigureDisplayEnabled(CGDisplayConfigRef, CGDirectDisplayID, bool); - - - extern CGError CGSConfigureDisplayEnabled(CGDisplayConfigRef, CGDirectDisplayID, bool); - -#ifdef __cplusplus -} -#endif - -// GLFW 3.0 START -//======================================================================== -// GLFW 3.0 OS X - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2010 Camilla Berglund -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== -io_service_t IOServicePortFromCGDisplayID(CGDirectDisplayID displayID) -{ - io_iterator_t iter; - io_service_t serv, servicePort = 0; - - CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect"); - - // releases matching for us - kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault, - matching, - &iter); - if (err) - { - return 0; - } - - while ((serv = IOIteratorNext(iter)) != 0) - { - CFDictionaryRef info; - CFIndex vendorID, productID; - CFNumberRef vendorIDRef, productIDRef; - Boolean success; - - info = IODisplayCreateInfoDictionary(serv, - kIODisplayOnlyPreferredName); - - vendorIDRef = CFDictionaryGetValue(info, - CFSTR(kDisplayVendorID)); - productIDRef = CFDictionaryGetValue(info, - CFSTR(kDisplayProductID)); - - success = CFNumberGetValue(vendorIDRef, kCFNumberCFIndexType, - &vendorID); - success &= CFNumberGetValue(productIDRef, kCFNumberCFIndexType, - &productID); - - if (!success) - { - CFRelease(info); - continue; - } - - if (CGDisplayVendorNumber(displayID) != vendorID || - CGDisplayModelNumber(displayID) != productID) - { - CFRelease(info); - continue; - } - - // we're a match - servicePort = serv; - CFRelease(info); - break; - } - - IOObjectRelease(iter); - return servicePort; -} - -// Get the name of the specified display -// -char* getDisplayName(CGDirectDisplayID displayID) -{ - char* name; - CFDictionaryRef info, names; - CFStringRef value; - CFIndex size; - - io_service_t serv = IOServicePortFromCGDisplayID(displayID); - if (!serv) - { - return strdup("Unknown"); - } - - info = IODisplayCreateInfoDictionary(serv, - kIODisplayOnlyPreferredName); - - IOObjectRelease(serv); - - names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); - - if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), - (const void**) &value)) - { - //_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to retrieve display name"); - CFRelease(info); - return strdup("Unknown"); - } - - size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), - kCFStringEncodingUTF8); - name = calloc(size + 1, sizeof(char)); - CFStringGetCString(value, name, size, kCFStringEncodingUTF8); - - CFRelease(info); - - return name; -} -// GLFW 3.0 END - -int main(int argc, const char * argv[]) -{ - - if (argc < 2) - { - CGDirectDisplayID displays[0x10]; - uint32_t nDisplays; - CGGetOnlineDisplayList(0x10, displays, &nDisplays); - - printf("DisableMonitor 1.1 - http://github.com/Eun/DisableMonitor\n\nusage: %s \n\n", basename((char*)argv[0])); - - printf("Name | Display ID | Metrics | Main Display? | Active?\n"); - if (nDisplays > 0) - { - for (int i = 0; i < nDisplays; i++) - { - char *name = getDisplayName(displays[i]); - if (strlen(name) > 10) - name[9] = 0; - printf("%-10s | %10d | %4dx%-4d | %-13s | %-s\n", name, displays[i], (int)CGDisplayPixelsWide(displays[i]), (int)CGDisplayPixelsHigh(displays[i]), CGDisplayIsMain(displays[i]) ? "Yes" : "No", CGDisplayIsActive(displays[i]) ? "Yes" : "No"); - } - } - else - { - printf("Could not detect displays!\n"); - } - - return 0; - } - else - { - CGError err; - CGDisplayConfigRef config; - - CGDirectDisplayID display; - - if (!strncmp(argv[1], "0", strlen(argv[1]))) - { - display = CGMainDisplayID(); - } - else - { - display = atoi(argv[1]); - } - - err = CGBeginDisplayConfiguration (&config); - if (err != 0) - { - printf("Error in CGBeginDisplayConfiguration: %d\n", err); - return err; - } - err = CGSConfigureDisplayEnabled(config, display, !CGDisplayIsActive(display)); - if (err != 0) - { - printf("Error in CGSConfigureDisplayEnabled: %d\n", err); - return err; - } - err = CGCompleteDisplayConfiguration(config, kCGConfigurePermanently); - if (err != 0) - { - printf("Error in CGCompleteDisplayConfiguration: %d\n", err); - return err; - } - } - - return 0; -} - diff --git a/DisableMonitor.xcodeproj/project.pbxproj b/DisableMonitor.xcodeproj/project.pbxproj new file mode 100644 index 0000000..379057b --- /dev/null +++ b/DisableMonitor.xcodeproj/project.pbxproj @@ -0,0 +1,306 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; + 256AC3DA0F4B6AC300CF3369 /* DisableMonitorAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* DisableMonitorAppDelegate.m */; }; + 592CED7E18FEB66E00FDDF65 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 592CED7D18FEB66E00FDDF65 /* IOKit.framework */; }; + 592CED8118FEBDB300FDDF65 /* GLFW.m in Sources */ = {isa = PBXBuildFile; fileRef = 592CED8018FEBDB300FDDF65 /* GLFW.m */; }; + 592CED8718FEC42800FDDF65 /* status_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 592CED8618FEC42800FDDF65 /* status_icon.png */; }; + 59B5766718FFDC6700B57E77 /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 59B5766618FFDC6700B57E77 /* icon.icns */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; + 256AC3D80F4B6AC300CF3369 /* DisableMonitorAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisableMonitorAppDelegate.h; sourceTree = ""; }; + 256AC3D90F4B6AC300CF3369 /* DisableMonitorAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DisableMonitorAppDelegate.m; sourceTree = ""; }; + 256AC3F00F4B6AF500CF3369 /* DisableMonitor_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisableMonitor_Prefix.pch; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 592CED7D18FEB66E00FDDF65 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + 592CED8018FEBDB300FDDF65 /* GLFW.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLFW.m; sourceTree = ""; }; + 592CED8618FEC42800FDDF65 /* status_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = status_icon.png; sourceTree = ""; }; + 59B5766618FFDC6700B57E77 /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = icon.icns; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* DisableMonitor-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "DisableMonitor-Info.plist"; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* DisableMonitor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DisableMonitor.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 592CED7E18FEB66E00FDDF65 /* IOKit.framework in Frameworks */, + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 256AC3D80F4B6AC300CF3369 /* DisableMonitorAppDelegate.h */, + 256AC3D90F4B6AC300CF3369 /* DisableMonitorAppDelegate.m */, + 592CED8018FEBDB300FDDF65 /* GLFW.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* DisableMonitor.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* DisableMonitor */ = { + isa = PBXGroup; + children = ( + 59B5766618FFDC6700B57E77 /* icon.icns */, + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = DisableMonitor; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 256AC3F00F4B6AF500CF3369 /* DisableMonitor_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 592CED8618FEC42800FDDF65 /* status_icon.png */, + 8D1107310486CEB800E47090 /* DisableMonitor-Info.plist */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 592CED7D18FEB66E00FDDF65 /* IOKit.framework */, + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* DisableMonitor */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "DisableMonitor" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DisableMonitor; + productInstallPath = "$(HOME)/Applications"; + productName = DisableMonitor; + productReference = 8D1107320486CEB800E47090 /* DisableMonitor.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DisableMonitor" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* DisableMonitor */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* DisableMonitor */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + 59B5766718FFDC6700B57E77 /* icon.icns in Resources */, + 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, + 592CED8718FEC42800FDDF65 /* status_icon.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072D0486CEB800E47090 /* main.m in Sources */, + 256AC3DA0F4B6AC300CF3369 /* DisableMonitorAppDelegate.m in Sources */, + 592CED8118FEBDB300FDDF65 /* GLFW.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 1DDD58150DA1D0A300B32029 /* English */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = DisableMonitor_Prefix.pch; + INFOPLIST_FILE = "DisableMonitor-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = DisableMonitor; + SDKROOT = macosx; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = DisableMonitor_Prefix.pch; + INFOPLIST_FILE = "DisableMonitor-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = DisableMonitor; + SDKROOT = macosx; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "DisableMonitor" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DisableMonitor" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/DisableMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DisableMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..a62547a --- /dev/null +++ b/DisableMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/DisableMonitorAppDelegate.h b/DisableMonitorAppDelegate.h new file mode 100644 index 0000000..f429f9b --- /dev/null +++ b/DisableMonitorAppDelegate.h @@ -0,0 +1,20 @@ +// +// DisableMonitorAppDelegate.h +// DisableMonitor +// +// Created by Aravindkumar Rajendiran on 10-04-17. +// Copyright 2010 Grapewave. All rights reserved. +// + +#import + +@interface DisableMonitorAppDelegate : NSObject { + NSWindow *window; + IBOutlet NSMenu *statusMenu; + NSStatusItem * statusItem; + +} + +@property (assign) IBOutlet NSWindow *window; + +@end diff --git a/DisableMonitorAppDelegate.m b/DisableMonitorAppDelegate.m new file mode 100644 index 0000000..e8da318 --- /dev/null +++ b/DisableMonitorAppDelegate.m @@ -0,0 +1,216 @@ +// +// DisableMonitorAppDelegate.m +// DisableMonitor +// +// Created by Aravindkumar Rajendiran on 10-04-17. +// Copyright 2010 Grapewave. All rights reserved. +// + +#import "DisableMonitorAppDelegate.h" +#import + +@implementation DisableMonitorAppDelegate + +@synthesize window; + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Insert code here to initialize your application +} + + +extern io_service_t IOServicePortFromCGDisplayID(CGDirectDisplayID displayID); +extern CGError CGSConfigureDisplayEnabled(CGDisplayConfigRef, CGDirectDisplayID, bool); + +NSString* screenNameForDisplay(CGDirectDisplayID displayID) +{ + NSString *screenName = nil; + + io_service_t service = IOServicePortFromCGDisplayID(displayID); + if (service) + { + NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName); + NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]]; + + if ([localizedNames count] > 0) { + screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain]; + } + + [deviceInfo release]; + } + return [screenName autorelease]; +} + +-(void)ToggleMonitor:(CGDirectDisplayID) display enabled:(Boolean) enabled +{ + CGError err; + CGDisplayConfigRef config; + @try { + err = CGBeginDisplayConfiguration (&config); + if (err != 0) + { + NSLog(@"Error in CGBeginDisplayConfiguration: %d\n", err); + return; + } + err = CGSConfigureDisplayEnabled(config, display, enabled); + if (err != 0) + { + NSLog(@"Error in CGSConfigureDisplayEnabled: %d\n", err); + return; + } + err = CGCompleteDisplayConfiguration(config, kCGConfigurePermanently); + if (err != 0) + { + NSLog(@"Error in CGCompleteDisplayConfiguration: %d\n", err); + return; + } + } + @catch (NSException *exception) { + + } +} + +-(void)MonitorClicked:(id) sender +{ + NSMenuItem * item = (NSMenuItem*)sender; + + CGDirectDisplayID display = (CGDirectDisplayID)[item tag]; + Boolean active = CGDisplayIsActive(display); + + if (active == true) + { + CGDirectDisplayID displays[0x10]; + CGDisplayCount nDisplays = 0; + CGError err = CGGetActiveDisplayList(0x10, displays, &nDisplays); + + if (err == 0 && nDisplays - 1 == 0) + { + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + [alert setInformativeText:@"You are disabling your last active monitor, you wont be able to see anything continue?"]; + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert setMessageText:@"Warning"]; + if ([alert runModal] != NSAlertFirstButtonReturn) + { + [alert release]; + return; + } + [alert release]; + } + } + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self ToggleMonitor:display enabled:!active]; + }); + +} + + +-(void)DetectMonitors:(id) sender +{ + CGDirectDisplayID displays[0x10]; + CGDisplayCount dspCount = 0; + + if (CGSGetDisplayList(0x10, displays, &dspCount) == noErr) + { + for(int i = 0; i < dspCount; i++) + { + io_service_t service = IOServicePortFromCGDisplayID(displays[i]); + if (service) + IOServiceRequestProbe(service, kIOFBUserRequestProbe); + } + } +} + + +- (void)menuNeedsUpdate:(NSMenu *)menu +{ + + [statusMenu removeAllItems]; + CGDirectDisplayID displays[0x10]; + CGDisplayCount nDisplays = 0; + + CGDisplayErr err = CGSGetDisplayList(0x10, displays, &nDisplays); + + if (err == 0 && nDisplays > 0) + { + NSMutableArray *monitors = [[NSMutableArray alloc] init]; + NSMutableArray *monitorIDs = [[NSMutableArray alloc] init]; + for (int i = 0; i < nDisplays; i++) + { + NSString *name = screenNameForDisplay(displays[i]); + if (name != nil) + { + [monitors addObject: name]; + [monitorIDs addObject:[NSNumber numberWithInt:(CGDirectDisplayID)displays[i]]]; + + + } + } + + for (int i = 0; i < monitors.count; i++) + { + int num = 0; + int index = 1; + + + for (int j = 0; j < monitors.count; j++) + { + if ([monitors[j] caseInsensitiveCompare:monitors[i]] == NSOrderedSame) + { + num++; + if (j < i) + { + index++; + } + } + } + + NSString *name; + if (num > 1) + name = [NSString stringWithFormat:@"%@ (%d)", monitors[i], index]; + else + name = monitors[i]; + + NSMenuItem *displayItem = [[NSMenuItem alloc] initWithTitle: name action:@selector(MonitorClicked:) keyEquivalent:@""]; + if (CGDisplayIsActive(displays[i])) + [displayItem setState:NSOnState]; + else + [displayItem setState:NSOffState]; + [displayItem setTag:displays[i]]; + [statusMenu addItem:displayItem]; + [displayItem release]; + + } + [monitors release]; + [monitorIDs release]; + + } + else + { + NSMenuItem *noDisplays = [[NSMenuItem alloc] initWithTitle: @"No Displays Detected" action:nil keyEquivalent:@""]; + [statusMenu addItem:noDisplays]; + [noDisplays release]; + } + + [statusMenu addItem:[NSMenuItem separatorItem]]; + + NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle: @"Detect Monitors" action:@selector(DetectMonitors:) keyEquivalent:@""]; + [statusMenu addItem:menuItem]; + [menuItem release]; +} + +-(void)awakeFromNib{ + + + statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain]; + + [statusMenu setDelegate:self]; + [statusItem setMenu:statusMenu]; + [statusItem setImage:[NSImage imageNamed:@"status_icon.png"]]; + [statusItem setHighlightMode:YES]; + + +} + +@end diff --git a/DisableMonitor_Prefix.pch b/DisableMonitor_Prefix.pch new file mode 100644 index 0000000..50623eb --- /dev/null +++ b/DisableMonitor_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'DisableMonitor' target in the 'DisableMonitor' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/English.lproj/InfoPlist.strings b/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/English.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/English.lproj/MainMenu.xib b/English.lproj/MainMenu.xib new file mode 100644 index 0000000..b142f78 --- /dev/null +++ b/English.lproj/MainMenu.xib @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GLFW.m b/GLFW.m new file mode 100644 index 0000000..b069df8 --- /dev/null +++ b/GLFW.m @@ -0,0 +1,106 @@ +/** + * DisableMonitor, Disable Monitors on Mac + * + * Copyright (C) 2014 Tobias Salzmann + * + * DisableMonitor is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * DisableMonitor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. You should have received a copy of the GNU + * General Public License along with DisableMonitor. If not, see . + * + * Authors: Tobias Salzmann + */ + +#import + +// GLFW 3.0 START +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +io_service_t IOServicePortFromCGDisplayID(CGDirectDisplayID displayID) +{ + io_iterator_t iter; + io_service_t serv, servicePort = 0; + + CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect"); + + // releases matching for us + kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault, + matching, + &iter); + if (err) + { + return 0; + } + + while ((serv = IOIteratorNext(iter)) != 0) + { + CFDictionaryRef info; + CFIndex vendorID, productID; + CFNumberRef vendorIDRef, productIDRef; + Boolean success; + + info = IODisplayCreateInfoDictionary(serv, + kIODisplayOnlyPreferredName); + + vendorIDRef = CFDictionaryGetValue(info, + CFSTR(kDisplayVendorID)); + productIDRef = CFDictionaryGetValue(info, + CFSTR(kDisplayProductID)); + + success = CFNumberGetValue(vendorIDRef, kCFNumberCFIndexType, + &vendorID); + success &= CFNumberGetValue(productIDRef, kCFNumberCFIndexType, + &productID); + + if (!success) + { + CFRelease(info); + continue; + } + + if (CGDisplayVendorNumber(displayID) != vendorID || + CGDisplayModelNumber(displayID) != productID) + { + CFRelease(info); + continue; + } + + // we're a match + servicePort = serv; + CFRelease(info); + break; + } + + IOObjectRelease(iter); + return servicePort; +} +// GLFW 3.0 END diff --git a/Makefile b/Makefile deleted file mode 100644 index c31429a..0000000 --- a/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# bin file -bin = DisableMonitor - -# source files -src = DisableMonitor.c - -# flags -flags = -Wall -framework ApplicationServices -framework IOKit - - -DisableMonitor: - rm -rf $(bin) - gcc -o $(bin) $(src) $(iniparser) $(flags) - -clean: - rm -rf $(bin) diff --git a/README.md b/README.md index 1767eb5..dfff66a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,5 @@ DisableMonitor ============== Disables a Monitor on your Mac Computer -usage: - DisableMonitor diff --git a/icon.icns b/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..ab77b495a17960649b9dff0c1f8ac7dbe4053b84 GIT binary patch literal 29701 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