├── README.mdown ├── WindowManager.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── steven.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── WindowManager.xcscheme │ └── xcschememanagement.plist └── WindowManager ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json └── wallpaper.imageset │ ├── Contents.json │ └── ios-9-wallpapers-4.png ├── Base.lproj └── LaunchScreen.storyboard ├── Info.plist ├── WMWindow.h ├── WMWindow.m ├── en.lproj └── Main.storyboard └── main.m /README.mdown: -------------------------------------------------------------------------------- 1 | WindowManager 2 | ============= 3 | 4 | (Not actually a window manager) 5 | 6 | Just an experiment - don't expect to use in real apps or pass App Store review process. Not production-ready or recommended. Pull Requests/Issues not necessary & may be ignored. 7 | 8 | SCREENSHOT 9 | ============= 10 | 11 | [![](https://lh3.googleusercontent.com/-tOTEnuf6e5I/Vn1MrVQdb-I/AAAAAAAACL8/SJ_NSzvONRc/s1024-Ic42/IMG_0883.jpg)](https://lh3.googleusercontent.com/-tOTEnuf6e5I/Vn1MrVQdb-I/AAAAAAAACL8/SJ_NSzvONRc/s1024-Ic42/IMG_0883.jpg) -------------------------------------------------------------------------------- /WindowManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B059BCA51C2D83AD00126834 /* README.mdown in Sources */ = {isa = PBXBuildFile; fileRef = B059BCA41C2D83AD00126834 /* README.mdown */; }; 11 | B0A8A2171C2ACF8C006C6E89 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B0A8A2161C2ACF8C006C6E89 /* main.m */; }; 12 | B0A8A21A1C2ACF8C006C6E89 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B0A8A2191C2ACF8C006C6E89 /* AppDelegate.m */; }; 13 | B0A8A2221C2ACF8C006C6E89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B0A8A2211C2ACF8C006C6E89 /* Assets.xcassets */; }; 14 | B0A8A2251C2ACF8C006C6E89 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B0A8A2231C2ACF8C006C6E89 /* LaunchScreen.storyboard */; }; 15 | B0A8A22E1C2ACFAE006C6E89 /* WMWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = B0A8A22D1C2ACFAE006C6E89 /* WMWindow.m */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | B059BCA41C2D83AD00126834 /* README.mdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.mdown; sourceTree = ""; }; 20 | B0A8A2121C2ACF8C006C6E89 /* WindowManager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WindowManager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | B0A8A2161C2ACF8C006C6E89 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 22 | B0A8A2181C2ACF8C006C6E89 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 23 | B0A8A2191C2ACF8C006C6E89 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 24 | B0A8A2211C2ACF8C006C6E89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | B0A8A2241C2ACF8C006C6E89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 26 | B0A8A2261C2ACF8C006C6E89 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | B0A8A22C1C2ACFAE006C6E89 /* WMWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMWindow.h; sourceTree = ""; }; 28 | B0A8A22D1C2ACFAE006C6E89 /* WMWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WMWindow.m; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | B0A8A20F1C2ACF8C006C6E89 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | B0A8A2091C2ACF8C006C6E89 = { 43 | isa = PBXGroup; 44 | children = ( 45 | B059BCA41C2D83AD00126834 /* README.mdown */, 46 | B0A8A2141C2ACF8C006C6E89 /* WindowManager */, 47 | B0A8A2131C2ACF8C006C6E89 /* Products */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | B0A8A2131C2ACF8C006C6E89 /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | B0A8A2121C2ACF8C006C6E89 /* WindowManager.app */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | B0A8A2141C2ACF8C006C6E89 /* WindowManager */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | B0A8A2181C2ACF8C006C6E89 /* AppDelegate.h */, 63 | B0A8A2191C2ACF8C006C6E89 /* AppDelegate.m */, 64 | B0A8A22C1C2ACFAE006C6E89 /* WMWindow.h */, 65 | B0A8A22D1C2ACFAE006C6E89 /* WMWindow.m */, 66 | B0A8A2211C2ACF8C006C6E89 /* Assets.xcassets */, 67 | B0A8A2231C2ACF8C006C6E89 /* LaunchScreen.storyboard */, 68 | B0A8A2261C2ACF8C006C6E89 /* Info.plist */, 69 | B0A8A2151C2ACF8C006C6E89 /* Supporting Files */, 70 | ); 71 | path = WindowManager; 72 | sourceTree = ""; 73 | }; 74 | B0A8A2151C2ACF8C006C6E89 /* Supporting Files */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | B0A8A2161C2ACF8C006C6E89 /* main.m */, 78 | ); 79 | name = "Supporting Files"; 80 | sourceTree = ""; 81 | }; 82 | /* End PBXGroup section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | B0A8A2111C2ACF8C006C6E89 /* WindowManager */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = B0A8A2291C2ACF8C006C6E89 /* Build configuration list for PBXNativeTarget "WindowManager" */; 88 | buildPhases = ( 89 | B0A8A20E1C2ACF8C006C6E89 /* Sources */, 90 | B0A8A20F1C2ACF8C006C6E89 /* Frameworks */, 91 | B0A8A2101C2ACF8C006C6E89 /* Resources */, 92 | ); 93 | buildRules = ( 94 | ); 95 | dependencies = ( 96 | ); 97 | name = WindowManager; 98 | productName = WindowManager; 99 | productReference = B0A8A2121C2ACF8C006C6E89 /* WindowManager.app */; 100 | productType = "com.apple.product-type.application"; 101 | }; 102 | /* End PBXNativeTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | B0A8A20A1C2ACF8C006C6E89 /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | LastUpgradeCheck = 0720; 109 | ORGANIZATIONNAME = "High Caffeine Content"; 110 | TargetAttributes = { 111 | B0A8A2111C2ACF8C006C6E89 = { 112 | CreatedOnToolsVersion = 7.2; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = B0A8A20D1C2ACF8C006C6E89 /* Build configuration list for PBXProject "WindowManager" */; 117 | compatibilityVersion = "Xcode 3.2"; 118 | developmentRegion = English; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | Base, 123 | ); 124 | mainGroup = B0A8A2091C2ACF8C006C6E89; 125 | productRefGroup = B0A8A2131C2ACF8C006C6E89 /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | B0A8A2111C2ACF8C006C6E89 /* WindowManager */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | B0A8A2101C2ACF8C006C6E89 /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | B0A8A2251C2ACF8C006C6E89 /* LaunchScreen.storyboard in Resources */, 140 | B0A8A2221C2ACF8C006C6E89 /* Assets.xcassets in Resources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXResourcesBuildPhase section */ 145 | 146 | /* Begin PBXSourcesBuildPhase section */ 147 | B0A8A20E1C2ACF8C006C6E89 /* Sources */ = { 148 | isa = PBXSourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | B0A8A22E1C2ACFAE006C6E89 /* WMWindow.m in Sources */, 152 | B0A8A21A1C2ACF8C006C6E89 /* AppDelegate.m in Sources */, 153 | B059BCA51C2D83AD00126834 /* README.mdown in Sources */, 154 | B0A8A2171C2ACF8C006C6E89 /* main.m in Sources */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXSourcesBuildPhase section */ 159 | 160 | /* Begin PBXVariantGroup section */ 161 | B0A8A2231C2ACF8C006C6E89 /* LaunchScreen.storyboard */ = { 162 | isa = PBXVariantGroup; 163 | children = ( 164 | B0A8A2241C2ACF8C006C6E89 /* Base */, 165 | ); 166 | name = LaunchScreen.storyboard; 167 | sourceTree = ""; 168 | }; 169 | /* End PBXVariantGroup section */ 170 | 171 | /* Begin XCBuildConfiguration section */ 172 | B0A8A2271C2ACF8C006C6E89 /* Debug */ = { 173 | isa = XCBuildConfiguration; 174 | buildSettings = { 175 | ALWAYS_SEARCH_USER_PATHS = NO; 176 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 177 | CLANG_CXX_LIBRARY = "libc++"; 178 | CLANG_ENABLE_MODULES = YES; 179 | CLANG_ENABLE_OBJC_ARC = YES; 180 | CLANG_WARN_BOOL_CONVERSION = YES; 181 | CLANG_WARN_CONSTANT_CONVERSION = YES; 182 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 183 | CLANG_WARN_EMPTY_BODY = YES; 184 | CLANG_WARN_ENUM_CONVERSION = YES; 185 | CLANG_WARN_INT_CONVERSION = YES; 186 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 187 | CLANG_WARN_UNREACHABLE_CODE = YES; 188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 189 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 190 | COPY_PHASE_STRIP = NO; 191 | DEBUG_INFORMATION_FORMAT = dwarf; 192 | ENABLE_STRICT_OBJC_MSGSEND = YES; 193 | ENABLE_TESTABILITY = YES; 194 | GCC_C_LANGUAGE_STANDARD = gnu99; 195 | GCC_DYNAMIC_NO_PIC = NO; 196 | GCC_NO_COMMON_BLOCKS = YES; 197 | GCC_OPTIMIZATION_LEVEL = 0; 198 | GCC_PREPROCESSOR_DEFINITIONS = ( 199 | "DEBUG=1", 200 | "$(inherited)", 201 | ); 202 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 203 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 204 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 205 | GCC_WARN_PEDANTIC = YES; 206 | GCC_WARN_UNDECLARED_SELECTOR = YES; 207 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 208 | GCC_WARN_UNUSED_FUNCTION = YES; 209 | GCC_WARN_UNUSED_VARIABLE = YES; 210 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 211 | MTL_ENABLE_DEBUG_INFO = YES; 212 | ONLY_ACTIVE_ARCH = YES; 213 | SDKROOT = iphoneos; 214 | TARGETED_DEVICE_FAMILY = 2; 215 | }; 216 | name = Debug; 217 | }; 218 | B0A8A2281C2ACF8C006C6E89 /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_WARN_BOOL_CONVERSION = YES; 227 | CLANG_WARN_CONSTANT_CONVERSION = YES; 228 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 229 | CLANG_WARN_EMPTY_BODY = YES; 230 | CLANG_WARN_ENUM_CONVERSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_UNREACHABLE_CODE = YES; 234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 235 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 236 | COPY_PHASE_STRIP = NO; 237 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 238 | ENABLE_NS_ASSERTIONS = NO; 239 | ENABLE_STRICT_OBJC_MSGSEND = YES; 240 | GCC_C_LANGUAGE_STANDARD = gnu99; 241 | GCC_NO_COMMON_BLOCKS = YES; 242 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 245 | GCC_WARN_PEDANTIC = YES; 246 | GCC_WARN_UNDECLARED_SELECTOR = YES; 247 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 248 | GCC_WARN_UNUSED_FUNCTION = YES; 249 | GCC_WARN_UNUSED_VARIABLE = YES; 250 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 251 | MTL_ENABLE_DEBUG_INFO = NO; 252 | SDKROOT = iphoneos; 253 | TARGETED_DEVICE_FAMILY = 2; 254 | VALIDATE_PRODUCT = YES; 255 | }; 256 | name = Release; 257 | }; 258 | B0A8A22A1C2ACF8C006C6E89 /* Debug */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 262 | INFOPLIST_FILE = WindowManager/Info.plist; 263 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 264 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 265 | PRODUCT_BUNDLE_IDENTIFIER = com.highcaffeinecontent.WindowManager; 266 | PRODUCT_NAME = "$(TARGET_NAME)"; 267 | TARGETED_DEVICE_FAMILY = "1,2"; 268 | }; 269 | name = Debug; 270 | }; 271 | B0A8A22B1C2ACF8C006C6E89 /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 275 | INFOPLIST_FILE = WindowManager/Info.plist; 276 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 277 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 278 | PRODUCT_BUNDLE_IDENTIFIER = com.highcaffeinecontent.WindowManager; 279 | PRODUCT_NAME = "$(TARGET_NAME)"; 280 | TARGETED_DEVICE_FAMILY = "1,2"; 281 | }; 282 | name = Release; 283 | }; 284 | /* End XCBuildConfiguration section */ 285 | 286 | /* Begin XCConfigurationList section */ 287 | B0A8A20D1C2ACF8C006C6E89 /* Build configuration list for PBXProject "WindowManager" */ = { 288 | isa = XCConfigurationList; 289 | buildConfigurations = ( 290 | B0A8A2271C2ACF8C006C6E89 /* Debug */, 291 | B0A8A2281C2ACF8C006C6E89 /* Release */, 292 | ); 293 | defaultConfigurationIsVisible = 0; 294 | defaultConfigurationName = Release; 295 | }; 296 | B0A8A2291C2ACF8C006C6E89 /* Build configuration list for PBXNativeTarget "WindowManager" */ = { 297 | isa = XCConfigurationList; 298 | buildConfigurations = ( 299 | B0A8A22A1C2ACF8C006C6E89 /* Debug */, 300 | B0A8A22B1C2ACF8C006C6E89 /* Release */, 301 | ); 302 | defaultConfigurationIsVisible = 0; 303 | defaultConfigurationName = Release; 304 | }; 305 | /* End XCConfigurationList section */ 306 | }; 307 | rootObject = B0A8A20A1C2ACF8C006C6E89 /* Project object */; 308 | } 309 | -------------------------------------------------------------------------------- /WindowManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WindowManager.xcodeproj/xcuserdata/steven.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /WindowManager.xcodeproj/xcuserdata/steven.xcuserdatad/xcschemes/WindowManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /WindowManager.xcodeproj/xcuserdata/steven.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | WindowManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B0A8A2111C2ACF8C006C6E89 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /WindowManager/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // WindowManager 4 | // 5 | // Created by Steven Troughton-Smith on 23/12/2015. 6 | // Copyright © 2015 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WMWindow.h" 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (strong, nonatomic) UIWindow *window; 15 | 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /WindowManager/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // WindowManager 4 | // 5 | // Created by Steven Troughton-Smith on 23/12/2015. 6 | // Copyright © 2015 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @import MapKit; 12 | @import WebKit; 13 | @import SafariServices; 14 | @import ObjectiveC.runtime; 15 | 16 | WMWindow *window1; 17 | WMWindow *window2; 18 | WMWindow *window3; 19 | 20 | @implementation UINavigationBar (WMNavigationBar) 21 | 22 | /* Overly simplistic. You'd want to rewrite this */ 23 | -(void)layoutSubviews_WM 24 | { 25 | [self layoutSubviews_WM]; 26 | 27 | for (UIView *view in self.subviews) 28 | { 29 | if (![[view class] isSubclassOfClass:NSClassFromString(@"_UINavigationBarBackground")] && [view class] != NSClassFromString(@"UINavigationItemView")) 30 | { 31 | CGRect f = view.frame; 32 | f.origin.x += 75; 33 | 34 | view.frame = f; 35 | } 36 | } 37 | } 38 | 39 | @end 40 | 41 | @implementation AppDelegate 42 | 43 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 44 | 45 | Class class = [UINavigationBar class]; 46 | 47 | Method originalMethod = class_getInstanceMethod(class, @selector(layoutSubviews)); 48 | Method categoryMethod = class_getInstanceMethod(class, @selector(layoutSubviews_WM)); 49 | method_exchangeImplementations(originalMethod, categoryMethod); 50 | 51 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 52 | 53 | self.window.rootViewController = [[UIViewController alloc] init]; 54 | 55 | self.window.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"wallpaper"]]; 56 | 57 | [self.window makeKeyAndVisible]; 58 | 59 | { 60 | window1 = [[WMWindow alloc] initWithFrame:CGRectMake(50, 50, 400, 300)]; 61 | window1.title = @"Map"; 62 | 63 | UIViewController *vc1 = [[UIViewController alloc] init]; 64 | vc1.title = @"Root"; 65 | 66 | UIViewController *vc = [[UIViewController alloc] init]; 67 | vc.title = @"Map"; 68 | 69 | vc.view = [[MKMapView alloc] init]; 70 | 71 | window1.rootViewController = [[UINavigationController alloc] initWithRootViewController:vc1]; 72 | vc.navigationItem.hidesBackButton = NO; 73 | 74 | [((UINavigationController *)window1.rootViewController) pushViewController:vc animated:YES]; // testing nav bar behavior 75 | 76 | [window1 makeKeyAndVisible]; 77 | } 78 | 79 | { 80 | window2 = [[WMWindow alloc] initWithFrame:CGRectMake(250, 250, 300, 300)]; 81 | window2.title = @"Table"; 82 | 83 | UITableViewController *vc = [[UITableViewController alloc] init]; 84 | vc.title = @"Table"; 85 | 86 | window2.rootViewController = [[UINavigationController alloc] initWithRootViewController:vc]; 87 | 88 | [window2 makeKeyAndVisible]; 89 | } 90 | 91 | { 92 | window3 = [[WMWindow alloc] initWithFrame:CGRectMake(480, 150, 500, 500)]; 93 | window3.title = @"Text"; 94 | 95 | UIViewController *vc = [[UIViewController alloc] init]; 96 | vc.view = [[UITextView alloc] init]; 97 | vc.title = @"Text"; 98 | 99 | 100 | UINavigationController *navC = [[UINavigationController alloc] initWithRootViewController:vc]; 101 | 102 | ((UITextView *)vc.view).text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 103 | 104 | window3.rootViewController = navC; 105 | 106 | [window3 makeKeyAndVisible]; 107 | 108 | } 109 | 110 | #pragma clang diagnostic push 111 | #pragma clang diagnostic ignored "-Wdeprecated" 112 | [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 113 | #pragma clang diagnostic pop 114 | 115 | return YES; 116 | } 117 | 118 | - (void)applicationWillResignActive:(UIApplication *)application { 119 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 120 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 121 | } 122 | 123 | - (void)applicationDidEnterBackground:(UIApplication *)application { 124 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 125 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 126 | } 127 | 128 | - (void)applicationWillEnterForeground:(UIApplication *)application { 129 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 130 | } 131 | 132 | - (void)applicationDidBecomeActive:(UIApplication *)application { 133 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 134 | } 135 | 136 | - (void)applicationWillTerminate:(UIApplication *)application { 137 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 138 | } 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /WindowManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "ipad", 5 | "size" : "29x29", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "ipad", 10 | "size" : "29x29", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "ipad", 15 | "size" : "40x40", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "40x40", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "76x76", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "76x76", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "83.5x83.5", 36 | "scale" : "2x" 37 | } 38 | ], 39 | "info" : { 40 | "version" : 1, 41 | "author" : "xcode" 42 | } 43 | } -------------------------------------------------------------------------------- /WindowManager/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /WindowManager/Assets.xcassets/wallpaper.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ios-9-wallpapers-4.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WindowManager/Assets.xcassets/wallpaper.imageset/ios-9-wallpapers-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steventroughtonsmith/WindowManager/5b16a46266fa8e6a3be369273e56e65ce4a69762/WindowManager/Assets.xcassets/wallpaper.imageset/ios-9-wallpapers-4.png -------------------------------------------------------------------------------- /WindowManager/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WindowManager/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIApplicationIsOpaque 26 | 27 | UIBackgroundStyle 28 | UIBackgroundStyleDarkBlur 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationLandscapeLeft 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationPortraitUpsideDown 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /WindowManager/WMWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMWindow.h 3 | // WindowManager 4 | // 5 | // Created by Steven Troughton-Smith on 23/12/2015. 6 | // Copyright © 2015 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef enum : NSUInteger { 13 | WMResizeLeft, 14 | WMResizeRight, 15 | WMResizeTop, 16 | WMResizeBottom 17 | } WMResizeAxis; 18 | @interface WMWindow : UIWindow 19 | { 20 | CGRect _savedFrame; 21 | BOOL _inWindowMove; 22 | BOOL _inWindowResize; 23 | CGPoint _originPoint; 24 | WMResizeAxis resizeAxis; 25 | } 26 | 27 | @property NSString *title; 28 | 29 | @property NSMutableArray *windowButtons; 30 | @property BOOL maximized; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /WindowManager/WMWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMWindow.m 3 | // WindowManager 4 | // 5 | // Created by Steven Troughton-Smith on 23/12/2015. 6 | // Copyright © 2015 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "WMWindow.h" 10 | 11 | #define kTitleBarHeight 0.0 12 | #define kMoveGrabHeight 44.0 13 | 14 | #define kWindowButtonFrameSize 44.0 15 | #define kWindowButtonSize 24.0 16 | #define kWindowResizeGutterSize 8.0 17 | #define kWindowResizeGutterTargetSize 24.0 18 | #define kWindowResizeGutterKnobSize 48.0 19 | #define kWindowResizeGutterKnobWidth 4.0 20 | 21 | 22 | @implementation WMWindow 23 | 24 | -(void)_commonInit 25 | { 26 | self.windowButtons = @[].mutableCopy; 27 | 28 | { 29 | UIButton *windowButton = [UIButton buttonWithType:UIButtonTypeCustom]; 30 | windowButton.frame = CGRectMake(kWindowResizeGutterSize, kWindowResizeGutterSize, kWindowButtonFrameSize, kWindowButtonFrameSize); 31 | windowButton.contentMode = UIViewContentModeCenter; 32 | windowButton.adjustsImageWhenHighlighted = YES; 33 | 34 | [windowButton addTarget:self action:@selector(close:) forControlEvents:UIControlEventTouchUpInside]; 35 | 36 | 37 | UIColor *fillColor = [UIColor colorWithRed:0.953 green:0.278 blue:0.275 alpha:1.000] ; 38 | UIColor *strokeColor = [UIColor colorWithRed:0.839 green:0.188 blue:0.192 alpha:1.000]; 39 | 40 | UIColor *inactiveFillColor = [UIColor colorWithWhite:0.765 alpha:1.000]; 41 | UIColor *inactiveStrokeColor = [UIColor colorWithWhite:0.608 alpha:1.000]; 42 | 43 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(kWindowButtonSize, kWindowButtonSize), NO, [UIScreen mainScreen].scale); 44 | 45 | [fillColor setFill]; 46 | [strokeColor setStroke]; 47 | 48 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] fill]; 49 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] stroke]; 50 | 51 | [windowButton setImage:UIGraphicsGetImageFromCurrentImageContext() forState:UIControlStateNormal]; 52 | UIGraphicsEndImageContext(); 53 | 54 | 55 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(kWindowButtonSize, kWindowButtonSize), NO, [UIScreen mainScreen].scale); 56 | 57 | [inactiveFillColor setFill]; 58 | [inactiveStrokeColor setStroke]; 59 | 60 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] fill]; 61 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] stroke]; 62 | 63 | [windowButton setImage:UIGraphicsGetImageFromCurrentImageContext() forState:UIControlStateDisabled]; 64 | UIGraphicsEndImageContext(); 65 | 66 | [self addSubview:windowButton]; 67 | 68 | [self.windowButtons addObject:windowButton]; 69 | } 70 | 71 | { 72 | UIButton *windowButton = [UIButton buttonWithType:UIButtonTypeCustom]; 73 | windowButton.frame = CGRectMake(kWindowResizeGutterSize+12+kWindowButtonSize, kWindowResizeGutterSize, kWindowButtonFrameSize, kWindowButtonFrameSize); 74 | windowButton.contentMode = UIViewContentModeCenter; 75 | windowButton.adjustsImageWhenHighlighted = YES; 76 | [windowButton addTarget:self action:@selector(maximize:) forControlEvents:UIControlEventTouchUpInside]; 77 | 78 | 79 | UIColor *fillColor = [UIColor colorWithRed:0.188 green:0.769 blue:0.196 alpha:1.000] ; 80 | UIColor *strokeColor = [UIColor colorWithRed:0.165 green:0.624 blue:0.125 alpha:1.000]; 81 | 82 | UIColor *inactiveFillColor = [UIColor colorWithWhite:0.765 alpha:1.000]; 83 | UIColor *inactiveStrokeColor = [UIColor colorWithWhite:0.608 alpha:1.000]; 84 | 85 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(kWindowButtonSize, kWindowButtonSize), NO, [UIScreen mainScreen].scale); 86 | 87 | [fillColor setFill]; 88 | [strokeColor setStroke]; 89 | 90 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] fill]; 91 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] stroke]; 92 | 93 | [windowButton setImage:UIGraphicsGetImageFromCurrentImageContext() forState:UIControlStateNormal]; 94 | UIGraphicsEndImageContext(); 95 | 96 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(kWindowButtonSize, kWindowButtonSize), NO, [UIScreen mainScreen].scale); 97 | 98 | [inactiveFillColor setFill]; 99 | [inactiveStrokeColor setStroke]; 100 | 101 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] fill]; 102 | [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(1, 1, kWindowButtonSize-2, kWindowButtonSize-2)] stroke]; 103 | 104 | [windowButton setImage:UIGraphicsGetImageFromCurrentImageContext() forState:UIControlStateDisabled]; 105 | UIGraphicsEndImageContext(); 106 | 107 | [self addSubview:windowButton]; 108 | [self.windowButtons addObject:windowButton]; 109 | } 110 | 111 | 112 | UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didPan:)]; 113 | panRecognizer.delegate = self; 114 | [self addGestureRecognizer:panRecognizer]; 115 | 116 | UITapGestureRecognizer *focusRecognizers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)]; 117 | [self addGestureRecognizer:focusRecognizers]; 118 | 119 | 120 | 121 | self.layer.shadowRadius = 30.0; 122 | self.layer.shadowColor = [UIColor blackColor].CGColor; 123 | self.layer.shadowOpacity = 0.3; 124 | } 125 | 126 | -(void)layoutSubviews 127 | { 128 | UIView *rootView = self.rootViewController.view; 129 | 130 | CGRect contentRect = CGRectMake(kWindowResizeGutterSize, kWindowResizeGutterSize+kTitleBarHeight, self.bounds.size.width-(kWindowResizeGutterSize*2), self.bounds.size.height-kTitleBarHeight-(kWindowResizeGutterSize*2)); 131 | 132 | rootView.frame = contentRect; 133 | [self adjustMask]; 134 | } 135 | 136 | -(BOOL)isOpaque 137 | { 138 | return NO; 139 | } 140 | 141 | - (instancetype)initWithFrame:(CGRect)frame 142 | { 143 | self = [super initWithFrame:frame]; 144 | if (self) { 145 | [self _commonInit]; 146 | } 147 | return self; 148 | } 149 | - (instancetype)initWithCoder:(NSCoder *)coder 150 | { 151 | self = [super initWithCoder:coder]; 152 | if (self) { 153 | [self _commonInit]; 154 | } 155 | return self; 156 | } 157 | 158 | -(void)maximize:(id)sender 159 | { 160 | self.maximized = !self.maximized; 161 | 162 | UIWindow *rootWindow = [UIApplication sharedApplication].windows[0]; 163 | 164 | [UIView beginAnimations:nil context:nil]; 165 | if (self.maximized) 166 | { 167 | _savedFrame = self.frame; 168 | self.frame = CGRectMake(-kWindowResizeGutterSize, 20+-kWindowResizeGutterSize, rootWindow.bounds.size.width+(kWindowResizeGutterSize*2), rootWindow.bounds.size.height-20+(kWindowResizeGutterSize*2)); 169 | } 170 | else 171 | { 172 | self.frame = _savedFrame; 173 | } 174 | [UIView commitAnimations]; 175 | } 176 | 177 | -(void)close:(id)sender 178 | { 179 | [self setHidden:YES]; 180 | } 181 | 182 | - (void)becomeKeyWindow 183 | { 184 | [self setNeedsDisplay]; 185 | self.layer.shadowRadius = 30.0; 186 | for (UIButton *btn in self.windowButtons) 187 | { 188 | btn.enabled = YES; 189 | } 190 | } 191 | 192 | - (void)resignKeyWindow 193 | { 194 | [self setNeedsDisplay]; 195 | self.layer.shadowRadius = 10.0; 196 | 197 | for (UIButton *btn in self.windowButtons) 198 | { 199 | btn.enabled = NO; 200 | } 201 | } 202 | 203 | -(void)addSubview:(UIView *)view 204 | { 205 | [super addSubview:view]; 206 | for (UIButton *btn in self.windowButtons) 207 | { 208 | [self insertSubview:btn atIndex:UINT_MAX]; 209 | } 210 | } 211 | 212 | -(void)didTap:(UIGestureRecognizer *)rec 213 | { 214 | [self makeKeyAndVisible]; 215 | } 216 | 217 | -(void)setFrame:(CGRect)frame 218 | { 219 | [super setFrame:frame]; 220 | [self setNeedsDisplay]; 221 | } 222 | 223 | -(void)didPan:(UIPanGestureRecognizer *)recognizer 224 | { 225 | CGRect titleBarRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, kMoveGrabHeight); 226 | CGPoint gp = [recognizer locationInView:[UIApplication sharedApplication].windows[0]]; 227 | CGPoint lp = [recognizer locationInView:self]; 228 | 229 | CGRect leftResizeRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, kWindowResizeGutterTargetSize, self.bounds.size.height); 230 | CGRect rightResizeRect = CGRectMake(self.bounds.origin.x+self.bounds.size.width-kWindowResizeGutterTargetSize, self.bounds.origin.y, kWindowResizeGutterTargetSize, self.bounds.size.height); 231 | 232 | CGRect topResizeRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, kWindowResizeGutterTargetSize); 233 | CGRect bottomResizeRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y+self.bounds.size.height-kWindowResizeGutterTargetSize, self.bounds.size.width, kWindowResizeGutterTargetSize); 234 | 235 | 236 | 237 | leftResizeRect = CGRectInset(leftResizeRect, -kWindowResizeGutterTargetSize, -kWindowResizeGutterTargetSize); 238 | rightResizeRect = CGRectInset(rightResizeRect, -kWindowResizeGutterTargetSize, -kWindowResizeGutterTargetSize); 239 | bottomResizeRect = CGRectInset(bottomResizeRect, -kWindowResizeGutterTargetSize, -kWindowResizeGutterTargetSize); 240 | 241 | 242 | if (self.maximized) 243 | return; 244 | 245 | if (recognizer.state == UIGestureRecognizerStateBegan) 246 | { 247 | _originPoint = lp; 248 | 249 | if (CGRectContainsPoint(titleBarRect, lp)) 250 | { 251 | _inWindowMove = YES; 252 | _inWindowResize = NO; 253 | return; 254 | } 255 | 256 | if (!self.isKeyWindow) 257 | return; 258 | 259 | if (CGRectContainsPoint(leftResizeRect, lp)) 260 | { 261 | _inWindowResize = YES; 262 | _inWindowMove = NO; 263 | resizeAxis = WMResizeLeft; 264 | } 265 | 266 | if (CGRectContainsPoint(rightResizeRect, lp)) 267 | { 268 | _inWindowResize = YES; 269 | _inWindowMove = NO; 270 | resizeAxis = WMResizeRight; 271 | } 272 | 273 | 274 | if (CGRectContainsPoint(topResizeRect, lp)) 275 | { 276 | _inWindowResize = YES; 277 | _inWindowMove = NO; 278 | resizeAxis = WMResizeTop; 279 | } 280 | 281 | if (CGRectContainsPoint(bottomResizeRect, lp)) 282 | { 283 | _inWindowResize = YES; 284 | _inWindowMove = NO; 285 | resizeAxis = WMResizeBottom; 286 | } 287 | } 288 | else if (recognizer.state == UIGestureRecognizerStateChanged) 289 | { 290 | 291 | if (_inWindowMove) 292 | { 293 | self.frame = CGRectMake(gp.x-_originPoint.x, gp.y-_originPoint.y, self.frame.size.width, self.frame.size.height); 294 | } 295 | if (_inWindowResize) 296 | { 297 | if (resizeAxis == WMResizeRight) 298 | { 299 | self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, gp.x-self.frame.origin.x, self.frame.size.height); 300 | } 301 | 302 | if (resizeAxis == WMResizeLeft) 303 | { 304 | self.frame = CGRectMake(gp.x, self.frame.origin.y, (-gp.x+self.frame.origin.x)+self.frame.size.width, self.frame.size.height); 305 | } 306 | 307 | if (resizeAxis == WMResizeBottom) 308 | { 309 | self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width,gp.y-self.frame.origin.y); 310 | } 311 | } 312 | } 313 | else if (recognizer.state == UIGestureRecognizerStateEnded) 314 | { 315 | _inWindowMove = NO; 316 | _inWindowResize = NO; 317 | [self setNeedsDisplay]; 318 | } 319 | 320 | 321 | } 322 | 323 | -(void)adjustMask 324 | { 325 | CGRect contentBounds = self.rootViewController.view.bounds; 326 | CGRect contentFrame = CGRectMake(self.bounds.origin.x+kWindowResizeGutterSize, self.bounds.origin.y+kWindowResizeGutterSize, self.bounds.size.width-(kWindowResizeGutterSize*2), self.bounds.size.height-(kWindowResizeGutterSize*2)); 327 | 328 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 329 | maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:contentBounds byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(8.0, 8.0)].CGPath; 330 | 331 | maskLayer.frame = contentBounds; 332 | 333 | self.rootViewController.view.layer.mask = maskLayer; 334 | 335 | self.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:contentFrame byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(8.0, 8.0)].CGPath; 336 | self.layer.shadowRadius = 30.0; 337 | self.layer.shadowColor = [UIColor blackColor].CGColor; 338 | self.layer.shadowOpacity = 0.3; 339 | } 340 | 341 | -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 342 | { 343 | return YES; 344 | } 345 | 346 | - (void)drawRect:(CGRect)rect 347 | { 348 | 349 | #if USE_TITLEBAR 350 | 351 | UIColor *lightColor = [UIColor colorWithRed:0.886 green:0.878 blue:0.886 alpha:1.000]; 352 | UIColor *darkColor = [UIColor colorWithRed:0.784 green:0.773 blue:0.784 alpha:1.000]; 353 | UIColor *highlightColor = [UIColor colorWithRed:0.949 green:0.945 blue:0.949 alpha:1.000]; 354 | UIColor *lowlightColor = [UIColor colorWithRed:0.749 green:0.745 blue:0.749 alpha:1.000]; 355 | UIColor *textColor = [UIColor blackColor]; 356 | 357 | 358 | UIColor *inactiveLightColor = [UIColor colorWithWhite:0.925 alpha:1.000]; 359 | UIColor *inactiveDarkColor = [UIColor colorWithWhite:0.905 alpha:1.000]; 360 | 361 | 362 | if (!self.isKeyWindow) 363 | { 364 | lightColor = inactiveLightColor; 365 | darkColor = inactiveDarkColor; 366 | textColor = [UIColor colorWithWhite:0.625 alpha:1.000]; 367 | } 368 | 369 | { 370 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 371 | CGContextRef context = UIGraphicsGetCurrentContext(); 372 | 373 | NSArray *gradientColors = [NSArray arrayWithObjects:(id) lightColor.CGColor, darkColor.CGColor, nil]; 374 | 375 | CGFloat gradientLocations[] = {0, 0.750, 1}; 376 | CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) gradientColors, gradientLocations); 377 | 378 | CGPoint startPoint = CGPointMake(CGRectGetMidX(titleBarRect), CGRectGetMinY(titleBarRect)); 379 | CGPoint endPoint = CGPointMake(CGRectGetMidX(titleBarRect), CGRectGetMaxY(titleBarRect)); 380 | 381 | CGContextSaveGState(context); 382 | CGContextAddPath(context, [UIBezierPath bezierPathWithRoundedRect:contentRect byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(8.0, 8.0)].CGPath); 383 | CGContextClip(context); 384 | 385 | [[UIColor whiteColor] set]; 386 | UIRectFill(self.bounds); 387 | 388 | CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 389 | 390 | [highlightColor set]; 391 | UIRectFill(CGRectMake(kWindowResizeGutterSize, kWindowResizeGutterSize, titleBarRect.size.width-(kWindowResizeGutterSize*2), 1)); 392 | 393 | [lowlightColor set]; 394 | UIRectFill(CGRectMake(kWindowResizeGutterSize, kWindowResizeGutterSize+titleBarRect.size.height-1, self.bounds.size.width-(kWindowResizeGutterSize*2), 1)); 395 | 396 | CGContextRestoreGState(context); 397 | CGGradientRelease(gradient); 398 | CGColorSpaceRelease(colorSpace); 399 | } 400 | 401 | if (kTitleBarHeight > 0) 402 | { 403 | NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; 404 | style.alignment = NSTextAlignmentCenter; 405 | 406 | NSDictionary *attr = @{NSFontAttributeName:[UIFont systemFontOfSize:18],NSParagraphStyleAttributeName:style, NSForegroundColorAttributeName:textColor}; 407 | 408 | CGSize sz = [self.title sizeWithAttributes:attr]; 409 | 410 | [self.title drawInRect:CGRectMake(titleBarRect.origin.x, titleBarRect.origin.y+(titleBarRect.size.height-sz.height)/2, titleBarRect.size.width, sz.height) withAttributes:attr]; 411 | } 412 | #endif 413 | 414 | 415 | if (self.isKeyWindow && !self.maximized) 416 | { 417 | if (_inWindowResize) 418 | { 419 | CGRect leftResizeRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y+kWindowResizeGutterSize, kWindowResizeGutterSize, self.bounds.size.height-(kWindowResizeGutterSize*2)); 420 | CGRect rightResizeRect = CGRectMake(self.bounds.origin.x+self.bounds.size.width-kWindowResizeGutterSize, self.bounds.origin.y+kWindowResizeGutterSize, kWindowResizeGutterSize, self.bounds.size.height-(kWindowResizeGutterSize*2)); 421 | 422 | CGRect bottomResizeRect = CGRectMake(self.bounds.origin.x+kWindowResizeGutterSize, self.bounds.origin.y+self.bounds.size.height-kWindowResizeGutterSize, self.bounds.size.width-(kWindowResizeGutterSize*2), kWindowResizeGutterSize); 423 | 424 | [[UIColor colorWithWhite:0.0 alpha:0.3] setFill]; 425 | 426 | if (resizeAxis == WMResizeRight) 427 | { 428 | [[UIBezierPath bezierPathWithRoundedRect:rightResizeRect cornerRadius:3.0] fill]; 429 | } 430 | 431 | if (resizeAxis == WMResizeLeft) 432 | { 433 | [[UIBezierPath bezierPathWithRoundedRect:leftResizeRect cornerRadius:3.0] fill]; 434 | } 435 | 436 | if (resizeAxis == WMResizeBottom) 437 | { 438 | [[UIBezierPath bezierPathWithRoundedRect:bottomResizeRect cornerRadius:3.0] fill]; 439 | } 440 | } 441 | 442 | 443 | [[UIColor colorWithWhite:1 alpha:0.3] setFill]; 444 | 445 | [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(CGRectGetMidX(self.bounds)-kWindowResizeGutterKnobSize/2, CGRectGetMaxY(self.bounds)-kWindowResizeGutterKnobWidth-(kWindowResizeGutterSize-kWindowResizeGutterKnobWidth)/2, kWindowResizeGutterKnobSize, kWindowResizeGutterKnobWidth) cornerRadius:2] fill]; 446 | 447 | [[UIBezierPath bezierPathWithRoundedRect:CGRectMake((kWindowResizeGutterSize-kWindowResizeGutterKnobWidth)/2, CGRectGetMidY(self.bounds)-kWindowResizeGutterKnobSize/2, kWindowResizeGutterKnobWidth, kWindowResizeGutterKnobSize) cornerRadius:2] fill]; 448 | 449 | [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(CGRectGetMaxX(self.bounds)-kWindowResizeGutterKnobWidth-(kWindowResizeGutterSize-kWindowResizeGutterKnobWidth)/2, CGRectGetMidY(self.bounds)-kWindowResizeGutterKnobSize/2, kWindowResizeGutterKnobWidth, kWindowResizeGutterKnobSize) cornerRadius:2] fill]; 450 | } 451 | } 452 | 453 | 454 | @end 455 | -------------------------------------------------------------------------------- /WindowManager/en.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /WindowManager/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WindowManager 4 | // 5 | // Created by Steven Troughton-Smith on 23/12/2015. 6 | // Copyright © 2015 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | --------------------------------------------------------------------------------