1 /* Cydget - open-source AwayView plugin multiplexer
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
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
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.
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.
38 #include <substrate.h>
40 #include <Foundation/Foundation.h>
41 #include <GraphicsServices/GraphicsServices.h>
42 #include <UIKit/UIKit.h>
44 #import <SpringBoard/SBAwayController.h>
45 #import <SpringBoard/SBAwayView.h>
46 #import <SpringBoard/SBAwayWindow.h>
47 #import <SpringBoard/SpringBoard.h>
51 MSClassHook(SpringBoard)
53 MSClassHook(SBAwayController)
54 MSClassHook(SBAwayView)
55 MSClassHook(SBAwayViewController)
56 MSClassHook(SBAwayWindow)
59 NSLog(@"_trace(%s:%u)@%s %d", __FILE__, __LINE__, __FUNCTION__, active_)
61 static_cast<type>(~type())
65 static _H<NSArray> settings_;
66 static _H<NSArray> cydgets_;
67 static size_t active_;
68 static unsigned online_;
70 @interface CydgetController : NSObject {
73 + (NSDictionary *) currentConfiguration;
77 @implementation CydgetController
79 + (NSDictionary *) currentConfiguration {
80 NSDictionary *cydget([cydgets_ objectAtIndex:active_]);
81 return [cydget objectForKey:@"CYConfiguration"] ?: [cydget objectForKey:@"Configuration"];
86 @interface NSDictionary (Cydgets)
87 - (void) enableCydget:(SBAwayController *)away;
88 - (void) disableCydget:(SBAwayController *)away;
91 @interface UIPeripheralHost : NSObject
92 + (UIPeripheralHost *) sharedInstance;
93 + (void) _releaseSharedInstance;
96 MSClassHook(UIPeripheralHost)
98 @interface UITextEffectsWindow : UIWindow
99 + (UIWindow *) sharedTextEffectsWindow;
102 @implementation NSDictionary (Cydgets)
104 - (void) enableCydget:(SBAwayController *)away {
105 if (NSString *plugin = [self objectForKey:@"CYPlugin"] ?: [self objectForKey:@"Plugin"]) {
108 if (kCFCoreFoundationVersionNumber < 600)
109 UIKeyboardEnableAutomaticAppearance();
111 [[UITextEffectsWindow sharedTextEffectsWindow] setWindowLevel:1000];
112 [away enableLockScreenBundleWithName:plugin];
116 - (void) disableCydget:(SBAwayController *)away {
117 if (NSString *plugin = [self objectForKey:@"CYPlugin"] ?: [self objectForKey:@"Plugin"]) {
118 [away disableLockScreenBundleWithName:plugin];
119 [$UIPeripheralHost _releaseSharedInstance];
121 if (kCFCoreFoundationVersionNumber < 600)
122 UIKeyboardDisableAutomaticAppearance();
130 // avoid rendering a keyboard onto the default SBAwayView while automatic keyboard is online
131 MSInstanceMessageHook0(UIView *, SBAwayView, inputView) {
132 // XXX: there is a conceptual error here
133 if (online_ == 0 && false || kCFCoreFoundationVersionNumber > 600)
136 return [[[UIView alloc] init] autorelease];
139 // by default, keyboard actions are redirected to SBAwayController and press menu button
140 MSInstanceMessageHook1(void, SpringBoard, handleKeyEvent, GSEventRef, event) {
141 if (online_ == 0 || kCFCoreFoundationVersionNumber > 600)
142 return MSOldCall(event);
144 return MSSuperCall(event);
147 MSInstanceMessageHook0(BOOL, SBAwayController, handleMenuButtonTap) {
148 if (!MSOldCall() && menu_) {
149 [[cydgets_ objectAtIndex:active_] disableCydget:self];
150 active_ = (active_ + 1) % [cydgets_ count];
151 [[cydgets_ objectAtIndex:active_] enableCydget:self];
157 MSInstanceMessageHook0(void, SBAwayController, undimScreen) {
158 if ([self isDimmed]) {
160 [[cydgets_ objectAtIndex:active_] enableCydget:self];
161 [[[self awayView] window] makeKeyWindow];
167 static void Deactivate_(SBAwayController *self) {
168 [[cydgets_ objectAtIndex:active_] disableCydget:self];
172 MSInstanceMessageHook1(void, SBAwayController, dimScreen, BOOL, dim) {
173 Deactivate_([$SBAwayController sharedAwayController]);
177 MSInstanceMessageHook1(void, SpringBoard, menuButtonDown, GSEventRef, event) {
182 MSInstanceMessageHook1(void, SBAwayView, addGestureRecognizer, id, recognizer) {
183 if (online_ == 0 || kCFCoreFoundationVersionNumber > 600)
184 return MSOldCall(recognizer);
187 MSInstanceMessageHook1(void, SBAwayWindow, sendGSEvent, GSEventRef, event) {
188 if (online_ == 0 || kCFCoreFoundationVersionNumber > 600)
189 return MSOldCall(event);
191 return MSSuperCall(event);
194 #define Cydgets_ @"/System/Library/LockCydgets"
196 static void CydgetSetup() {
197 NSString *plist([NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.Cydget.plist", NSHomeDirectory()]);
198 settings_ = [NSMutableDictionary dictionaryWithContentsOfFile:plist] ?: [NSMutableDictionary dictionary];
200 NSArray *cydgets([settings_ objectForKey:@"LockCydgets"] ?: [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:
201 @"Welcome", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
202 ], [NSDictionary dictionaryWithObjectsAndKeys:
203 @"AwayView", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
206 cydgets_ = [NSMutableArray arrayWithCapacity:4];
207 for (NSDictionary *cydget in cydgets)
208 if ([[cydget objectForKey:@"Active"] boolValue])
209 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.cydget/Info.plist", Cydgets_, [cydget objectForKey:@"Name"]]])
210 [cydgets_ addObject:info];
212 if ([cydgets_ count] == 0)
216 // XXX: this could happen while it is unlocked
217 MSInstanceMessageHook1(id, SBAwayView, initWithFrame, CGRect, frame) {
218 self = MSOldCall(frame);
220 [[cydgets_ objectAtIndex:active_] enableCydget:[$SBAwayController sharedAwayController]];
224 MSInstanceMessageHook1(void, SBAwayController, _finishedUnlockAttemptWithStatus, BOOL, status) {
230 // this is called occasionally by -[SBAwayView updateInterface] and takes away our keyboard
231 MSInstanceMessageHook0(void, SBAwayView, _fixupFirstResponder) {
236 MSInstanceMessageHook0(void, SBAwayView, updateInterface) {
239 NSDictionary *cydget([cydgets_ objectAtIndex:active_]);
241 NSString *background([cydget objectForKey:@"CYBackground"]);
242 if ([background isEqualToString:@"Wallpaper"]) {
243 MSIvarHook(UIView *, _backgroundView);
244 [_backgroundView setAlpha:1.0f];
247 if ([[cydget objectForKey:@"CYShowDateTime"] boolValue])