]> git.saurik.com Git - cydget.git/blame - Tweak.mm
Support application URL schemes.
[cydget.git] / Tweak.mm
CommitLineData
36228fbc
JF
1/* Cydget - open-source AwayView plugin multiplexer
2 * Copyright (C) 2009-2011 Jay Freeman (saurik)
e6cd4dee
JF
3*/
4
5/*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
17 * distribution.
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36*/
37
38#include <substrate.h>
39
40#include <Foundation/Foundation.h>
41#include <GraphicsServices/GraphicsServices.h>
545370d8 42#include <UIKit/UIKit.h>
e6cd4dee
JF
43
44#import <SpringBoard/SBAwayController.h>
d86d4327 45#import <SpringBoard/SBAwayView.h>
e6cd4dee 46#import <SpringBoard/SBAwayWindow.h>
3a0081b3 47#import <SpringBoard/SpringBoard.h>
e6cd4dee
JF
48
49MSClassHook(SpringBoard)
fde9eca1 50
e6cd4dee
JF
51MSClassHook(SBAwayController)
52MSClassHook(SBAwayView)
fde9eca1 53MSClassHook(SBAwayViewController)
3aa346e5 54MSClassHook(SBAwayWindow)
e6cd4dee
JF
55
56#define _trace() \
57 NSLog(@"_trace(%s:%u)@%s %d", __FILE__, __LINE__, __FUNCTION__, active_)
58#define _not(type) \
59 static_cast<type>(~type())
60
61static bool menu_;
e6cd4dee 62
3a0081b3 63static _H<NSArray> settings_;
e6cd4dee 64static _H<NSArray> cydgets_;
3a0081b3 65static size_t active_;
3aa346e5 66static unsigned online_;
e6cd4dee 67
d8165c74
JF
68@interface CydgetController : NSObject {
69}
70
71+ (NSDictionary *) currentConfiguration;
72
73@end
74
75@implementation CydgetController
76
77+ (NSDictionary *) currentConfiguration {
d86d4327
JF
78 NSDictionary *cydget([cydgets_ objectAtIndex:active_]);
79 return [cydget objectForKey:@"CYConfiguration"] ?: [cydget objectForKey:@"Configuration"];
d8165c74
JF
80}
81
82@end
83
e6cd4dee
JF
84@interface NSDictionary (Cydgets)
85- (void) enableCydget:(SBAwayController *)away;
86- (void) disableCydget:(SBAwayController *)away;
87@end
88
57df9ddb
JF
89@interface UIPeripheralHost : NSObject
90+ (UIPeripheralHost *) sharedInstance;
91+ (void) _releaseSharedInstance;
57df9ddb
JF
92@end
93
94MSClassHook(UIPeripheralHost)
95
96@interface UITextEffectsWindow : UIWindow
97+ (UIWindow *) sharedTextEffectsWindow;
98@end
99
e6cd4dee
JF
100@implementation NSDictionary (Cydgets)
101
102- (void) enableCydget:(SBAwayController *)away {
d86d4327 103 if (NSString *plugin = [self objectForKey:@"CYPlugin"] ?: [self objectForKey:@"Plugin"]) {
fde9eca1 104 ++online_;
57df9ddb 105 UIKeyboardEnableAutomaticAppearance();
fde9eca1 106
57df9ddb
JF
107 [[UITextEffectsWindow sharedTextEffectsWindow] setWindowLevel:1000];
108
3a0081b3 109 [away enableLockScreenBundleWithName:plugin];
3aa346e5 110 }
e6cd4dee
JF
111}
112
113- (void) disableCydget:(SBAwayController *)away {
d86d4327 114 if (NSString *plugin = [self objectForKey:@"CYPlugin"] ?: [self objectForKey:@"Plugin"]) {
c1e7d039 115 [away disableLockScreenBundleWithName:plugin];
57df9ddb
JF
116
117 [$UIPeripheralHost _releaseSharedInstance];
fde9eca1 118
57df9ddb 119 UIKeyboardDisableAutomaticAppearance();
fde9eca1 120 --online_;
3aa346e5 121 }
e6cd4dee
JF
122}
123
124@end
125
fde9eca1
JF
126// avoid rendering a keyboard onto the default SBAwayView while automatic keyboard is online
127MSInstanceMessageHook0(UIView *, SBAwayView, inputView) {
d373498d
JF
128 // XXX: there is a conceptual error here
129 if (online_ == 0 && false)
fde9eca1
JF
130 return MSOldCall();
131
132 return [[[UIView alloc] init] autorelease];
133}
134
135// by default, keyboard actions are redirected to SBAwayController and press menu button
57df9ddb 136MSInstanceMessageHook1(void, SpringBoard, handleKeyEvent, GSEventRef, event) {
fde9eca1
JF
137 if (online_ == 0)
138 return MSOldCall(event);
139
140 return MSSuperCall(event);
57df9ddb
JF
141}
142
3a0081b3 143MSInstanceMessageHook0(BOOL, SBAwayController, handleMenuButtonTap) {
1b616711 144 if (!MSOldCall() && menu_) {
3a0081b3
JF
145 [[cydgets_ objectAtIndex:active_] disableCydget:self];
146 active_ = (active_ + 1) % [cydgets_ count];
147 [[cydgets_ objectAtIndex:active_] enableCydget:self];
1b616711 148 }
e6cd4dee
JF
149
150 return YES;
151}
152
3a0081b3 153MSInstanceMessageHook0(void, SBAwayController, _undimScreen) {
1b616711 154 menu_ = false;
fde9eca1
JF
155 [[cydgets_ objectAtIndex:active_] enableCydget:self];
156 [[[self awayView] window] makeKeyWindow];
157 return MSOldCall();
e6cd4dee
JF
158}
159
e6cd4dee 160static void Deactivate_(SBAwayController *self) {
3a0081b3
JF
161 [[cydgets_ objectAtIndex:active_] disableCydget:self];
162 active_ = 0;
e6cd4dee
JF
163}
164
1b616711 165MSInstanceMessageHook1(void, SBAwayController, dimScreen, BOOL, dim) {
3aa346e5 166 Deactivate_([$SBAwayController sharedAwayController]);
1b616711 167 MSOldCall(dim);
e6cd4dee
JF
168}
169
3a0081b3 170MSInstanceMessageHook1(void, SpringBoard, menuButtonUp, GSEventRef, event) {
e6cd4dee 171 menu_ = true;
3a0081b3 172 MSOldCall(event);
e6cd4dee
JF
173}
174
3a0081b3 175MSInstanceMessageHook1(void, SBAwayView, addGestureRecognizer, id, recognizer) {
fde9eca1
JF
176 if (online_ == 0)
177 return MSOldCall(recognizer);
545370d8
JF
178}
179
3aa346e5 180MSInstanceMessageHook1(void, SBAwayWindow, sendGSEvent, GSEventRef, event) {
fde9eca1
JF
181 NSLog(@"sendGSEvent");
182 if (online_ == 0)
183 return MSOldCall(event);
184
185 return MSSuperCall(event);
3aa346e5
JF
186}
187
3a0081b3 188#define Cydgets_ @"/System/Library/LockCydgets"
545370d8 189
3a0081b3
JF
190static void CydgetSetup() {
191 NSString *plist([NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.Cydget.plist", NSHomeDirectory()]);
192 settings_ = [NSMutableDictionary dictionaryWithContentsOfFile:plist] ?: [NSMutableDictionary dictionary];
545370d8 193
3a0081b3 194 NSArray *cydgets([settings_ objectForKey:@"LockCydgets"] ?: [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:
3aa346e5 195 @"Welcome", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
3a0081b3 196 ], [NSDictionary dictionaryWithObjectsAndKeys:
3aa346e5 197 @"AwayView", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
3a0081b3 198 ], nil]);
545370d8 199
3a0081b3
JF
200 cydgets_ = [NSMutableArray arrayWithCapacity:4];
201 for (NSDictionary *cydget in cydgets)
202 if ([[cydget objectForKey:@"Active"] boolValue])
203 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.cydget/Info.plist", Cydgets_, [cydget objectForKey:@"Name"]]])
204 [cydgets_ addObject:info];
81c3ce7d
JF
205
206 if ([cydgets_ count] == 0)
207 cydgets_ = nil;
545370d8
JF
208}
209
3a0081b3
JF
210// XXX: this could happen while it is unlocked
211MSInstanceMessageHook1(id, SBAwayView, initWithFrame, CGRect, frame) {
212 self = MSOldCall(frame);
213 CydgetSetup();
214 [[cydgets_ objectAtIndex:active_] enableCydget:[$SBAwayController sharedAwayController]];
215 return self;
545370d8
JF
216}
217
3a0081b3
JF
218MSInstanceMessageHook1(void, SBAwayController, _finishedUnlockAttemptWithStatus, BOOL, status) {
219 if (status)
220 Deactivate_(self);
221 MSOldCall(status);
e6cd4dee 222}
d86d4327 223
672fa884
JF
224// this is called occasionally by -[SBAwayView updateInterface] and takes away our keyboard
225MSInstanceMessageHook0(void, SBAwayView, _fixupFirstResponder) {
226 if (online_ == 0)
227 return MSOldCall();
228}
229
d86d4327
JF
230MSInstanceMessageHook0(void, SBAwayView, updateInterface) {
231 MSOldCall();
232
233 NSDictionary *cydget([cydgets_ objectAtIndex:active_]);
234
235 NSString *background([cydget objectForKey:@"CYBackground"]);
236 if ([background isEqualToString:@"Wallpaper"]) {
237 MSIvarHook(UIView *, _backgroundView);
238 [_backgroundView setAlpha:1.0f];
239 }
240
241 if ([[cydget objectForKey:@"CYShowDateTime"] boolValue])
242 [self addDateView];
243}