]> git.saurik.com Git - cydget.git/blob - Tweak.mm
Added a PhotoExample.cydget and renamed Cycript= to CycriptURLs=.
[cydget.git] / Tweak.mm
1 /* Cydget - open-source IntelliScreen replacement
2 * Copyright (C) 2009 Jay Freeman (saurik)
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>
42 #include <UIKit/UIKit.h>
43
44 #import <SpringBoard/SBAwayController.h>
45 #import <SpringBoard/SBAwayWindow.h>
46 #import <SpringBoard/SpringBoard.h>
47
48 MSClassHook(SpringBoard)
49 MSClassHook(SBAwayController)
50 MSClassHook(SBAwayView)
51 MSClassHook(SBAwayWindow)
52
53 #define _trace() \
54 NSLog(@"_trace(%s:%u)@%s %d", __FILE__, __LINE__, __FUNCTION__, active_)
55 #define _not(type) \
56 static_cast<type>(~type())
57
58 static bool menu_;
59 static unsigned lock_;
60
61 static _H<NSArray> settings_;
62 static _H<NSArray> cydgets_;
63 static size_t active_;
64 static unsigned online_;
65
66 @interface CydgetController : NSObject {
67 }
68
69 + (NSDictionary *) currentConfiguration;
70
71 @end
72
73 @implementation CydgetController
74
75 + (NSDictionary *) currentConfiguration {
76 return [[cydgets_ objectAtIndex:active_] objectForKey:@"Configuration"];
77 }
78
79 @end
80
81 @interface NSDictionary (Cydgets)
82 - (void) enableCydget:(SBAwayController *)away;
83 - (void) disableCydget:(SBAwayController *)away;
84 @end
85
86 @implementation NSDictionary (Cydgets)
87
88 - (void) enableCydget:(SBAwayController *)away {
89 if (NSString *plugin = [self objectForKey:@"Plugin"]) {
90 [away enableLockScreenBundleWithName:plugin];
91 ++online_;
92 }
93 }
94
95 - (void) disableCydget:(SBAwayController *)away {
96 if (NSString *plugin = [self objectForKey:@"Plugin"]) {
97 [away disableLockScreenBundleWithName:plugin];
98 --online_;
99 }
100 }
101
102 @end
103
104 MSInstanceMessageHook0(BOOL, SBAwayController, handleMenuButtonTap) {
105 unsigned lock(lock_);
106
107 if (!MSOldCall() && lock != 2) {
108 [[cydgets_ objectAtIndex:active_] disableCydget:self];
109 active_ = (active_ + 1) % [cydgets_ count];
110 [[cydgets_ objectAtIndex:active_] enableCydget:self];
111 } else if (lock == 2)
112 lock_ = 0;
113
114 return YES;
115 }
116
117 MSInstanceMessageHook0(void, SBAwayController, _undimScreen) {
118 if (lock_ == 1)
119 lock_ = 2;
120 [[cydgets_ objectAtIndex:active_] enableCydget:[$SBAwayController sharedAwayController]];
121 MSOldCall();
122 }
123
124 MSInstanceMessageHook0(void, SBAwayController, undimScreen) {
125 if (lock_ != 2)
126 lock_ = menu_ ? 1 : 0;
127 MSOldCall();
128 }
129
130 static void Deactivate_(SBAwayController *self) {
131 [[cydgets_ objectAtIndex:active_] disableCydget:self];
132 active_ = 0;
133 }
134
135 #define MSNotificationHook(notification) \
136 static void N_mas(); \
137 static void burple(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef info) { \
138 N_mas(); \
139 } \
140 static class N_MSq { public: _finline N_MSq() { \
141 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &burple, CFSTR(notification), NULL, 0); \
142 } } n_msq; \
143 static void N_mas()
144
145 MSNotificationHook("SBDidTurnOffDisplayNotification") {
146 Deactivate_([$SBAwayController sharedAwayController]);
147 }
148
149 MSInstanceMessageHook1(void, SpringBoard, menuButtonUp, GSEventRef, event) {
150 menu_ = true;
151 MSOldCall(event);
152 menu_ = false;
153 }
154
155 MSInstanceMessageHook1(void, SBAwayView, addGestureRecognizer, id, recognizer) {
156 // MSOldCall(recognizer);
157 }
158
159 MSInstanceMessageHook1(void, SBAwayWindow, sendGSEvent, GSEventRef, event) {
160 if (online_ != 0)
161 MSSuperCall(event);
162 else
163 MSOldCall(event);
164 }
165
166 #define Cydgets_ @"/System/Library/LockCydgets"
167
168 static void CydgetSetup() {
169 NSString *plist([NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.Cydget.plist", NSHomeDirectory()]);
170 settings_ = [NSMutableDictionary dictionaryWithContentsOfFile:plist] ?: [NSMutableDictionary dictionary];
171
172 NSArray *cydgets([settings_ objectForKey:@"LockCydgets"] ?: [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:
173 @"Welcome", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
174 ], [NSDictionary dictionaryWithObjectsAndKeys:
175 @"AwayView", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
176 ], nil]);
177
178 cydgets_ = [NSMutableArray arrayWithCapacity:4];
179 for (NSDictionary *cydget in cydgets)
180 if ([[cydget objectForKey:@"Active"] boolValue])
181 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.cydget/Info.plist", Cydgets_, [cydget objectForKey:@"Name"]]])
182 [cydgets_ addObject:info];
183
184 if ([cydgets_ count] == 0)
185 cydgets_ = nil;
186 }
187
188 // XXX: this could happen while it is unlocked
189 MSInstanceMessageHook1(id, SBAwayView, initWithFrame, CGRect, frame) {
190 self = MSOldCall(frame);
191 CydgetSetup();
192 [[cydgets_ objectAtIndex:active_] enableCydget:[$SBAwayController sharedAwayController]];
193 return self;
194 }
195
196 MSInstanceMessageHook1(void, SBAwayController, _finishedUnlockAttemptWithStatus, BOOL, status) {
197 if (status)
198 Deactivate_(self);
199 MSOldCall(status);
200 }