├── .gitignore ├── TotalTerminal-Prefix.pch ├── English.lproj └── InfoPlist.strings ├── OSAX.xcconfigs ├── OSAX_Debug_TotalTerminal.xcconfig ├── OSAX_Release_TotalTerminal.xcconfig ├── OSAX_Release_TotalTerminal_generated.xcconfig └── OSAX_Debug_TotalTerminal_generated.xcconfig ├── TTVersionComparisonProtocol.h ├── TotalTerminalInjector.sdef ├── TTStandardVersionComparator.h ├── license.txt ├── TotalTerminal-Info.plist ├── readme.md ├── TTStandardVersionComparator.m ├── OSAX.xcodeproj └── project.pbxproj └── TotalTerminalInjector.mm /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | xcuserdata 3 | bin/ -------------------------------------------------------------------------------- /TotalTerminal-Prefix.pch: -------------------------------------------------------------------------------- 1 | #import 2 | -------------------------------------------------------------------------------- /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /OSAX.xcconfigs/OSAX_Debug_TotalTerminal.xcconfig: -------------------------------------------------------------------------------- 1 | //!bagen generate binaryage OSAX Debug TotalTerminal 2 | // 3 | // this file should be set as Debug configuration for target TotalTerminal in OSAX.xcodeproj 4 | 5 | // following included file can be regenerated by running 'badev regen_xcconfigs' 6 | #include "OSAX_Debug_TotalTerminal_generated.xcconfig" 7 | 8 | // here you can follow with your custom settings overrides if needed 9 | 10 | 11 | -------------------------------------------------------------------------------- /OSAX.xcconfigs/OSAX_Release_TotalTerminal.xcconfig: -------------------------------------------------------------------------------- 1 | //!bagen generate binaryage OSAX Release TotalTerminal 2 | // 3 | // this file should be set as Release configuration for target TotalTerminal in OSAX.xcodeproj 4 | 5 | // following included file can be regenerated by running 'badev regen_xcconfigs' 6 | #include "OSAX_Release_TotalTerminal_generated.xcconfig" 7 | 8 | // here you can follow with your custom settings overrides if needed 9 | 10 | 11 | -------------------------------------------------------------------------------- /TTVersionComparisonProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // TTVersionComparisonProtocol.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 12/21/07. 6 | // Copyright 2007 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef TTVERSIONCOMPARISONPROTOCOL_H 10 | #define TTVERSIONCOMPARISONPROTOCOL_H 11 | 12 | /*! 13 | @protocol 14 | @abstract Implement this protocol to provide version comparison facilities for Sparkle. 15 | */ 16 | @protocol TTVersionComparison 17 | 18 | /*! 19 | @method 20 | @abstract An abstract method to compare two version strings. 21 | @discussion Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a, and NSOrderedSame if they are equivalent. 22 | */ 23 | - (NSComparisonResult)compareVersion:(NSString*)versionA toVersion:(NSString*)versionB; 24 | 25 | @end 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /TotalTerminalInjector.sdef: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TTStandardVersionComparator.h: -------------------------------------------------------------------------------- 1 | // 2 | // TTStandardVersionComparator.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 12/21/07. 6 | // Copyright 2007 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef TTSTANDARDVERSIONCOMPARATOR_H 10 | #define TTSTANDARDVERSIONCOMPARATOR_H 11 | 12 | 13 | #import "TTVersionComparisonProtocol.h" 14 | 15 | /*! 16 | @class 17 | @abstract Sparkle's default version comparator. 18 | @discussion This comparator is adapted from MacPAD, by Kevin Ballard. It's "dumb" in that it does essentially string comparison, in components split by 19 | character type. 20 | */ 21 | @interface TTStandardVersionComparator : NSObject { 22 | } 23 | 24 | /*! 25 | @method 26 | @abstract Returns a singleton instance of the comparator. 27 | */ 28 | + (TTStandardVersionComparator*)defaultComparator; 29 | 30 | /*! 31 | @method 32 | @abstract Compares version strings through textual analysis. 33 | @discussion See the implementation for more details. 34 | */ 35 | - (NSComparisonResult)compareVersion:(NSString*)versionA toVersion:(NSString*)versionB; 36 | @end 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Antonin Hildebrand 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of Antonin Hildebrand nor the 12 | names of other contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY Antonin Hildebrand ``AS IS'' AND ANY 16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL Antonin Hildebrand BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /TotalTerminal-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.binaryage.totalterminal.injector 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | TotalTerminalInjector 15 | CFBundlePackageType 16 | osax 17 | CFBundleShortVersionString 18 | ##VERSION## 19 | CFBundleSignature 20 | BAGE 21 | CFBundleVersion 22 | ##VERSION## 23 | OSAScriptingDefinition 24 | TotalTerminalInjector.sdef 25 | OSAXHandlers 26 | 27 | Events 28 | 29 | BATTvih_ 30 | 31 | Context 32 | Process 33 | Handler 34 | handleVisorHiddenEvent 35 | ThreadSafe 36 | 37 | 38 | BATTvish 39 | 40 | Context 41 | Process 42 | Handler 43 | handleShowVisorEvent 44 | ThreadSafe 45 | 46 | 47 | BATTvihd 48 | 49 | Context 50 | Process 51 | Handler 52 | handleHideVisorEvent 53 | ThreadSafe 54 | 55 | 56 | BATTchck 57 | 58 | Context 59 | Process 60 | Handler 61 | handleCheckEvent 62 | ThreadSafe 63 | 64 | 65 | BATTinit 66 | 67 | Context 68 | Process 69 | Handler 70 | handleInitEvent 71 | ThreadSafe 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # TotalTerminal.osax 2 | 3 | This source code implements scripting additions used by [TotalTerminal](http://totalterminal.binaryage.com). 4 | 5 | **TotalTerminal** is a plugin for Apple's Terminal.app which brings Visor (famous Quake console) and more! 6 | 7 | 8 | 9 | ### Visit [totalterminal.binaryage.com](http://totalterminal.binaryage.com) 10 | 11 | ## Is this a replacement for SIMBL? 12 | 13 | Yes, this is SIMBL-lite tailored specifically for TotalTerminal. 14 | 15 | ## BATTinit event 16 | 17 | Installs TotalTerminal.bundle into running Terminal.app (/Applications/TotalTerminal.app is just a wrapper app for this script) 18 | 19 | tell application "Terminal" 20 | -- give Terminal some time to launch if it wasn't running (rare case) 21 | delay 1 -- this delay is important to prevent random "Connection is Invalid -609" AppleScript errors 22 | try 23 | «event BATTinit» 24 | on error msg number num 25 | display dialog "Unable to launch TotalTerminal." & msg & " (" & (num as text) & ")" 26 | end try 27 | end tell 28 | 29 | ## BATTchck event 30 | 31 | Check if TotalTerminal is present in running Terminal image. 32 | 33 | tell application "Terminal" 34 | -- give Terminal some time to launch if it wasn't running (rare case) 35 | delay 1 -- this delay is important to prevent random "Connection is Invalid -609" AppleScript errors 36 | try 37 | «event BATTchck» 38 | set res to "present" 39 | on error msg number num 40 | set res to "not present" 41 | end try 42 | res 43 | end tell 44 | 45 | ## More applescript commands 46 | 47 | ### Show visor window (BATTvish) 48 | 49 | tell application "Terminal" 50 | try 51 | «event BATTvish» 52 | on error msg number num 53 | display dialog "Unable to show visor." & msg & " (" & (num as text) & ")" 54 | end try 55 | end tell 56 | 57 | ### Hide visor window (BATTvihd) 58 | 59 | tell application "Terminal" 60 | try 61 | «event BATTvihd» 62 | on error msg number num 63 | display dialog "Unable to show visor." & msg & " (" & (num as text) & ")" 64 | end try 65 | end tell 66 | 67 | ### Is visor window hidden? (BATTvih_) 68 | 69 | tell application "Terminal" 70 | try 71 | set res to («event BATTvih_») 72 | on error msg number num 73 | display dialog "Unable to show visor." & msg & " (" & (num as text) & ")" 74 | end try 75 | res 76 | end tell 77 | -------------------------------------------------------------------------------- /OSAX.xcconfigs/OSAX_Release_TotalTerminal_generated.xcconfig: -------------------------------------------------------------------------------- 1 | // A GENERATED FILE by bagen utility 2 | // more info: https://github.com/binaryage/badev 3 | // 4 | // !!! DO NOT EDIT IT BY HAND !!! 5 | // 6 | 7 | // 8 | // Common settings that should be enabled for every project 9 | // 10 | CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES 11 | CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES 12 | CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES 13 | CLANG_ENABLE_OBJC_ARC = YES 14 | CLANG_WARN_BOOL_CONVERSION = YES 15 | CLANG_WARN_CONSTANT_CONVERSION = YES 16 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 17 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES 18 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 19 | CLANG_WARN_EMPTY_BODY = YES 20 | CLANG_WARN_ENUM_CONVERSION = YES 21 | CLANG_WARN_INT_CONVERSION = YES 22 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO 23 | CLANG_WARN_OBJC_ROOT_CLASS = YES 24 | GCC_WARN_UNINITIALIZED_AUTOS = YES 25 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 26 | GCC_C_LANGUAGE_STANDARD = gnu99 27 | GCC_ENABLE_OBJC_EXCEPTIONS = YES 28 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES 29 | GCC_PRECOMPILE_PREFIX_HEADER = YES 30 | GCC_STRICT_ALIASING = YES 31 | GCC_THREADSAFE_STATICS = NO 32 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0 33 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 34 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES 35 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO 36 | GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES 37 | GCC_WARN_ABOUT_RETURN_TYPE = YES 38 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES 39 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES 40 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES 41 | GCC_WARN_MISSING_PARENTHESES = YES 42 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES 43 | GCC_WARN_UNINITIALIZED_AUTOS = YES 44 | GCC_WARN_UNUSED_FUNCTION = YES 45 | GCC_WARN_UNUSED_LABEL = YES 46 | GCC_WARN_UNUSED_VARIABLE = YES 47 | RUN_CLANG_STATIC_ANALYZER = NO 48 | TEST_AFTER_BUILD = NO 49 | ALWAYS_SEARCH_USER_PATHS = NO 50 | PRODUCT_NAME = TotalTerminal 51 | // 52 | // Base configuration for a Release build of any project 53 | // 54 | COPY_PHASE_STRIP = YES 55 | GCC_OPTIMIZATION_LEVEL = fast 56 | LLVM_LTO = YES 57 | ONLY_ACTIVE_ARCH = NO 58 | STRIP_INSTALLED_PRODUCT = YES 59 | // 60 | // Base configuration for all TotalFinder projects 61 | // 62 | MACOSX_DEPLOYMENT_TARGET = 10.9 63 | SDKROOT = macosx 64 | CLANG_CXX_LIBRARY = libc++ 65 | CLANG_CXX_LANGUAGE_STANDARD = c++0x 66 | CLANG_ENABLE_MODULES = YES 67 | GCC_WARN_UNINITIALIZED_AUTOS = YES 68 | GCC_WARN_UNUSED_VARIABLE = YES 69 | CLANG_WARN_EMPTY_BODY = YES 70 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 71 | GCC_WARN_ABOUT_RETURN_TYPE = YES 72 | COMBINE_HIDPI_IMAGES = YES 73 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 74 | INFOPLIST_FILE = TotalTerminal-Info.plist 75 | GCC_PRECOMPILE_PREFIX_HEADER = NO 76 | GCC_PREFIX_HEADER = TotalTerminal-Prefix.pch 77 | GCC_INCREASE_PRECOMPILED_HEADER_SHARING = NO 78 | // 79 | // Release mode additions to TotalFinder configs 80 | // 81 | GCC_SYMBOLS_PRIVATE_EXTERN = YES 82 | // 83 | // Base configuration for all TotalTerminal projects 84 | // 85 | MACOSX_DEPLOYMENT_TARGET = 10.9 86 | SDKROOT = macosx 87 | CLANG_CXX_LIBRARY = libc++ 88 | CLANG_CXX_LANGUAGE_STANDARD = c++0x 89 | CLANG_ENABLE_MODULES = YES 90 | GCC_WARN_UNINITIALIZED_AUTOS = YES 91 | GCC_WARN_UNUSED_VARIABLE = YES 92 | CLANG_WARN_EMPTY_BODY = YES 93 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 94 | GCC_WARN_ABOUT_RETURN_TYPE = YES 95 | COMBINE_HIDPI_IMAGES = YES 96 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 97 | INFOPLIST_FILE = TotalTerminal-Info.plist 98 | GCC_PRECOMPILE_PREFIX_HEADER = NO 99 | GCC_PREFIX_HEADER = TotalTerminal-Prefix.pch 100 | GCC_INCREASE_PRECOMPILED_HEADER_SHARING = NO 101 | // 102 | // Release mode additions to TotalFinder configs 103 | // 104 | // we don't want OSAX subsystem to treat our intermediate build folder as installed osax in the system 105 | // they use SpotLight or some similar search mechanism to look for all .osax in the system 106 | WRAPPER_EXTENSION = xaso 107 | // 108 | // Dynamic configuration collected from all sections above 109 | // 110 | WARNING_CFLAGS = -Wextra -Wself-assign -Wno-gcc-compat -Wno-unused-parameter -Wstrict-prototypes -Wunreachable-code -Wunused-member-function -Wuninitialized -Wsuper-class-method-mismatch -Warc -Warc-retain-cycles -Warc-unsafe-retained-assign -Warc-non-pod-memaccess -Wbind-to-temporary-copy -Wno-unused-variable -Wthread-safety -Wthread-safety-beta -Wthread-safety -Wthread-safety-beta 111 | GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1 NS_BLOCK_ASSERTIONS=1 112 | OTHER_LDFLAGS = -undefined dynamic_lookup -headerpad_max_install_names -undefined dynamic_lookup -headerpad_max_install_names -------------------------------------------------------------------------------- /OSAX.xcconfigs/OSAX_Debug_TotalTerminal_generated.xcconfig: -------------------------------------------------------------------------------- 1 | // A GENERATED FILE by bagen utility 2 | // more info: https://github.com/binaryage/badev 3 | // 4 | // !!! DO NOT EDIT IT BY HAND !!! 5 | // 6 | 7 | // 8 | // Common settings that should be enabled for every project 9 | // 10 | CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES 11 | CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES 12 | CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES 13 | CLANG_ENABLE_OBJC_ARC = YES 14 | CLANG_WARN_BOOL_CONVERSION = YES 15 | CLANG_WARN_CONSTANT_CONVERSION = YES 16 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 17 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES 18 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 19 | CLANG_WARN_EMPTY_BODY = YES 20 | CLANG_WARN_ENUM_CONVERSION = YES 21 | CLANG_WARN_INT_CONVERSION = YES 22 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO 23 | CLANG_WARN_OBJC_ROOT_CLASS = YES 24 | GCC_WARN_UNINITIALIZED_AUTOS = YES 25 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 26 | GCC_C_LANGUAGE_STANDARD = gnu99 27 | GCC_ENABLE_OBJC_EXCEPTIONS = YES 28 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES 29 | GCC_PRECOMPILE_PREFIX_HEADER = YES 30 | GCC_STRICT_ALIASING = YES 31 | GCC_THREADSAFE_STATICS = NO 32 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0 33 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 34 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES 35 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO 36 | GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES 37 | GCC_WARN_ABOUT_RETURN_TYPE = YES 38 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES 39 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES 40 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES 41 | GCC_WARN_MISSING_PARENTHESES = YES 42 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES 43 | GCC_WARN_UNINITIALIZED_AUTOS = YES 44 | GCC_WARN_UNUSED_FUNCTION = YES 45 | GCC_WARN_UNUSED_LABEL = YES 46 | GCC_WARN_UNUSED_VARIABLE = YES 47 | RUN_CLANG_STATIC_ANALYZER = NO 48 | TEST_AFTER_BUILD = NO 49 | ALWAYS_SEARCH_USER_PATHS = NO 50 | PRODUCT_NAME = TotalTerminal 51 | // 52 | // Base configuration for a Debug build of any project 53 | // 54 | COPY_PHASE_STRIP = NO 55 | GCC_OPTIMIZATION_LEVEL = 0 56 | LLVM_LTO = NO 57 | ONLY_ACTIVE_ARCH = YES 58 | STRIP_INSTALLED_PRODUCT = NO 59 | OTHER_CODE_SIGN_FLAGS = --timestamp=none 60 | // 61 | // Base configuration for all TotalFinder projects 62 | // 63 | MACOSX_DEPLOYMENT_TARGET = 10.9 64 | SDKROOT = macosx 65 | CLANG_CXX_LIBRARY = libc++ 66 | CLANG_CXX_LANGUAGE_STANDARD = c++0x 67 | CLANG_ENABLE_MODULES = YES 68 | GCC_WARN_UNINITIALIZED_AUTOS = YES 69 | GCC_WARN_UNUSED_VARIABLE = YES 70 | CLANG_WARN_EMPTY_BODY = YES 71 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 72 | GCC_WARN_ABOUT_RETURN_TYPE = YES 73 | COMBINE_HIDPI_IMAGES = YES 74 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 75 | INFOPLIST_FILE = TotalTerminal-Info.plist 76 | GCC_PRECOMPILE_PREFIX_HEADER = NO 77 | GCC_PREFIX_HEADER = TotalTerminal-Prefix.pch 78 | GCC_INCREASE_PRECOMPILED_HEADER_SHARING = NO 79 | // 80 | // Debug mode additions to TotalFinder configs 81 | // 82 | GCC_SYMBOLS_PRIVATE_EXTERN = YES 83 | // 84 | // Base configuration for all TotalTerminal projects 85 | // 86 | MACOSX_DEPLOYMENT_TARGET = 10.9 87 | SDKROOT = macosx 88 | CLANG_CXX_LIBRARY = libc++ 89 | CLANG_CXX_LANGUAGE_STANDARD = c++0x 90 | CLANG_ENABLE_MODULES = YES 91 | GCC_WARN_UNINITIALIZED_AUTOS = YES 92 | GCC_WARN_UNUSED_VARIABLE = YES 93 | CLANG_WARN_EMPTY_BODY = YES 94 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 95 | GCC_WARN_ABOUT_RETURN_TYPE = YES 96 | COMBINE_HIDPI_IMAGES = YES 97 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 98 | INFOPLIST_FILE = TotalTerminal-Info.plist 99 | GCC_PRECOMPILE_PREFIX_HEADER = NO 100 | GCC_PREFIX_HEADER = TotalTerminal-Prefix.pch 101 | GCC_INCREASE_PRECOMPILED_HEADER_SHARING = NO 102 | // 103 | // Debug mode additions to TotalFinder configs 104 | // 105 | // we don't want OSAX subsystem to treat our intermediate build folder as installed osax in the system 106 | // they use SpotLight or some similar search mechanism to look for all .osax in the system 107 | WRAPPER_EXTENSION = xaso 108 | // 109 | // Dynamic configuration collected from all sections above 110 | // 111 | WARNING_CFLAGS = -Wextra -Wself-assign -Wno-gcc-compat -Wno-unused-parameter -Wstrict-prototypes -Wunreachable-code -Wunused-member-function -Wuninitialized -Wsuper-class-method-mismatch -Warc -Warc-retain-cycles -Warc-unsafe-retained-assign -Warc-non-pod-memaccess -Wbind-to-temporary-copy -Wthread-safety -Wthread-safety-beta -Wthread-safety -Wthread-safety-beta 112 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 LOGGING_SUPPORT=1 113 | OTHER_CPLUSPLUSFLAGS = -ftrapv -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error 114 | OTHER_LDFLAGS = -undefined dynamic_lookup -headerpad_max_install_names -undefined dynamic_lookup -headerpad_max_install_names -------------------------------------------------------------------------------- /TTStandardVersionComparator.m: -------------------------------------------------------------------------------- 1 | // 2 | // TTStandardVersionComparator.m 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 12/21/07. 6 | // Copyright 2007 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TTStandardVersionComparator.h" 11 | 12 | @implementation TTStandardVersionComparator 13 | 14 | + (TTStandardVersionComparator*)defaultComparator { 15 | static TTStandardVersionComparator* defaultComparator = nil; 16 | if (defaultComparator == nil) 17 | defaultComparator = [[TTStandardVersionComparator alloc] init]; 18 | return defaultComparator; 19 | } 20 | 21 | typedef enum { 22 | kNumberType, 23 | kStringType, 24 | kPeriodType 25 | } SUCharacterType; 26 | 27 | - (SUCharacterType)typeOfCharacter:(NSString*)character { 28 | if ([character isEqualToString:@"."]) { 29 | return kPeriodType; 30 | } else if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[character characterAtIndex:0]]) { 31 | return kNumberType; 32 | } else { 33 | return kStringType; 34 | } 35 | } 36 | 37 | - (NSArray*)splitVersionString:(NSString*)version { 38 | NSString* character; 39 | NSMutableString* s; 40 | NSUInteger i, n; 41 | SUCharacterType oldType, newType; 42 | NSMutableArray* parts = [NSMutableArray array]; 43 | if ([version length] == 0) { 44 | // Nothing to do here 45 | return parts; 46 | } 47 | s = [[version substringToIndex:1] mutableCopy]; 48 | oldType = [self typeOfCharacter:s]; 49 | n = [version length] - 1; 50 | for (i = 1; i <= n; ++i) { 51 | character = [version substringWithRange:NSMakeRange(i, 1)]; 52 | newType = [self typeOfCharacter:character]; 53 | if (oldType != newType || oldType == kPeriodType) { 54 | // We've reached a new segment 55 | NSString* aPart = [[NSString alloc] initWithString:s]; 56 | [parts addObject:aPart]; 57 | [s setString:character]; 58 | } else { 59 | // Add character to string and continue 60 | [s appendString:character]; 61 | } 62 | oldType = newType; 63 | } 64 | 65 | // Add the last part onto the array 66 | [parts addObject:[NSString stringWithString:s]]; 67 | return parts; 68 | } 69 | 70 | - (NSComparisonResult)compareVersion:(NSString*)versionA toVersion:(NSString*)versionB 71 | { 72 | NSArray* partsA = [self splitVersionString:versionA]; 73 | NSArray* partsB = [self splitVersionString:versionB]; 74 | 75 | NSString* partA, *partB; 76 | NSUInteger i, n; 77 | int intA, intB; 78 | SUCharacterType typeA, typeB; 79 | 80 | n = MIN([partsA count], [partsB count]); 81 | for (i = 0; i < n; ++i) { 82 | partA = partsA[i]; 83 | partB = partsB[i]; 84 | 85 | typeA = [self typeOfCharacter:partA]; 86 | typeB = [self typeOfCharacter:partB]; 87 | 88 | // Compare types 89 | if (typeA == typeB) { 90 | // Same type; we can compare 91 | if (typeA == kNumberType) { 92 | intA = [partA intValue]; 93 | intB = [partB intValue]; 94 | if (intA > intB) { 95 | return NSOrderedDescending; 96 | } else if (intA < intB) { 97 | return NSOrderedAscending; 98 | } 99 | } else if (typeA == kStringType) { 100 | NSComparisonResult result = [partA compare:partB]; 101 | if (result != NSOrderedSame) { 102 | return result; 103 | } 104 | } 105 | } else { 106 | // Not the same type? Now we have to do some validity checking 107 | if (typeA != kStringType && typeB == kStringType) { 108 | // typeA wins 109 | return NSOrderedDescending; 110 | } else if (typeA == kStringType && typeB != kStringType) { 111 | // typeB wins 112 | return NSOrderedAscending; 113 | } else { 114 | // One is a number and the other is a period. The period is invalid 115 | if (typeA == kNumberType) { 116 | return NSOrderedDescending; 117 | } else { 118 | return NSOrderedAscending; 119 | } 120 | } 121 | } 122 | } 123 | // The versions are equal up to the point where they both still have parts 124 | // Lets check to see if one is larger than the other 125 | if ([partsA count] != [partsB count]) { 126 | // Yep. Lets get the next part of the larger 127 | // n holds the index of the part we want. 128 | NSString* missingPart; 129 | SUCharacterType missingType; 130 | NSComparisonResult shorterResult, largerResult; 131 | 132 | if ([partsA count] > [partsB count]) { 133 | missingPart = partsA[n]; 134 | shorterResult = NSOrderedAscending; 135 | largerResult = NSOrderedDescending; 136 | } else { 137 | missingPart = partsB[n]; 138 | shorterResult = NSOrderedDescending; 139 | largerResult = NSOrderedAscending; 140 | } 141 | 142 | missingType = [self typeOfCharacter:missingPart]; 143 | // Check the type 144 | if (missingType == kStringType) { 145 | // It's a string. Shorter version wins 146 | return shorterResult; 147 | } else { 148 | // It's a number/period. Larger version wins 149 | return largerResult; 150 | } 151 | } 152 | 153 | // The 2 strings are identical 154 | return NSOrderedSame; 155 | } 156 | 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /OSAX.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */; }; 11 | 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; }; 12 | D6ACBEA2117B7D5600F6691C /* TotalTerminalInjector.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6ACBE9E117B7D5600F6691C /* TotalTerminalInjector.mm */; }; 13 | D6ACBEA3117B7D5600F6691C /* TTStandardVersionComparator.m in Sources */ = {isa = PBXBuildFile; fileRef = D6ACBEA0117B7D5600F6691C /* TTStandardVersionComparator.m */; }; 14 | D6ACBEA5117B7D6100F6691C /* TotalTerminalInjector.sdef in Resources */ = {isa = PBXBuildFile; fileRef = D6ACBEA4117B7D6100F6691C /* TotalTerminalInjector.sdef */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 19 | 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; 20 | 8D576316048677EA00EA77CD /* TotalTerminal.xaso */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TotalTerminal.xaso; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 8D576317048677EA00EA77CD /* TotalTerminal-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TotalTerminal-Info.plist"; sourceTree = ""; }; 22 | D619108C1959C75400BA335F /* OSAX_Debug_TotalTerminal.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = OSAX_Debug_TotalTerminal.xcconfig; path = OSAX.xcconfigs/OSAX_Debug_TotalTerminal.xcconfig; sourceTree = ""; }; 23 | D619108D1959C75400BA335F /* OSAX_Release_TotalTerminal.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = OSAX_Release_TotalTerminal.xcconfig; path = OSAX.xcconfigs/OSAX_Release_TotalTerminal.xcconfig; sourceTree = ""; }; 24 | D6ACBE9E117B7D5600F6691C /* TotalTerminalInjector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TotalTerminalInjector.mm; sourceTree = ""; }; 25 | D6ACBE9F117B7D5600F6691C /* TTVersionComparisonProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTVersionComparisonProtocol.h; sourceTree = ""; }; 26 | D6ACBEA0117B7D5600F6691C /* TTStandardVersionComparator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTStandardVersionComparator.m; sourceTree = ""; }; 27 | D6ACBEA1117B7D5600F6691C /* TTStandardVersionComparator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTStandardVersionComparator.h; sourceTree = ""; }; 28 | D6ACBEA4117B7D6100F6691C /* TotalTerminalInjector.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = TotalTerminalInjector.sdef; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 8D576313048677EA00EA77CD /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 089C166AFE841209C02AAC07 /* OSAX */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | D60C69B8188A030400C0108B /* Configs */, 47 | 08FB77AFFE84173DC02AAC07 /* Source */, 48 | 089C167CFE841241C02AAC07 /* Resources */, 49 | 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */, 50 | 19C28FB6FE9D52B211CA2CBB /* Products */, 51 | ); 52 | indentWidth = 2; 53 | name = OSAX; 54 | sourceTree = ""; 55 | tabWidth = 2; 56 | }; 57 | 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */, 61 | ); 62 | name = "External Frameworks and Libraries"; 63 | sourceTree = ""; 64 | }; 65 | 089C167CFE841241C02AAC07 /* Resources */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | D6ACBEA4117B7D6100F6691C /* TotalTerminalInjector.sdef */, 69 | 8D576317048677EA00EA77CD /* TotalTerminal-Info.plist */, 70 | 8D5B49A704867FD3000E48DA /* InfoPlist.strings */, 71 | ); 72 | name = Resources; 73 | sourceTree = ""; 74 | }; 75 | 08FB77AFFE84173DC02AAC07 /* Source */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | D6ACBE9E117B7D5600F6691C /* TotalTerminalInjector.mm */, 79 | D6ACBE9F117B7D5600F6691C /* TTVersionComparisonProtocol.h */, 80 | D6ACBEA0117B7D5600F6691C /* TTStandardVersionComparator.m */, 81 | D6ACBEA1117B7D5600F6691C /* TTStandardVersionComparator.h */, 82 | ); 83 | name = Source; 84 | sourceTree = ""; 85 | }; 86 | 19C28FB6FE9D52B211CA2CBB /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 8D576316048677EA00EA77CD /* TotalTerminal.xaso */, 90 | ); 91 | name = Products; 92 | sourceTree = ""; 93 | }; 94 | D60C69B8188A030400C0108B /* Configs */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | D619108C1959C75400BA335F /* OSAX_Debug_TotalTerminal.xcconfig */, 98 | D619108D1959C75400BA335F /* OSAX_Release_TotalTerminal.xcconfig */, 99 | ); 100 | name = Configs; 101 | sourceTree = ""; 102 | }; 103 | /* End PBXGroup section */ 104 | 105 | /* Begin PBXNativeTarget section */ 106 | 8D57630D048677EA00EA77CD /* TotalTerminal */ = { 107 | isa = PBXNativeTarget; 108 | buildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget "TotalTerminal" */; 109 | buildPhases = ( 110 | 8D57630F048677EA00EA77CD /* Resources */, 111 | 8D576311048677EA00EA77CD /* Sources */, 112 | 8D576313048677EA00EA77CD /* Frameworks */, 113 | ); 114 | buildRules = ( 115 | ); 116 | dependencies = ( 117 | ); 118 | name = TotalTerminal; 119 | productInstallPath = "$(HOME)/Library/Bundles"; 120 | productName = OSAX; 121 | productReference = 8D576316048677EA00EA77CD /* TotalTerminal.xaso */; 122 | productType = "com.apple.product-type.bundle"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 089C1669FE841209C02AAC07 /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | BuildIndependentTargetsInParallel = YES; 131 | LastUpgradeCheck = 0710; 132 | ORGANIZATIONNAME = BinaryAge; 133 | }; 134 | buildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject "OSAX" */; 135 | compatibilityVersion = "Xcode 3.2"; 136 | developmentRegion = English; 137 | hasScannedForEncodings = 1; 138 | knownRegions = ( 139 | en, 140 | ); 141 | mainGroup = 089C166AFE841209C02AAC07 /* OSAX */; 142 | projectDirPath = ""; 143 | projectRoot = ""; 144 | targets = ( 145 | 8D57630D048677EA00EA77CD /* TotalTerminal */, 146 | ); 147 | }; 148 | /* End PBXProject section */ 149 | 150 | /* Begin PBXResourcesBuildPhase section */ 151 | 8D57630F048677EA00EA77CD /* Resources */ = { 152 | isa = PBXResourcesBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */, 156 | D6ACBEA5117B7D6100F6691C /* TotalTerminalInjector.sdef in Resources */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXResourcesBuildPhase section */ 161 | 162 | /* Begin PBXSourcesBuildPhase section */ 163 | 8D576311048677EA00EA77CD /* Sources */ = { 164 | isa = PBXSourcesBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | D6ACBEA2117B7D5600F6691C /* TotalTerminalInjector.mm in Sources */, 168 | D6ACBEA3117B7D5600F6691C /* TTStandardVersionComparator.m in Sources */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXSourcesBuildPhase section */ 173 | 174 | /* Begin PBXVariantGroup section */ 175 | 8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = { 176 | isa = PBXVariantGroup; 177 | children = ( 178 | 089C167EFE841241C02AAC07 /* English */, 179 | ); 180 | name = InfoPlist.strings; 181 | sourceTree = ""; 182 | }; 183 | /* End PBXVariantGroup section */ 184 | 185 | /* Begin XCBuildConfiguration section */ 186 | 1DEB911B08733D790010E9CD /* Debug */ = { 187 | isa = XCBuildConfiguration; 188 | baseConfigurationReference = D619108C1959C75400BA335F /* OSAX_Debug_TotalTerminal.xcconfig */; 189 | buildSettings = { 190 | WRAPPER_EXTENSION = xaso; 191 | }; 192 | name = Debug; 193 | }; 194 | 1DEB911C08733D790010E9CD /* Release */ = { 195 | isa = XCBuildConfiguration; 196 | baseConfigurationReference = D619108D1959C75400BA335F /* OSAX_Release_TotalTerminal.xcconfig */; 197 | buildSettings = { 198 | WRAPPER_EXTENSION = xaso; 199 | }; 200 | name = Release; 201 | }; 202 | 1DEB911F08733D790010E9CD /* Debug */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | }; 206 | name = Debug; 207 | }; 208 | 1DEB912008733D790010E9CD /* Release */ = { 209 | isa = XCBuildConfiguration; 210 | buildSettings = { 211 | }; 212 | name = Release; 213 | }; 214 | /* End XCBuildConfiguration section */ 215 | 216 | /* Begin XCConfigurationList section */ 217 | 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget "TotalTerminal" */ = { 218 | isa = XCConfigurationList; 219 | buildConfigurations = ( 220 | 1DEB911B08733D790010E9CD /* Debug */, 221 | 1DEB911C08733D790010E9CD /* Release */, 222 | ); 223 | defaultConfigurationIsVisible = 0; 224 | defaultConfigurationName = Release; 225 | }; 226 | 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject "OSAX" */ = { 227 | isa = XCConfigurationList; 228 | buildConfigurations = ( 229 | 1DEB911F08733D790010E9CD /* Debug */, 230 | 1DEB912008733D790010E9CD /* Release */, 231 | ); 232 | defaultConfigurationIsVisible = 0; 233 | defaultConfigurationName = Release; 234 | }; 235 | /* End XCConfigurationList section */ 236 | }; 237 | rootObject = 089C1669FE841209C02AAC07 /* Project object */; 238 | } 239 | -------------------------------------------------------------------------------- /TotalTerminalInjector.mm: -------------------------------------------------------------------------------- 1 | #import "TTStandardVersionComparator.h" 2 | 3 | #define EXPORT extern "C" __attribute__((visibility("default"))) 4 | 5 | #define TOTALTERMINAL_STANDARD_INSTALL_LOCATION "/Applications/TotalTerminal.app" 6 | #define TERMINAL_MIN_TESTED_VERSION @"0" 7 | #define TERMINAL_MAX_TESTED_VERSION @"361" // 10.11.1 GM (10.11.1-15B17c) 8 | #define TERMINAL_UNSUPPORTED_VERSION @"" 9 | #define TOTALTERMINAL_INJECTED_NOTIFICATION @"TotalTerminalInjectedNotification" 10 | #define TOTALTERMINAL_FAILED_INJECTION_NOTIFICATION @"TotalTerminalFailedInjectionNotification" 11 | 12 | static NSString* globalLock = @"I'm the global lock to prevent concruent handler executions"; 13 | static bool alreadyLoaded = false; 14 | static Class gPrincipalClass = nil; 15 | 16 | @interface TotalTerminal : NSObject { 17 | } 18 | - (BOOL)isHidden; 19 | - (void)showVisor:(BOOL)fast; 20 | - (void)hideVisor:(BOOL)fast; 21 | @end 22 | 23 | // SIMBL-compatible interface 24 | @interface TotalTerminalPlugin : NSObject 25 | + (void)install; 26 | + (TotalTerminal*) sharedInstance; 27 | @end 28 | 29 | // just a dummy class for locating our bundle 30 | @interface TotalTerminalInjector : NSObject 31 | @end 32 | @implementation TotalTerminalInjector 33 | @end 34 | 35 | static void broadcastNotification(NSString* notification) { 36 | pid_t pid = [[NSProcessInfo processInfo] processIdentifier]; 37 | 38 | [[NSDistributedNotificationCenter defaultCenter] postNotificationName:notification 39 | object:[[NSBundle mainBundle] bundleIdentifier] 40 | userInfo:@{@"pid" : @(pid)} 41 | deliverImmediately:YES]; 42 | } 43 | 44 | static void broadcastSucessfulInjection() { broadcastNotification(TOTALTERMINAL_INJECTED_NOTIFICATION); } 45 | 46 | static void broadcastUnsucessfulInjection() { broadcastNotification(TOTALTERMINAL_FAILED_INJECTION_NOTIFICATION); } 47 | 48 | static OSErr AEPutParamString(AppleEvent* event, AEKeyword keyword, NSString* string) { 49 | UInt8* textBuf; 50 | CFIndex length, maxBytes, actualBytes; 51 | length = CFStringGetLength((CFStringRef)string); 52 | maxBytes = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); 53 | textBuf = (UInt8*)malloc(maxBytes); 54 | if (textBuf) { 55 | CFStringGetBytes((CFStringRef)string, CFRangeMake(0, length), kCFStringEncodingUTF8, 0, true, (UInt8*)textBuf, maxBytes, &actualBytes); 56 | OSErr err = AEPutParamPtr(event, keyword, typeUTF8Text, textBuf, actualBytes); 57 | free(textBuf); 58 | return err; 59 | } else { 60 | return memFullErr; 61 | } 62 | } 63 | 64 | static void reportError(AppleEvent* reply, NSString* msg) { 65 | NSLog(@"TotalTerminalInjector: %@", msg); 66 | AEPutParamString(reply, keyErrorString, msg); 67 | } 68 | 69 | static void returnBool(AppleEvent* reply, BOOL value, AEKeyword keyword = keyDirectObject) { 70 | AEPutParamDesc(reply, keyword, [[NSAppleEventDescriptor descriptorWithBoolean:value] aeDesc]); 71 | } 72 | 73 | // this is just a sanity checking to catch missing methods early 74 | static int performSelfCheck() { 75 | if (!gPrincipalClass) { 76 | return 1; 77 | } 78 | 79 | if (![gPrincipalClass respondsToSelector:@selector(sharedInstance)]) { 80 | return 2; 81 | } 82 | 83 | TotalTerminal* instance = [gPrincipalClass sharedInstance]; 84 | if (!instance) { 85 | return 3; 86 | } 87 | 88 | if (![instance respondsToSelector:@selector(isHidden)]) { 89 | return 4; 90 | } 91 | 92 | if (![instance respondsToSelector:@selector(showVisor:)]) { 93 | return 5; 94 | } 95 | 96 | if (![instance respondsToSelector:@selector(hideVisor:)]) { 97 | return 6; 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | EXPORT OSErr handleInitEvent(const AppleEvent* ev, AppleEvent* reply, long refcon) { 104 | @synchronized(globalLock) { 105 | @autoreleasepool { 106 | NSBundle* injectorBundle = [NSBundle bundleForClass:[TotalTerminalInjector class]]; 107 | NSString* injectorVersion = [injectorBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; 108 | if (!injectorVersion || ![injectorVersion isKindOfClass:[NSString class]]) { 109 | reportError(reply, [NSString stringWithFormat:@"Unable to determine TotalTerminalInjector version!"]); 110 | return 7; 111 | } 112 | 113 | NSLog(@"TotalTerminalInjector v%@ received init event", injectorVersion); 114 | 115 | NSString* bundleName = @"TotalTerminal"; 116 | NSString* targetAppName = @"Terminal"; 117 | NSString* maxVersion = TERMINAL_MAX_TESTED_VERSION; 118 | NSString* minVersion = TERMINAL_MIN_TESTED_VERSION; 119 | 120 | if (alreadyLoaded) { 121 | NSLog(@"TotalTerminalInjector: TotalTerminal has been already loaded. Ignoring this request."); 122 | return noErr; 123 | } 124 | @try { 125 | NSBundle* terminalBundle = [NSBundle mainBundle]; 126 | if (!terminalBundle) { 127 | reportError(reply, [NSString stringWithFormat:@"Unable to locate main Terminal bundle!"]); 128 | return 4; 129 | } 130 | 131 | NSString* terminalVersion = [terminalBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; 132 | if (!terminalVersion || ![terminalVersion isKindOfClass:[NSString class]]) { 133 | reportError(reply, [NSString stringWithFormat:@"Unable to determine Terminal version!"]); 134 | return 5; 135 | } 136 | 137 | // some versions are explicitely unsupported 138 | if (([TERMINAL_UNSUPPORTED_VERSION length] > 0) && ([terminalVersion rangeOfString:TERMINAL_UNSUPPORTED_VERSION].length > 0)) { 139 | NSUserNotification* notification = [[NSUserNotification alloc] init]; 140 | notification.title = [NSString stringWithFormat:@"TotalTerminal hasn't been tested with Terminal version %@", terminalVersion]; 141 | notification.informativeText = [NSString stringWithFormat:@"Please visit https://totalterminal.binaryage.com for more info on our progress."]; 142 | [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; 143 | } 144 | 145 | // warn about non-tested minor versions into the log only 146 | NSString* supressKey = @"TotalTerminalSuppressTerminalVersionCheck"; 147 | if (![[NSUserDefaults standardUserDefaults] boolForKey:supressKey]) { 148 | TTStandardVersionComparator* comparator = [TTStandardVersionComparator defaultComparator]; 149 | if (([comparator compareVersion:terminalVersion toVersion:maxVersion] == NSOrderedDescending) || 150 | ([comparator compareVersion:terminalVersion toVersion:minVersion] == NSOrderedAscending)) { 151 | NSLog(@"You have %@ version %@. But %@ was properly tested only with %@ versions in range %@ - %@.", 152 | targetAppName, 153 | terminalVersion, 154 | bundleName, 155 | targetAppName, 156 | minVersion, 157 | maxVersion); 158 | } 159 | } 160 | 161 | NSBundle* totalTerminalInjectorBundle = [NSBundle bundleForClass:[TotalTerminalInjector class]]; 162 | NSString* totalTerminalLocation = [totalTerminalInjectorBundle pathForResource:bundleName ofType:@"bundle"]; 163 | NSBundle* pluginBundle = [NSBundle bundleWithPath:totalTerminalLocation]; 164 | if (!pluginBundle) { 165 | reportError(reply, [NSString stringWithFormat:@"Unable to create bundle from path: %@ [%@]", totalTerminalLocation, totalTerminalInjectorBundle]); 166 | return 2; 167 | } 168 | 169 | NSLog(@"TotalTerminalInjector: Installing %@ from %@", bundleName, totalTerminalLocation); 170 | NSError* error; 171 | if (![pluginBundle loadAndReturnError:&error]) { 172 | reportError(reply, [NSString stringWithFormat:@"Unable to load bundle from path: %@ error: %@ [code=%ld]", totalTerminalLocation, [error localizedDescription], (long)[error code]]); 173 | return 6; 174 | } 175 | 176 | gPrincipalClass = [pluginBundle principalClass]; 177 | if (!gPrincipalClass) { 178 | reportError(reply, [NSString stringWithFormat:@"Unable to retrieve principalClass for bundle: %@", pluginBundle]); 179 | return 3; 180 | } 181 | 182 | if (![gPrincipalClass respondsToSelector:@selector(install)]) { 183 | reportError(reply, [NSString stringWithFormat:@"TotalTerminal's principal class does not implement 'install' method!"]); 184 | return 7; 185 | } 186 | 187 | [gPrincipalClass install]; 188 | 189 | int selfCheckCode = performSelfCheck(); 190 | if (selfCheckCode) { 191 | reportError(reply, [NSString stringWithFormat:@"Self-check failed with code %d", selfCheckCode]); 192 | return 10; 193 | } 194 | 195 | alreadyLoaded = true; 196 | broadcastSucessfulInjection(); 197 | 198 | return noErr; 199 | } 200 | @catch (NSException* exception) { 201 | reportError(reply, [NSString stringWithFormat:@"Failed to load %@ with exception: %@", bundleName, exception]); 202 | broadcastUnsucessfulInjection(); // stops subsequent attempts 203 | } 204 | return 1; 205 | } 206 | } 207 | } 208 | 209 | EXPORT OSErr handleCheckEvent(const AppleEvent* ev, AppleEvent* reply, long refcon) { 210 | @synchronized(globalLock) { 211 | @autoreleasepool { 212 | if (alreadyLoaded) { 213 | return noErr; 214 | } 215 | reportError(reply, @"TotalTerminal not loaded"); 216 | return 1; 217 | } 218 | } 219 | } 220 | 221 | typedef OSErr(^commandBlock)(TotalTerminal* totalTerminal); 222 | 223 | OSErr executeCommand(commandBlock command, const AppleEvent* ev, AppleEvent* reply, long refcon) { 224 | @synchronized(globalLock) { 225 | @autoreleasepool { 226 | if (!gPrincipalClass) { 227 | reportError(reply, [NSString stringWithFormat:@"TotalTerminal not present"]); 228 | return 150; 229 | } 230 | 231 | TotalTerminal* instance = [gPrincipalClass sharedInstance]; 232 | if (!instance) { 233 | reportError(reply, [NSString stringWithFormat:@"Unable to retrieve TotalTerminal instance"]); 234 | return 151; 235 | } 236 | 237 | return command(instance); 238 | } 239 | } 240 | } 241 | 242 | EXPORT OSErr handleShowVisorEvent(const AppleEvent* ev, AppleEvent* reply, long refcon) { 243 | commandBlock command = ^OSErr(TotalTerminal* totalTerminal) { 244 | [totalTerminal showVisor:NO]; 245 | return noErr; 246 | }; 247 | 248 | return executeCommand(command, ev, reply, refcon); 249 | } 250 | 251 | EXPORT OSErr handleHideVisorEvent(const AppleEvent* ev, AppleEvent* reply, long refcon) { 252 | commandBlock command = ^OSErr(TotalTerminal* totalTerminal) { 253 | [totalTerminal hideVisor:NO]; 254 | return noErr; 255 | }; 256 | 257 | return executeCommand(command, ev, reply, refcon); 258 | } 259 | 260 | EXPORT OSErr handleVisorHiddenEvent(const AppleEvent* ev, AppleEvent* reply, long refcon) { 261 | commandBlock command = ^OSErr(TotalTerminal* totalTerminal) { 262 | BOOL answer = [totalTerminal isHidden]; 263 | returnBool(reply, answer); 264 | return noErr; 265 | }; 266 | 267 | return executeCommand(command, ev, reply, refcon); 268 | } 269 | --------------------------------------------------------------------------------