From 195d23739233c48c901b66cbb57a50996d15eae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Walsh?= Date: Mon, 17 Nov 2008 23:48:16 +0000 Subject: [PATCH] Initial commit --- .gitignore | 6 + Info.plist | 37 +++ JRSwizzle.h | 13 + JRSwizzle.m | 115 ++++++++ TerminalTabSwitching.m | 63 ++++ .../project.pbxproj | 271 ++++++++++++++++++ TerminalTabSwitching_Prefix.pch | 7 + 7 files changed, 512 insertions(+) create mode 100644 .gitignore create mode 100644 Info.plist create mode 100644 JRSwizzle.h create mode 100644 JRSwizzle.m create mode 100644 TerminalTabSwitching.m create mode 100644 TerminalTabSwitching.xcodeproj/project.pbxproj create mode 100644 TerminalTabSwitching_Prefix.pch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..01e1532 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +build +*.xcodeproj/*.pbxuser +*.xcodeproj/*.perspectivev3 +*.xcodeproj/*.mode1v3 +*.xcodeproj/*.tm_build_errors +*.tmproj diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..c069fa8 --- /dev/null +++ b/Info.plist @@ -0,0 +1,37 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleIconFile + + CFBundleIdentifier + sh.ciaranwal.terminaltabswitching + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + TerminalTabSwitching + SIMBLTargetApplications + + + BundleIdentifier + com.apple.Terminal + MaxBundleVersion + 240 + MinBundleVersion + 237 + + + + diff --git a/JRSwizzle.h b/JRSwizzle.h new file mode 100644 index 0000000..e69e7a3 --- /dev/null +++ b/JRSwizzle.h @@ -0,0 +1,13 @@ +/******************************************************************************* + JRSwizzle.h + Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: + Some rights reserved: + + ***************************************************************************/ + +#import + +@interface NSObject (JRSwizzle) ++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_; ++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_; +@end diff --git a/JRSwizzle.m b/JRSwizzle.m new file mode 100644 index 0000000..80149f9 --- /dev/null +++ b/JRSwizzle.m @@ -0,0 +1,115 @@ +/******************************************************************************* + JRSwizzle.m + Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: + Some rights reserved: + + ***************************************************************************/ + +#import "JRSwizzle.h" +#import + +#define SetNSError(ERROR_VAR, FORMAT,...) \ + if (ERROR_VAR) { \ + NSString *errStr = [@"+[NSObject(JRSwizzle) jr_swizzleMethod:withMethod:error:]: " stringByAppendingFormat:FORMAT,##__VA_ARGS__]; \ + *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \ + code:-1 \ + userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \ + } + +@implementation NSObject (JRSwizzle) + ++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ { +#if OBJC_API_VERSION >= 2 + Method origMethod = class_getInstanceMethod(self, origSel_); + if (!origMethod) { + SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); + return NO; + } + + Method altMethod = class_getInstanceMethod(self, altSel_); + if (!altMethod) { + SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); + return NO; + } + + class_addMethod(self, + origSel_, + class_getMethodImplementation(self, origSel_), + method_getTypeEncoding(origMethod)); + class_addMethod(self, + altSel_, + class_getMethodImplementation(self, altSel_), + method_getTypeEncoding(altMethod)); + + method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_)); + return YES; +#else + // Scan for non-inherited methods. + Method directOriginalMethod = NULL, directAlternateMethod = NULL; + + void *iterator = NULL; + struct objc_method_list *mlist = class_nextMethodList(self, &iterator); + while (mlist) { + int method_index = 0; + for (; method_index < mlist->method_count; method_index++) { + if (mlist->method_list[method_index].method_name == origSel_) { + assert(!directOriginalMethod); + directOriginalMethod = &mlist->method_list[method_index]; + } + if (mlist->method_list[method_index].method_name == altSel_) { + assert(!directAlternateMethod); + directAlternateMethod = &mlist->method_list[method_index]; + } + } + mlist = class_nextMethodList(self, &iterator); + } + + // If either method is inherited, copy it up to the target class to make it non-inherited. + if (!directOriginalMethod || !directAlternateMethod) { + Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL; + if (!directOriginalMethod) { + inheritedOriginalMethod = class_getInstanceMethod(self, origSel_); + if (!inheritedOriginalMethod) { + SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); + return NO; + } + } + if (!directAlternateMethod) { + inheritedAlternateMethod = class_getInstanceMethod(self, altSel_); + if (!inheritedAlternateMethod) { + SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); + return NO; + } + } + + int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1; + struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1))); + hoisted_method_list->method_count = hoisted_method_count; + Method hoisted_method = hoisted_method_list->method_list; + + if (!directOriginalMethod) { + bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method)); + directOriginalMethod = hoisted_method++; + } + if (!directAlternateMethod) { + bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method)); + directAlternateMethod = hoisted_method; + } + class_addMethods(self, hoisted_method_list); + } + + // Swizzle. + IMP temp = directOriginalMethod->method_imp; + directOriginalMethod->method_imp = directAlternateMethod->method_imp; + directAlternateMethod->method_imp = temp; + + return YES; +#endif +} + ++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ { + assert(0); + return NO; +} + +@end diff --git a/TerminalTabSwitching.m b/TerminalTabSwitching.m new file mode 100644 index 0000000..ab38b34 --- /dev/null +++ b/TerminalTabSwitching.m @@ -0,0 +1,63 @@ +#import "JRSwizzle.h" + +@implementation NSWindowController (Mine) +- (void)updateTabListMenu +{ + NSMenu* windowsMenu = [[NSApplication sharedApplication] windowsMenu]; + + for(NSMenuItem* menuItem in [windowsMenu itemArray]) + { + if([menuItem action] == @selector(selectRepresentedTabViewItem:)) + [windowsMenu removeItem:menuItem]; + } + + NSArray* tabViewItems = [[self valueForKey:@"tabView"] tabViewItems]; + for(size_t tabIndex = 0; tabIndex < [tabViewItems count]; ++tabIndex) + { + NSString* keyEquivalent = (tabIndex < 10) ? [NSString stringWithFormat:@"%d", (tabIndex+1)%10] : @""; + NSTabViewItem* tabViewItem = [tabViewItems objectAtIndex:tabIndex]; + NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:[tabViewItem label] + action:@selector(selectRepresentedTabViewItem:) + keyEquivalent:keyEquivalent]; + [menuItem setRepresentedObject:tabViewItem]; + [windowsMenu addItem:menuItem]; + [menuItem release]; + } +} + +- (void)TerminalTabSwitching_windowDidBecomeMain:(id)fp8; +{ + [self TerminalTabSwitching_windowDidBecomeMain:fp8]; + [self updateTabListMenu]; +} + +- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView*)aTabView +{ + [self updateTabListMenu]; +} + +- (void)TerminalTabSwitching_awakeFromNib; +{ + [[NSApplication sharedApplication] removeWindowsItem:[self window]]; + [[self window] setExcludedFromWindowsMenu:YES]; + [self TerminalTabSwitching_awakeFromNib]; +} + +- (void)selectRepresentedTabViewItem:(NSMenuItem*)item +{ + NSTabViewItem* tabViewItem = [item representedObject]; + [[tabViewItem tabView] selectTabViewItem:tabViewItem]; +} +@end + +@interface TerminalTabSwitching : NSObject +@end + +@implementation TerminalTabSwitching ++ (void)load +{ + [[[NSApplication sharedApplication] windowsMenu] addItem:[NSMenuItem separatorItem]]; + [NSClassFromString(@"TTWindowController") jr_swizzleMethod:@selector(windowDidBecomeMain:) withMethod:@selector(TerminalTabSwitching_windowDidBecomeMain:) error:NULL]; + [NSClassFromString(@"TTWindowController") jr_swizzleMethod:@selector(awakeFromNib) withMethod:@selector(TerminalTabSwitching_awakeFromNib) error:NULL]; +} +@end diff --git a/TerminalTabSwitching.xcodeproj/project.pbxproj b/TerminalTabSwitching.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1aa5925 --- /dev/null +++ b/TerminalTabSwitching.xcodeproj/project.pbxproj @@ -0,0 +1,271 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 44; + objects = { + +/* Begin PBXBuildFile section */ + 8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; }; + 91151C500CD8DD5300E72F1F /* TerminalTabSwitching.m in Sources */ = {isa = PBXBuildFile; fileRef = 91151C4F0CD8DD5300E72F1F /* TerminalTabSwitching.m */; }; + 912D2A9B0CD9156B00EB7419 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 912D2A9A0CD9156B00EB7419 /* JRSwizzle.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 32DBCF630370AF2F00C91783 /* TerminalTabSwitching_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TerminalTabSwitching_Prefix.pch; sourceTree = ""; }; + 8D5B49B6048680CD000E48DA /* TerminalTabSwitching.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TerminalTabSwitching.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 91151C4F0CD8DD5300E72F1F /* TerminalTabSwitching.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TerminalTabSwitching.m; sourceTree = ""; }; + 912D2A9A0CD9156B00EB7419 /* JRSwizzle.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = ""; }; + D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D5B49B3048680CD000E48DA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* Blurminal */ = { + isa = PBXGroup; + children = ( + 08FB77AFFE84173DC02AAC07 /* Classes */, + 32C88E010371C26100C91783 /* Other Sources */, + 089C167CFE841241C02AAC07 /* Resources */, + 089C1671FE841209C02AAC07 /* Frameworks and Libraries */, + 19C28FB8FE9D52D311CA2CBB /* Products */, + ); + name = Blurminal; + sourceTree = ""; + }; + 089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */, + 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */, + ); + name = "Frameworks and Libraries"; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8D5B49B7048680CD000E48DA /* Info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77AFFE84173DC02AAC07 /* Classes */ = { + isa = PBXGroup; + children = ( + 91151C4F0CD8DD5300E72F1F /* TerminalTabSwitching.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 089C167FFE841241C02AAC07 /* AppKit.framework */, + D2F7E65807B2D6F200F64583 /* CoreData.framework */, + 089C1672FE841209C02AAC07 /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FB8FE9D52D311CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D5B49B6048680CD000E48DA /* TerminalTabSwitching.bundle */, + ); + name = Products; + sourceTree = ""; + }; + 32C88E010371C26100C91783 /* Other Sources */ = { + isa = PBXGroup; + children = ( + 912D2A9A0CD9156B00EB7419 /* JRSwizzle.m */, + 32DBCF630370AF2F00C91783 /* TerminalTabSwitching_Prefix.pch */, + ); + name = "Other Sources"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D5B49AC048680CD000E48DA /* TerminalTabSwitching */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "TerminalTabSwitching" */; + buildPhases = ( + 8D5B49AF048680CD000E48DA /* Resources */, + 8D5B49B1048680CD000E48DA /* Sources */, + 8D5B49B3048680CD000E48DA /* Frameworks */, + 912D2AA50CD919EB00EB7419 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TerminalTabSwitching; + productInstallPath = "$(HOME)/Library/Bundles"; + productName = Blurminal; + productReference = 8D5B49B6048680CD000E48DA /* TerminalTabSwitching.bundle */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "TerminalTabSwitching" */; + compatibilityVersion = "Xcode 3.0"; + hasScannedForEncodings = 1; + mainGroup = 089C166AFE841209C02AAC07 /* Blurminal */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D5B49AC048680CD000E48DA /* TerminalTabSwitching */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D5B49AF048680CD000E48DA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 912D2AA50CD919EB00EB7419 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p \"$HOME/Library/Application Support/SIMBL/PlugIns\"\ncp -pR \"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\" \"$HOME/Library/Application Support/SIMBL/PlugIns\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D5B49B1048680CD000E48DA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 91151C500CD8DD5300E72F1F /* TerminalTabSwitching.m in Sources */, + 912D2A9B0CD9156B00EB7419 /* JRSwizzle.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB913B08733D840010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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 = TerminalTabSwitching_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + PRODUCT_NAME = TerminalTabSwitching; + WRAPPER_EXTENSION = bundle; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB913C08733D840010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = TerminalTabSwitching_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + PRODUCT_NAME = TerminalTabSwitching; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 1DEB913F08733D840010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Debug; + }; + 1DEB914008733D840010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "TerminalTabSwitching" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB913B08733D840010E9CD /* Debug */, + 1DEB913C08733D840010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "TerminalTabSwitching" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB913F08733D840010E9CD /* Debug */, + 1DEB914008733D840010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/TerminalTabSwitching_Prefix.pch b/TerminalTabSwitching_Prefix.pch new file mode 100644 index 0000000..a266929 --- /dev/null +++ b/TerminalTabSwitching_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'TerminalColours' target in the 'TerminalColours' project. +// + +#ifdef __OBJC__ + #import +#endif