]> git.saurik.com Git - cydget.git/blob - CydgetLoader.mm
Port Cydget to iOS 7, ARM64, Xcode 5, and cycc :/.
[cydget.git] / CydgetLoader.mm
1 /* Cydget - open-source AwayView plugin multiplexer
2 * Copyright (C) 2009-2014 Jay Freeman (saurik)
3 */
4
5 /* GNU General Public License, Version 3 {{{ */
6 /*
7 * Cydia is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cydia is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cydia. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <CydiaSubstrate/CydiaSubstrate.h>
23
24 #include <Foundation/Foundation.h>
25 #include <UIKit/UIKit.h>
26
27 #import <SpringBoard/SBAwayController.h>
28 #import <SpringBoard/SBAwayView.h>
29 #import <SpringBoard/SBAwayWindow.h>
30 #import <SpringBoard/SpringBoard.h>
31
32 #include "Handle.hpp"
33
34 #define _trace() \
35 NSLog(@"_trace(%s:%u)@%s %zd", __FILE__, __LINE__, __FUNCTION__, active_)
36 #define _not(type) \
37 static_cast<type>(~type())
38
39 typedef void *GSEventRef;
40
41 extern "C" void UIKeyboardEnableAutomaticAppearance();
42 extern "C" void UIKeyboardDisableAutomaticAppearance();
43
44 MSClassHook(SpringBoard)
45
46 MSClassHook(SBAwayController)
47 MSClassHook(SBAwayView)
48 MSClassHook(SBAwayWindow)
49 MSClassHook(SBLockScreenManager)
50 MSClassHook(SBLockScreenView)
51 MSClassHook(SBLockScreenViewController)
52 MSClassHook(SBScreenFadeAnimationController)
53 MSClassHook(SBUserAgent)
54
55 MSInitialize {
56 if (kCFCoreFoundationVersionNumber < 800) {
57 $SBUserAgent = $SBAwayController;
58 $SBLockScreenManager = $SBAwayController;
59 $SBLockScreenView = $SBAwayView;
60 }
61 }
62
63 static bool menu_;
64
65 static _H<NSDictionary> settings_;
66 static _H<NSMutableArray> cydgets_;
67 static size_t active_;
68 static unsigned online_;
69
70 @interface CydgetController : NSObject {
71 }
72
73 + (NSDictionary *) currentConfiguration;
74
75 @end
76
77 @implementation CydgetController
78
79 + (NSDictionary *) currentConfiguration {
80 NSDictionary *cydget([cydgets_ objectAtIndex:active_]);
81 return [cydget objectForKey:@"CYConfiguration"] ?: [cydget objectForKey:@"Configuration"];
82 }
83
84 @end
85
86 @interface SBUserAgent : NSObject
87 + (SBUserAgent *) sharedUserAgent;
88 - (void) enableLockScreenBundleNamed:(NSString *)bundle activationContext:(id)context;
89 - (void) disableLockScreenBundleNamed:(NSString *)bundle deactivationContext:(id)context;
90 @end
91
92 @interface UIPeripheralHost : NSObject
93 + (UIPeripheralHost *) sharedInstance;
94 + (void) _releaseSharedInstance;
95 @end
96
97 MSClassHook(UIPeripheralHost)
98
99 @interface UITextEffectsWindow : UIWindow
100 + (UIWindow *) sharedTextEffectsWindow;
101 @end
102
103 @implementation NSDictionary (CydgetLoader)
104
105 - (NSString *) cydget {
106 return [self objectForKey:@"CYPlugin"] ?: [self objectForKey:@"Plugin"];
107 }
108
109 - (void) enableCydget {
110 if (NSString *plugin = [self cydget]) {
111 ++online_;
112
113 if (kCFCoreFoundationVersionNumber < 600)
114 UIKeyboardEnableAutomaticAppearance();
115
116 [[UITextEffectsWindow sharedTextEffectsWindow] setWindowLevel:1000];
117
118 if (kCFCoreFoundationVersionNumber < 800)
119 [[$SBAwayController sharedAwayController] enableLockScreenBundleWithName:plugin];
120 else
121 [[$SBUserAgent sharedUserAgent] enableLockScreenBundleNamed:plugin activationContext:nil];
122 }
123 }
124
125 - (void) disableCydget {
126 if (NSString *plugin = [self cydget]) {
127 if (kCFCoreFoundationVersionNumber < 800)
128 [[$SBAwayController sharedAwayController] disableLockScreenBundleWithName:plugin];
129 else
130 [[$SBUserAgent sharedUserAgent] disableLockScreenBundleNamed:plugin deactivationContext:nil];
131
132 [$UIPeripheralHost _releaseSharedInstance];
133
134 if (kCFCoreFoundationVersionNumber < 600)
135 UIKeyboardDisableAutomaticAppearance();
136
137 --online_;
138 }
139 }
140
141 @end
142
143 // avoid rendering a keyboard onto the default SBAwayView while automatic keyboard is online
144 MSInstanceMessageHook0(UIView *, SBAwayView, inputView) {
145 // XXX: there is a conceptual error here
146 if (online_ == 0 && false || kCFCoreFoundationVersionNumber > 600)
147 return MSOldCall();
148
149 return [[[UIView alloc] init] autorelease];
150 }
151
152 // by default, keyboard actions are redirected to SBAwayController and press menu button
153 MSInstanceMessageHook1(void, SpringBoard, handleKeyEvent, GSEventRef, event) {
154 if (online_ == 0 || kCFCoreFoundationVersionNumber > 600)
155 return MSOldCall(event);
156
157 return MSSuperCall(event);
158 }
159
160 MSInstanceMessageHook0(BOOL, SBLockScreenManager, handleMenuButtonTap) {
161 if (!MSOldCall() && menu_) {
162 [[cydgets_ objectAtIndex:active_] disableCydget];
163 active_ = (active_ + 1) % [cydgets_ count];
164 [[cydgets_ objectAtIndex:active_] enableCydget];
165 }
166
167 return YES;
168 }
169
170 void Activate_() {
171 menu_ = false;
172 [[cydgets_ objectAtIndex:active_] enableCydget];
173 }
174
175 static void Undim_(SBAwayController *self) {
176 if ([self isDimmed]) {
177 Activate_();
178 [[[self awayView] window] makeKeyWindow];
179 }
180 }
181
182 MSInstanceMessageHook1(void, SBLockScreenViewController, startLockScreenFadeInAnimationForSource, int, source) {
183 Activate_();
184 MSOldCall(source);
185 }
186
187 MSInstanceMessageHook0(void, SBAwayController, undimScreen) {
188 Undim_(self);
189 MSOldCall();
190 }
191
192 MSInstanceMessageHook1(void, SBAwayController, undimScreen, BOOL, undim) {
193 Undim_(self);
194 MSOldCall(undim);
195 }
196
197 static void Deactivate_() {
198 [[cydgets_ objectAtIndex:active_] disableCydget];
199 active_ = 0;
200 }
201
202 MSHook(void, BKSDisplayServicesSetScreenBlanked, BOOL blanked) {
203 if (blanked)
204 Deactivate_();
205 _BKSDisplayServicesSetScreenBlanked(blanked);
206 }
207
208 MSInitialize {
209 MSHookFunction("_BKSDisplayServicesSetScreenBlanked", MSHake(BKSDisplayServicesSetScreenBlanked));
210 }
211
212 MSInstanceMessageHook1(void, SBUserAgent, dimScreen, BOOL, dim) {
213 Deactivate_();
214 MSOldCall(dim);
215 }
216
217 MSInstanceMessageHook1(void, SpringBoard, _menuButtonDown, GSEventRef, event) {
218 menu_ = true;
219 MSOldCall(event);
220 }
221
222 MSInstanceMessageHook1(void, SpringBoard, menuButtonDown, GSEventRef, event) {
223 menu_ = true;
224 MSOldCall(event);
225 }
226
227 MSInstanceMessageHook1(void, SBAwayView, addGestureRecognizer, id, recognizer) {
228 if (online_ == 0 || kCFCoreFoundationVersionNumber > 600)
229 return MSOldCall(recognizer);
230 }
231
232 MSInstanceMessageHook1(void, SBAwayWindow, sendGSEvent, GSEventRef, event) {
233 if (online_ == 0 || kCFCoreFoundationVersionNumber > 600)
234 return MSOldCall(event);
235
236 return MSSuperCall(event);
237 }
238
239 #define Cydgets_ @"/System/Library/LockCydgets"
240
241 static void CydgetSetup() {
242 NSString *plist([NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.Cydget.plist", NSHomeDirectory()]);
243 settings_ = [NSMutableDictionary dictionaryWithContentsOfFile:plist] ?: [NSMutableDictionary dictionary];
244
245 NSArray *cydgets([settings_ objectForKey:@"LockCydgets"] ?: [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:
246 @"Welcome", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
247 ], [NSDictionary dictionaryWithObjectsAndKeys:
248 @"AwayView", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
249 ], nil]);
250
251 cydgets_ = [NSMutableArray arrayWithCapacity:4];
252 for (NSDictionary *cydget in cydgets)
253 if ([[cydget objectForKey:@"Active"] boolValue])
254 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.cydget/Info.plist", Cydgets_, [cydget objectForKey:@"Name"]]])
255 [cydgets_ addObject:info];
256
257 if ([cydgets_ count] == 0)
258 cydgets_ = nil;
259 }
260
261 // XXX: this could happen while it is unlocked
262 MSInstanceMessageHook1(id, SBLockScreenView, initWithFrame, CGRect, frame) {
263 self = MSOldCall(frame);
264 CydgetSetup();
265 [[cydgets_ objectAtIndex:active_] enableCydget];
266 return self;
267 }
268
269 MSInstanceMessageHook1(void, SBAwayController, _finishedUnlockAttemptWithStatus, BOOL, status) {
270 if (status)
271 Deactivate_();
272 MSOldCall(status);
273 }
274
275 // this is called occasionally by -[SBAwayView updateInterface] and takes away our keyboard
276 MSInstanceMessageHook0(void, SBAwayView, _fixupFirstResponder) {
277 if (online_ == 0)
278 return MSOldCall();
279 }
280
281 MSInstanceMessageHook0(void, SBAwayView, updateInterface) {
282 MSOldCall();
283
284 NSDictionary *cydget([cydgets_ objectAtIndex:active_]);
285
286 NSString *background([cydget objectForKey:@"CYBackground"]);
287 if ([background isEqualToString:@"Wallpaper"]) {
288 MSIvarHook(UIView *, _backgroundView);
289 [_backgroundView setAlpha:1.0f];
290 }
291
292 if ([[cydget objectForKey:@"CYShowDateTime"] boolValue])
293 [self addDateView];
294 }