source: trunk/ICeCoffEE/ICeCoffEE/APEMain.m@ 66

Last change on this file since 66 was 66, checked in by Nicholas Riley, 19 years ago

Initial import.

File size: 4.8 KB
Line 
1// ===========================================================================
2//
3// File: APEMain.m
4//
5// Contains: ICeCoffEE APE Module code
6//
7// Copyright: Copyright (c) 2003, Nicholas Riley
8// All Rights Reserved.
9//
10// Author(s): Nicholas Riley (Sun Jan 19 2003)
11//
12// ===========================================================================
13
14#import <Carbon/Carbon.h>
15#import <ApplicationEnhancer/ApplicationEnhancer.h>
16#import <ApplicationEnhancer/APETools.h>
17#import <objc/objc-runtime.h>
18#import "ICeCoffEE.h"
19
20//¥¥¥ Our settings
21
22//¥¥¥ Function prototypes
23static void ICCF_ReloadPrefs(); // reloads our preferences
24
25//¥¥¥ Enter sandman, the code begins --
26
27#define ICCF_GET_PATCHCLASS(patchclass) \
28 struct objc_class *patchclass = objc_getClass(patchclass ## Name); \
29 if (patchclass == NULL) { \
30 apeprintf("can't get %s\n", patchclass ## Name); \
31 return NO; \
32 }
33
34#define ICCF_GET_METHOD(name, patchclass, sel) \
35 Method name = class_getInstanceMethod(patchclass, sel); \
36 if (name == NULL) { \
37 apeprintf("can't get %s\n", patchclass ## Name); \
38 return NO; \
39 }
40
41BOOL ICCF_PatchMethod(char *patcheeClassName,
42 char *patchClassName,
43 char *patchSuperclassName,
44 char *selectorString) {
45
46 ICCF_GET_PATCHCLASS(patcheeClass);
47 ICCF_GET_PATCHCLASS(patchClass);
48 ICCF_GET_PATCHCLASS(patchSuperclass);
49
50 SEL selector = sel_getUid(selectorString);
51
52 ICCF_GET_METHOD(patcheeMethod, patcheeClass, selector);
53 ICCF_GET_METHOD(patchMethod, patchClass, selector);
54 ICCF_GET_METHOD(patchSuperMethod, patchSuperclass, selector);
55
56 APEPatchCreate(patchSuperMethod->method_imp,
57 APEPatchCreate(patcheeMethod->method_imp, patchMethod->method_imp));
58 return YES;
59}
60
61void APEBundleMain(CFBundleRef inBundle)
62{
63 // first check if this application is in the exclude list;
64 // if it is, simply return and do not apply any patches.
65 // APETools will help us with that; APE Manager will take care of
66 // exclude list management for us.
67 if (APEToolsIsInExcludeList(CFSTR("net.sabi.ICeCoffEE"), NULL))
68 {
69 apeprintf("ICeCoffEE APE: not loading as this application is excluded.\n");
70 return;
71 }
72
73 ICCF_ReloadPrefs(); // load your preferences
74 // Add any of your initialization here...
75
76 CFStringRef bundleID = CFBundleGetIdentifier(CFBundleGetMainBundle());
77 BOOL shouldLoadAlways = YES;
78
79 if (bundleID != NULL) {
80 if (CFStringCompare(bundleID, CFSTR("com.apple.projectbuilder"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
81 ICCF_PatchMethod("PBXTextView", "ICeCoffEEMenuOnly", "ICeCoffEEMenuSuper", "menuForEvent:");
82 apeprintf("ICeCoffEE APE: loading in PB!\n");
83 shouldLoadAlways = NO;
84 } else if (CFStringCompare(bundleID, CFSTR("com.apple.terminal"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
85 ICCF_PatchMethod("TermSubview", "ICeCoffEEMenuOnly", "ICeCoffEEMenuSuper", "menuForEvent:");
86 apeprintf("ICeCoffEE APE: loading in Terminal!\n");
87 } else if (CFStringCompare(bundleID, CFSTR("com.apple.safari"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
88 ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "mouseUp:");
89 ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "mouseDown:");
90 ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "menuForEvent:");
91 apeprintf("ICeCoffEE APE: loading in Safari!\n");
92 }
93 }
94
95 if (shouldLoadAlways) {
96 ICCF_PatchMethod("NSTextView", "ICeCoffEE", "ICeCoffEESuper", "mouseDown:");
97 ICCF_PatchMethod("NSTextView", "ICeCoffEE", "ICeCoffEESuper", "menuForEvent:");
98 apeprintf("ICeCoffEE APE: loading\n");
99 }
100
101 ICCF_AddServicesMenu();
102
103 return;
104}
105
106// We define APEBundleMessage so we can receive messages from our preference pane. We actually only know the Refresh message that instructs our APE module to reload the preferences. Why do we reload preferences here and not do it in our patch? Well, although you can poll CFPreferences in every patch call, that'll result in some performance loss - we better cache the settings in a static variable and refresh them from prefs only when needed.
107OSStatus APEBundleMessage(CFStringRef message,CFDataRef inData,CFDataRef *outData)
108{
109 apeprintf("ICeCoffEE APE: message '%@' (inData = %@)\n", message, inData);
110
111 if (CFStringCompare(message, CFSTR("Refresh"), NULL) == kCFCompareEqualTo)
112 { // request to reload prefs from our preference pane
113 ICCF_ReloadPrefs();
114 }
115
116 return noErr;
117}
118
119// Reload our settings from the (nonexistent) plist
120static void ICCF_ReloadPrefs()
121{
122 CFPreferencesAppSynchronize(CFSTR("net.sabi.ICeCoffEE"));
123
124 // Load your preferences here...
125}
Note: See TracBrowser for help on using the repository browser.