Added the empty LockCydgets folder and setup plist reading for .cydget sub-bundles.
[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
43 #import <SpringBoard/SBAwayController.h>
44 #import <SpringBoard/SBAwayWindow.h>
45
46 MSClassHook(SpringBoard)
47 MSClassHook(SBAwayController)
48 MSClassHook(SBAwayView)
49
50 #define _trace() \
51     NSLog(@"_trace(%s:%u)@%s %d", __FILE__, __LINE__, __FUNCTION__, active_)
52 #define _not(type) \
53     static_cast<type>(~type())
54
55 static bool menu_;
56 static unsigned lock_;
57
58 static _H<NSArray> cydgets_;
59 static size_t active_ = _not(size_t);
60
61 @interface NSDictionary (Cydgets)
62 - (void) enableCydget:(SBAwayController *)away;
63 - (void) disableCydget:(SBAwayController *)away;
64 @end
65
66 @implementation NSDictionary (Cydgets)
67
68 - (void) enableCydget:(SBAwayController *)away {
69     [away enableLockScreenBundleWithName:[self objectForKey:@"Plugin"]];
70 }
71
72 - (void) disableCydget:(SBAwayController *)away {
73     [away disableLockScreenBundleWithName:[self objectForKey:@"Plugin"]];
74 }
75
76 @end
77
78 MSHook(BOOL, SBAwayController$handleMenuButtonTap, SBAwayController *self, SEL sel) {
79     unsigned lock(lock_);
80
81     if (!_SBAwayController$handleMenuButtonTap(self, sel) && lock != 2) {
82         if (active_ != _not(size_t))
83             [[cydgets_ objectAtIndex:active_] disableCydget:self];
84
85         size_t count([cydgets_ count]);
86         if ((++active_ %= count + 1) == count)
87             active_ = _not(size_t);
88         else
89             [[cydgets_ objectAtIndex:active_] enableCydget:self];
90     }
91
92     return YES;
93 }
94
95 MSHook(void, SBAwayController$_undimScreen, SBAwayController *self, SEL sel) {
96     if (lock_ == 1)
97         lock_ = 2;
98     _SBAwayController$_undimScreen(self, sel);
99 }
100
101 MSHook(void, SBAwayController$undimScreen, SBAwayController *self, SEL sel) {
102     lock_ = menu_ ? 1 : 0;
103     _SBAwayController$undimScreen(self, sel);
104 }
105
106 static void Deactivate_(SBAwayController *self) {
107     if (active_ != _not(size_t)) {
108         [[cydgets_ objectAtIndex:active_] disableCydget:self];
109         active_ = _not(size_t);
110     }
111 }
112
113 MSHook(void, SBAwayController$finishedDimmingScreen, SBAwayController *self, SEL sel) {
114     Deactivate_(self);
115     _SBAwayController$finishedDimmingScreen(self, sel);
116 }
117
118 MSHook(void, SpringBoard$menuButtonUp$, UIView *self, SEL sel, GSEventRef event) {
119     menu_ = true;
120     _SpringBoard$menuButtonUp$(self, sel, event);
121     menu_ = false;
122 }
123
124 MSHook(void, SBAwayView$addGestureRecognizer$, UIView *self, SEL sel, id gr) {
125     //_SBAwayView$addGestureRecognizer$(self, sel, gr);
126 }
127
128 MSInstanceMessageHook1(void, SBAwayController, _finishedUnlockAttemptWithStatus, BOOL, status) {
129     if (status)
130         Deactivate_(self);
131     MSOldCall(status);
132 }
133
134 #define Cydgets_ @"/System/Library/LockCydgets"
135
136 MSInitialize { _pooled
137     cydgets_ = [NSMutableArray arrayWithCapacity:4];
138
139     for (NSString *folder in [[NSFileManager defaultManager] directoryContentsAtPath:Cydgets_])
140         if ([folder hasSuffix:@".cydget"])
141             [cydgets_ addObject:[NSDictionary dictionaryWithContentsOfFile:[[Cydgets_ stringByAppendingPathComponent:folder] stringByAppendingPathComponent:@"Info.plist"]]];
142
143     MSHookMessage1(SpringBoard, menuButtonUp);
144
145     MSHookMessage0(SBAwayController, handleMenuButtonTap);
146     MSHookMessage0(SBAwayController, _undimScreen);
147     MSHookMessage0(SBAwayController, undimScreen);
148     MSHookMessage0(SBAwayController, finishedDimmingScreen);
149
150     MSHookMessage1(SBAwayView, addGestureRecognizer);
151 }