Checkpoint for Welcome.
[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
52 #define _trace() \
53     NSLog(@"_trace(%s:%u)@%s %d", __FILE__, __LINE__, __FUNCTION__, active_)
54 #define _not(type) \
55     static_cast<type>(~type())
56
57 static bool menu_;
58 static unsigned lock_;
59
60 static _H<NSArray> settings_;
61 static _H<NSArray> cydgets_;
62 static size_t active_;
63
64 @interface CydgetController : NSObject {
65 }
66
67 + (NSDictionary *) currentConfiguration;
68
69 @end
70
71 @implementation CydgetController
72
73 + (NSDictionary *) currentConfiguration {
74     return [[cydgets_ objectAtIndex:active_] objectForKey:@"Configuration"];
75 }
76
77 @end
78
79 @interface NSDictionary (Cydgets)
80 - (void) enableCydget:(SBAwayController *)away;
81 - (void) disableCydget:(SBAwayController *)away;
82 @end
83
84 @implementation NSDictionary (Cydgets)
85
86 - (void) enableCydget:(SBAwayController *)away {
87     if (NSString *plugin = [self objectForKey:@"Plugin"])
88         [away enableLockScreenBundleWithName:plugin];
89 }
90
91 - (void) disableCydget:(SBAwayController *)away {
92     if (NSString *plugin = [self objectForKey:@"Plugin"])
93         [away disableLockScreenBundleWithName:plugin];
94 }
95
96 @end
97
98 MSInstanceMessageHook0(BOOL, SBAwayController, handleMenuButtonTap) {
99     unsigned lock(lock_);
100
101     if (!MSOldCall() && lock != 2) {
102         [[cydgets_ objectAtIndex:active_] disableCydget:self];
103         active_ = (active_ + 1) % [cydgets_ count];
104         [[cydgets_ objectAtIndex:active_] enableCydget:self];
105     }
106
107     return YES;
108 }
109
110 MSInstanceMessageHook0(void, SBAwayController, _undimScreen) {
111     if (lock_ == 1)
112         lock_ = 2;
113     [[cydgets_ objectAtIndex:active_] enableCydget:[$SBAwayController sharedAwayController]];
114     MSOldCall();
115 }
116
117 MSInstanceMessageHook0(void, SBAwayController, undimScreen) {
118     lock_ = menu_ ? 1 : 0;
119     MSOldCall();
120 }
121
122 static void Deactivate_(SBAwayController *self) {
123     [[cydgets_ objectAtIndex:active_] disableCydget:self];
124     active_ = 0;
125 }
126
127 MSInstanceMessageHook0(void, SBAwayController, finishedDimmingScreen) {
128     Deactivate_(self);
129     MSOldCall();
130 }
131
132 MSInstanceMessageHook1(void, SpringBoard, menuButtonUp, GSEventRef, event) {
133     menu_ = true;
134     MSOldCall(event);
135     menu_ = false;
136 }
137
138 MSInstanceMessageHook1(void, SBAwayView, addGestureRecognizer, id, recognizer) {
139     // MSOldCall(recognizer);
140 }
141
142 #define Cydgets_ @"/System/Library/LockCydgets"
143
144 static void CydgetSetup() {
145     NSString *plist([NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.Cydget.plist", NSHomeDirectory()]);
146     settings_ = [NSMutableDictionary dictionaryWithContentsOfFile:plist] ?: [NSMutableDictionary dictionary];
147
148     NSArray *cydgets([settings_ objectForKey:@"LockCydgets"] ?: [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:
149         @"AwayView", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
150     ], [NSDictionary dictionaryWithObjectsAndKeys:
151         @"CydgetCentral", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
152     ], nil]);
153
154     cydgets_ = [NSMutableArray arrayWithCapacity:4];
155     for (NSDictionary *cydget in cydgets)
156         if ([[cydget objectForKey:@"Active"] boolValue])
157             if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.cydget/Info.plist", Cydgets_, [cydget objectForKey:@"Name"]]])
158                 [cydgets_ addObject:info];
159 }
160
161 // XXX: this could happen while it is unlocked
162 MSInstanceMessageHook1(id, SBAwayView, initWithFrame, CGRect, frame) {
163     self = MSOldCall(frame);
164     CydgetSetup();
165     [[cydgets_ objectAtIndex:active_] enableCydget:[$SBAwayController sharedAwayController]];
166     return self;
167 }
168
169 MSInstanceMessageHook1(void, SBAwayController, _finishedUnlockAttemptWithStatus, BOOL, status) {
170     if (status)
171         Deactivate_(self);
172     MSOldCall(status);
173 }