/
FinderExt.m
154 lines (127 loc) · 4.95 KB
/
FinderExt.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//
// FinderInj.m
// FinderMenu
//
// Created by Alexey Zhuchkov on 10/21/12.
// Copyright (c) 2012 InfiniteLabs. All rights reserved.
//
#import "FinderExt.h"
#import <objc/runtime.h>
#import "Finder.h"
#import "TFENodeHelper.h"
static TFENodeHelper *gNodeHelper;
// Auxiliary class to execute menu actions
@interface MenuItemTarget : NSObject {
@private
NSArray *_files;
}
- (id)initWithNodes:(const struct TFENodeVector *)vector;
- (void)sayHello:(id)sender;
- (void)sayGoodbye:(id)sender;
@end
@implementation MenuItemTarget
- (id)initWithNodes:(const struct TFENodeVector *)vector {
self = [super init];
if (self) {
_files = [[gNodeHelper arrayForNodeVector:vector] retain];
}
return self;
}
- (void)dealloc
{
[_files release];
[super dealloc];
}
- (void)sayMessage:(NSString *)title {
[[NSAlert alertWithMessageText:title
defaultButton:nil
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"Files: %@", _files] runModal];
[self release];
}
- (void)sayHello:(id)sender { [self sayMessage:@"Hello"]; }
- (void)sayGoodbye:(id)sender { [self sayMessage:@"Goodbye"]; }
@end
/**
* Renames the selector for a given method.
* Searches for a method with origSEL and reassigned overrideSEL to that
* implementation.
* http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html
*/
static void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL)
{
Method origMethod = class_getInstanceMethod(c, origSEL);
Method overrideMethod = class_getInstanceMethod(c, overrideSEL);
NSLog(@"orig=%p, override=%p", origMethod, overrideMethod);
if(class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, overrideMethod);
}
}
static void OverrideClass(const char *name, SEL origSEL, Method overrideMethod) {
Class c = objc_getClass(name);
if (c != nil) {
// add override method to target class
class_addMethod(c,
method_getName(overrideMethod),
method_getImplementation(overrideMethod),
method_getTypeEncoding(overrideMethod));
// swizzle methods
MethodSwizzle(c, origSEL, method_getName(overrideMethod));
NSLog(@"Method 'menuForEvent:' overriden in class %s", name);
} else {
NSLog(@"Class %s not found to override", name);
}
}
@implementation FinderExt
+ (void)load {
// Setup logging
// Write log file to ~/FinderExt.log
const char* logFilePath = [[NSHomeDirectory() stringByAppendingPathComponent:@"FinderExt.log"] UTF8String];
freopen(logFilePath, "a", stdout);
freopen(logFilePath, "a", stderr);
NSLog(@"Main bundle: %@", [[NSBundle mainBundle] bundleIdentifier]);
// Create helper object
gNodeHelper = [[TFENodeHelper alloc] init];
if (gNodeHelper == nil) {
NSLog(@"Failed to instantiate 'TFENodeHelper' class");
return;
}
Method method = class_getInstanceMethod(self, @selector(override_configureWithNodes:browserController:container:));
OverrideClass("TContextMenu", @selector(configureWithNodes:browserController:container:), method);
NSLog(@"FinderExt load is complete");
}
- (void)override_configureWithNodes:(const struct TFENodeVector *)vector
browserController:(id)browserController
container:(BOOL)container {
[self override_configureWithNodes:vector browserController:browserController container:container];
NSMenu *contextMenu = (NSMenu *)self;
// Find first separator to insert menu after it
NSInteger index;
for (index = 1 /* 0 is always separator */; index < [contextMenu numberOfItems]; ++index) {
if ([[contextMenu itemAtIndex:index] isSeparatorItem]) {
// separator found!
break;
}
}
MenuItemTarget *myMenuTarget = [[MenuItemTarget alloc] initWithNodes:vector];
// Build extension menu
NSMenuItem *myMenuItem = [[NSMenuItem alloc] initWithTitle:@"My Menu" action:nil keyEquivalent:@""];
NSMenu *mySubmenu = [[NSMenu alloc] initWithTitle:@"My menu"];
[mySubmenu setAutoenablesItems:NO];
[[mySubmenu addItemWithTitle:@"Say Hello"
action:@selector(sayHello:)
keyEquivalent:@""]
setTarget:myMenuTarget];
[[mySubmenu addItemWithTitle:@"Say Goodbye"
action:@selector(sayGoodbye:)
keyEquivalent:@""]
setTarget:myMenuTarget];
[myMenuItem setSubmenu:mySubmenu];
// Add menu
[contextMenu insertItem:myMenuItem atIndex:index + 1];
[contextMenu insertItem:[NSMenuItem separatorItem] atIndex:index + 2];
}
@end