├── Inbox for Mac ├── appicon.icns ├── main.m ├── AppDelegate.h ├── Extensions │ ├── INWindowBackgroundView+CoreUIRendering.h │ ├── INAppStoreWindowSwizzling.h │ ├── NSDocument+INAppStoreWindowFixes.h │ ├── INAppStoreWindowSwizzling.c │ ├── NSDocument+INAppStoreWindowFixes.m │ └── INWindowBackgroundView+CoreUIRendering.m ├── ViewController.h ├── AppDelegate.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── INWindowButton.h ├── INAppStoreWindowCompatibility.h ├── ViewController.m ├── WAYAppStoreWindow.m ├── WAYWindow.h ├── INWindowButton.m ├── INAppStoreWindow.h ├── WAYAppStoreWindow.h ├── WAYWindow.m └── Base.lproj │ └── Main.storyboard ├── Inbox for Mac.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── Inbox for Mac.xccheckout ├── xcuserdata │ └── amonk.xcuserdatad │ │ ├── xcschemes │ │ ├── xcschememanagement.plist │ │ └── Inbox for Mac.xcscheme │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist └── project.pbxproj ├── README.md └── Inbox for MacTests ├── Info.plist └── Inbox_for_MacTests.m /Inbox for Mac/appicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/almonk/Inbox-for-Mac/HEAD/Inbox for Mac/appicon.icns -------------------------------------------------------------------------------- /Inbox for Mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Inbox for Mac/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Inbox for Mac 4 | // 5 | // Created by Alasdair Lampon-Monk on 9/16/15. 6 | // Copyright (c) 2015 Alasdair Lampon-Monk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /Inbox for Mac/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Inbox for Mac 4 | // 5 | // Created by Alasdair Lampon-Monk on 9/16/15. 6 | // Copyright (c) 2015 Alasdair Lampon-Monk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Inbox for Mac/Extensions/INWindowBackgroundView+CoreUIRendering.h: -------------------------------------------------------------------------------- 1 | // 2 | // INWindowBackgroundView+CoreUIRendering.h 3 | // 4 | // Copyright (c) 2014 Petroules Corporation. All rights reserved. 5 | // 6 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 7 | // code of this project. 8 | // 9 | 10 | #import "INAppStoreWindow.h" 11 | 12 | @interface INWindowBackgroundView (CoreUIRendering) 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Inbox for Mac/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Inbox for Mac 4 | // 5 | // Created by Alasdair Lampon-Monk on 9/16/15. 6 | // Copyright (c) 2015 Alasdair Lampon-Monk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface ViewController : NSViewController { 13 | IBOutlet WebView *webView; 14 | IBOutlet WebView *webView2; 15 | } 16 | 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Inbox for Mac/Extensions/INAppStoreWindowSwizzling.h: -------------------------------------------------------------------------------- 1 | // 2 | // INAppStoreWindowSwizzling.h 3 | // 4 | // Created by Jake Petroules on 1/13/2014. 5 | // Copyright (c) 2011-2014 Indragie Karunaratne. All rights reserved. 6 | // 7 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 8 | // code of this project. 9 | // 10 | 11 | #import 12 | 13 | void INAppStoreWindowSwizzle(Class c, SEL orig, SEL new); 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inbox-for-Mac 2 | A handsomely simple OSX app wrapper around Google Inbox. Use Inbox as if it were a native OSX app. 3 | 4 | #### Features 5 | * Cleanly supports multiple accounts 6 | * URLs open in your default browser 7 | * Beautiful app icon by Jason Zigrino (source) 8 | 9 | #### Installation 10 | * Download the latest binary 11 | * Drag to your `/Applications` folder 12 | 13 | 14 | -------------------------------------------------------------------------------- /Inbox for Mac/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Inbox for Mac 4 | // 5 | // Created by Alasdair Lampon-Monk on 9/16/15. 6 | // Copyright (c) 2015 Alasdair Lampon-Monk. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 18 | // Insert code here to initialize your application 19 | } 20 | 21 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 22 | // Insert code here to tear down your application 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Inbox for Mac.xcodeproj/xcuserdata/amonk.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Inbox for Mac.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9F836A291BA9C09B00DE4D39 16 | 17 | primary 18 | 19 | 20 | 9F836A3F1BA9C09C00DE4D39 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Inbox for Mac/Extensions/NSDocument+INAppStoreWindowFixes.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDocument+INAppStoreWindowFixes.h 3 | // SampleApp 4 | // 5 | // Created by Indragie Karunaratne on 1/5/2014. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 9 | // code of this project. 10 | // 11 | 12 | #import 13 | 14 | // Fix for the issue described here: https://github.com/indragiek/INAppStoreWindow/issues/91 15 | // 16 | // Including this category in your project will swizzle NSDocument -updateChangeCount: such 17 | // that any INAppStoreWindow instances belonging to the document's window controllers will 18 | // automatically relayout their title bars when the change count is updated. 19 | @interface NSDocument (INAppStoreWindowFixes) 20 | @end 21 | -------------------------------------------------------------------------------- /Inbox for MacTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | alasdairmonk.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Inbox for Mac/Extensions/INAppStoreWindowSwizzling.c: -------------------------------------------------------------------------------- 1 | // 2 | // INAppStoreWindowSwizzling.c 3 | // 4 | // Created by Jake Petroules on 1/13/2014. 5 | // Copyright (c) 2011-2014 Indragie Karunaratne. All rights reserved. 6 | // 7 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 8 | // code of this project. 9 | // 10 | 11 | #import "INAppStoreWindowSwizzling.h" 12 | 13 | void INAppStoreWindowSwizzle(Class c, SEL orig, SEL new) 14 | { 15 | Method origMethod = class_getInstanceMethod(c, orig); 16 | Method newMethod = class_getInstanceMethod(c, new); 17 | if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { 18 | class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); 19 | } else { 20 | method_exchangeImplementations(origMethod, newMethod); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Inbox for Mac.xcodeproj/xcuserdata/amonk.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Inbox for MacTests/Inbox_for_MacTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Inbox_for_MacTests.m 3 | // Inbox for MacTests 4 | // 5 | // Created by Alasdair Lampon-Monk on 9/16/15. 6 | // Copyright (c) 2015 Alasdair Lampon-Monk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface Inbox_for_MacTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation Inbox_for_MacTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Inbox for Mac/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Inbox for Mac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | appicon.icns 11 | CFBundleIdentifier 12 | alasdairmonk.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2015 Alasdair Monk. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /Inbox for Mac/Extensions/NSDocument+INAppStoreWindowFixes.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDocument+INAppStoreWindowFixes.m 3 | // SampleApp 4 | // 5 | // Created by Indragie Karunaratne on 1/5/2014. 6 | // Copyright (c) 2014 Indragie Karunaratne. All rights reserved. 7 | // 8 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 9 | // code of this project. 10 | // 11 | 12 | #import "NSDocument+INAppStoreWindowFixes.h" 13 | #import "INAppStoreWindow.h" 14 | #import "INAppStoreWindowSwizzling.h" 15 | 16 | @interface INAppStoreWindow (Private) 17 | - (void)_layoutTrafficLightsAndContent; 18 | @end 19 | 20 | @implementation NSDocument (INAppStoreWindowFixes) 21 | 22 | + (void)load 23 | { 24 | INAppStoreWindowSwizzle(self, @selector(updateChangeCount:), @selector(ind_updateChangeCount:)); 25 | } 26 | 27 | - (void)ind_updateChangeCount:(NSDocumentChangeType)changeType 28 | { 29 | [self ind_updateChangeCount:changeType]; // Original implementation 30 | NSArray *windowControllers = self.windowControllers; 31 | for (NSWindowController *wc in windowControllers) { 32 | if ([wc.window isKindOfClass:INAppStoreWindow.class]) { 33 | [(INAppStoreWindow *)wc.window _layoutTrafficLightsAndContent]; 34 | } 35 | } 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Inbox for Mac.xcodeproj/project.xcworkspace/xcshareddata/Inbox for Mac.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | AED412BF-A74D-4C69-8EBB-747F187A49F4 9 | IDESourceControlProjectName 10 | Inbox for Mac 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C094795CC3531D29D7A2A8916814F085D9823269 14 | https://github.com/almonk/Inbox-for-Mac.git 15 | 16 | IDESourceControlProjectPath 17 | Inbox for Mac.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C094795CC3531D29D7A2A8916814F085D9823269 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/almonk/Inbox-for-Mac.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C094795CC3531D29D7A2A8916814F085D9823269 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C094795CC3531D29D7A2A8916814F085D9823269 36 | IDESourceControlWCCName 37 | Inbox%20for%20Mac 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Inbox for Mac/INWindowButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // INWindowButton.h 3 | // 4 | // Copyright 2013-2014 Vladislav Alexeev. All rights reserved. 5 | // 6 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 7 | // code of this project. 8 | // 9 | 10 | #import 11 | 12 | /** 13 | A concrete NSButton subclass that allows to mimic standard window title bar "traffic light" buttons 14 | and replace their graphics with custom ones. 15 | */ 16 | @interface INWindowButton : NSButton 17 | 18 | /** 19 | The group identifier the receiver was initialized with. 20 | */ 21 | @property (nonatomic, copy, readonly) NSString *groupIdentifier; 22 | 23 | /** 24 | An image for the normal state. 25 | */ 26 | @property (nonatomic, strong) NSImage *activeImage; 27 | 28 | /** 29 | An image for the normal state, but displayed when receiver's window in not a key. 30 | */ 31 | @property (nonatomic, strong) NSImage *activeNotKeyWindowImage; 32 | 33 | /** 34 | An image used in disabled state. 35 | */ 36 | @property (nonatomic, strong) NSImage *inactiveImage; 37 | 38 | /** 39 | An image used when user hovers receiver with mouse pointer. 40 | */ 41 | @property (nonatomic, strong) NSImage *rolloverImage; 42 | 43 | /** 44 | An image for the pressed state. 45 | */ 46 | @property (nonatomic, strong) NSImage *pressedImage; 47 | 48 | /** 49 | @param size Designated size of the button. System size is 14x16 and you are considered to use it. 50 | @param groupIdentifier ID of the group which will apply rollover effect to its members. 51 | You may pass \c nil. 52 | @see initWithSize:groupIdentifier: 53 | */ 54 | + (instancetype)windowButtonWithSize:(NSSize)size groupIdentifier:(NSString *)groupIdentifier; 55 | 56 | /** 57 | @abstract Designated initializer. 58 | @discussion Initializes the receiver with the given size and includes it in the group with the 59 | given identifier. 60 | Groups are used to apply rollover effect to all buttons that are inside the same group. 61 | For example, close, minimize and zoom buttons should be inside the same group since they all get a 62 | rollover effect when the mouse pointer hovers over one of these buttons. 63 | @param size Designated size of the button. System size is 14x16 and you are considered to use it. 64 | @param groupIdentifier ID of the group which will apply rollover effect to its members. 65 | You may pass \c nil. 66 | */ 67 | - (instancetype)initWithSize:(NSSize)size groupIdentifier:(NSString *)groupIdentifier; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Inbox for Mac/INAppStoreWindowCompatibility.h: -------------------------------------------------------------------------------- 1 | // 2 | // INAppStoreWindowCompatibility.h 3 | // INAppStoreWindow 4 | // 5 | // Copyright (c) 2011-2014 Indragie Karunaratne. All rights reserved. 6 | // Copyright (c) 2014 Petroules Corporation. All rights reserved. 7 | // 8 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 9 | // code of this project. 10 | // 11 | 12 | #import 13 | 14 | #ifndef NSAppKitVersionNumber10_7 15 | #define NSAppKitVersionNumber10_7 1138 16 | #endif 17 | 18 | #ifndef NSAppKitVersionNumber10_9 19 | #define NSAppKitVersionNumber10_9 1265 20 | #endif 21 | 22 | #ifndef NSAppKitVersionNumber10_10 23 | #define NSAppKitVersionNumber10_10 1343 24 | #endif 25 | 26 | #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1070 27 | enum { NSWindowDocumentVersionsButton = 6, NSWindowFullScreenButton = 7 }; 28 | enum { NSFullScreenWindowMask = 1 << 14 }; 29 | extern NSString * const NSAccessibilityFullScreenButtonSubrole; 30 | extern NSString * const NSWindowWillEnterFullScreenNotification; 31 | extern NSString * const NSWindowDidEnterFullScreenNotification; 32 | extern NSString * const NSWindowWillExitFullScreenNotification; 33 | extern NSString * const NSWindowDidExitFullScreenNotification; 34 | extern NSString * const NSWindowWillEnterVersionBrowserNotification; 35 | extern NSString * const NSWindowDidEnterVersionBrowserNotification; 36 | extern NSString * const NSWindowWillExitVersionBrowserNotification; 37 | extern NSString * const NSWindowDidExitVersionBrowserNotification; 38 | #endif 39 | 40 | #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080 41 | @interface NSDictionary (INNSDictionaryBackwardCompatibility) 42 | 43 | // NS_AVAILABLE(10_8, 6_0), but this is a lie - this responds in 10.7 44 | - (id)objectForKeyedSubscript:(id)aKey; 45 | 46 | @end 47 | 48 | @interface NSMutableDictionary (INNSMutableDictionaryBackwardCompatibility) 49 | 50 | // NS_AVAILABLE(10_8, 6_0), but this is a lie - this responds in 10.7 51 | - (void)setObject:(id)obj forKeyedSubscript:(id )key; 52 | 53 | @end 54 | #endif 55 | 56 | #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1090 57 | @interface NSArray (INNSArrayBackwardCompatibility) 58 | - (id)firstObject; // not present in the 10.8 SDK but available since 10.6 59 | @end 60 | 61 | @interface NSData (INNSDataBackwardCompatibility) 62 | - (id)initWithBase64Encoding:(NSString *)base64String; 63 | @end 64 | #endif 65 | 66 | NS_INLINE bool INRunningLion() { 67 | return (NSInteger)NSAppKitVersionNumber >= NSAppKitVersionNumber10_7; 68 | } 69 | 70 | NS_INLINE bool INRunningMavericks() { 71 | return (NSInteger)NSAppKitVersionNumber >= NSAppKitVersionNumber10_9; 72 | } 73 | 74 | NS_INLINE bool INRunningYosemite() { 75 | return (NSInteger)NSAppKitVersionNumber >= NSAppKitVersionNumber10_10; 76 | } 77 | -------------------------------------------------------------------------------- /Inbox for Mac/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Inbox for Mac 4 | // 5 | // Created by Alasdair Lampon-Monk on 9/16/15. 6 | // Copyright (c) 2015 Alasdair Lampon-Monk. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @implementation ViewController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | 16 | [webView setPolicyDelegate:self]; 17 | 18 | NSURL*url=[NSURL URLWithString:@"https://inbox.google.com/u/0/"]; 19 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 20 | [webView setCustomUserAgent:@"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"]; 21 | [[webView mainFrame] loadRequest:request]; 22 | 23 | [webView2 setPolicyDelegate:self]; 24 | 25 | NSURL*url2=[NSURL URLWithString:@"https://inbox.google.com/u/1/"]; 26 | NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:url2]; 27 | [webView2 setCustomUserAgent:@"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"]; 28 | [[webView2 mainFrame] loadRequest:request2]; 29 | // Do any additional setup after loading the view. 30 | } 31 | 32 | - (void)setRepresentedObject:(id)representedObject { 33 | [super setRepresentedObject:representedObject]; 34 | // Update the view, if already loaded. 35 | } 36 | // 37 | //- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request 38 | //{ 39 | // // HACK: This is all a hack to get around a bug/misfeature in Tiger's WebKit 40 | // // (should be fixed in Leopard). On Javascript window.open, Tiger sends a null 41 | // // request here, then sends a loadRequest: to the new WebView, which will 42 | // // include a decidePolicyForNavigation (which is where we'll open our 43 | // // external window). In Leopard, we should be getting the request here from 44 | // // the start, and we should just be able to create a new window. 45 | // 46 | // WebView *newWebView = [[WebView alloc] init]; 47 | // [newWebView setUIDelegate:self]; 48 | // [newWebView setPolicyDelegate:self]; 49 | // 50 | // return newWebView; 51 | //} 52 | 53 | - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { 54 | if( [sender isEqual:webView] ) { 55 | [listener use]; 56 | } 57 | else { 58 | 59 | if ([[[actionInformation valueForKey:WebActionOriginalURLKey] absoluteString]containsString:@".google.com"]) { 60 | [listener use]; 61 | } else { 62 | [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]]; 63 | [listener ignore]; 64 | } 65 | 66 | } 67 | } 68 | 69 | - (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id)listener { 70 | NSLog(@"%@", [actionInformation valueForKey:WebActionOriginalURLKey]); 71 | 72 | if ([[[actionInformation valueForKey:WebActionOriginalURLKey] absoluteString]containsString:@".google.com"]) { 73 | NSURL*url=[NSURL URLWithString:[[actionInformation valueForKey:WebActionOriginalURLKey] absoluteString]]; 74 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 75 | [[webView mainFrame] loadRequest:request]; 76 | [listener use]; 77 | } else { 78 | [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]]; 79 | [listener ignore]; 80 | } 81 | 82 | 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Inbox for Mac/WAYAppStoreWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // WAYAppStoreWindow.m 3 | // WAYAppStoreWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 Raffael Hannemann. All rights reserved. 7 | // Visit weAreYeah.com or follow @weareYeah for updates. 8 | // 9 | // Licensed under the BSD License 10 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 11 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 12 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 13 | // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 14 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 15 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 16 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 17 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 18 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | // 20 | 21 | #import "WAYAppStoreWindow.h" 22 | #import 23 | #import "WAYWindow.h" 24 | #import "INAppStoreWindow.h" 25 | 26 | // Set this flag to 1, if you want to force the usage of INAppStoreWindow 27 | #define SIMULATE_PRE_YOSEMITE 0 28 | 29 | #pragma mark - WAYDefensiveWindow 30 | /** Internally, if the class decides to use WAYWindow instead of INAppStoreWindow, we won't use WAYWindow directly, but its subclass WAYDefensiveWindow instead, which logs warnings, if the developer calls a method, which is only implemented by INAppStoreWindow. This may happen if the developer tries to make use of features of INAppStoreWindow, which have not been ported yet to WAYWindow. */ 31 | @interface WAYDefensiveWindow : WAYWindow 32 | @end 33 | 34 | // DUMMY FUNCTION 35 | void WAYDefensiveWindowDummyIMP(id self, SEL _cmd) { 36 | // This function will be used as method implementation for 37 | // methods which are available in INAppStoreWindow, but not 38 | // in WAYWindow 39 | NSLog(@"WARNING: Instances of '%@' do not implement %@; yet. Prevented an exception for sending unrecognized selector.", 40 | [self superclass], 41 | NSStringFromSelector(_cmd)); 42 | } 43 | 44 | @implementation WAYDefensiveWindow : WAYWindow 45 | 46 | + (BOOL) resolveInstanceMethod:(SEL)aSelector { 47 | // If INAppStoreWindow implements this method, and WAYWindow does not, add a new dummy method, which does nothing but logging a warning. 48 | if ([INAppStoreWindow instancesRespondToSelector:aSelector] && ![WAYWindow instancesRespondToSelector:aSelector]) { 49 | class_addMethod([self class], aSelector, (IMP)WAYDefensiveWindowDummyIMP, "v@:"); 50 | return YES; 51 | } 52 | return [super resolveInstanceMethod:aSelector]; 53 | } 54 | 55 | @end 56 | 57 | /** We need to add private properties of the NSWindow subclasses here. */ 58 | @class WAYWindowDelegateProxy; 59 | @interface WAYAppStoreWindow () 60 | @property (strong) WAYWindowDelegateProxy* delegateProxy; 61 | @property (strong) NSArray* standardButtons; 62 | @property (strong) NSTitlebarAccessoryViewController *dummyTitlebarAccessoryViewController; 63 | @end 64 | 65 | static int isYosemiteOrGreater = -1; 66 | 67 | // Let's suppress Incomplete Implementation warnings 68 | #pragma clang diagnostic ignored "-Wincomplete-implementation" 69 | @implementation WAYAppStoreWindow 70 | 71 | + (BOOL) isYosemiteOrGreater { 72 | if (isYosemiteOrGreater==-1) { 73 | isYosemiteOrGreater = NSClassFromString(@"NSVisualEffectView")!=nil ? 1 : 0; 74 | #if SIMULATE_PRE_YOSEMITE 75 | isYosemiteOrGreater = 0; 76 | #endif 77 | } 78 | return isYosemiteOrGreater; 79 | } 80 | 81 | /** All we do is to swap the class implementation at runtime. */ 82 | + (instancetype)alloc { 83 | id instance = [super alloc]; 84 | object_setClass(instance, ([self isYosemiteOrGreater]) ? [WAYDefensiveWindow class] : [INAppStoreWindow class]); 85 | return instance; 86 | } 87 | 88 | + (instancetype) allocWithZone:(struct _NSZone *)zone { 89 | id instance = [super allocWithZone:zone]; 90 | object_setClass(instance, ([self isYosemiteOrGreater]) ? [WAYDefensiveWindow class] : [INAppStoreWindow class]); 91 | return instance; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /Inbox for Mac/WAYWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // WAYWindow.m 3 | // WAYWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 Raffael Hannemann. All rights reserved. 7 | // Visit weAreYeah.com or follow @weareYeah for updates. 8 | // 9 | // Licensed under the BSD License 10 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 11 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 12 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 13 | // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 14 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 15 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 16 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 17 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 18 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | // 20 | 21 | #import 22 | 23 | /** This NSWindow subclass provides an interface to enable OS X 10.10 Yosemite exclusive features conveniently. Next to customizing the look of the WAYWindow content view, you can also customize the title bar and standard window buttons (`traffic lights´). The public interface is generally similar to INAppStoreWindow to simplify the migration. 24 | Whenever it makes sense, the properties of your WAYWindow instance in Interface Builder are inspectable. 25 | 26 | Tips: 27 | - Check out the WWDC '14 session `Adopting Advanced Features of the New UI of OS X Yosemite´, which provides more details on how to make use of the new Yosemite APIs. 28 | - Also check out the new APIs in NSScrollView to make use of contentInsets, scrollInsets, and more. 29 | */ 30 | @interface WAYWindow : NSWindow 31 | 32 | /// Returns YES, if the class supports vibrant appearances. Can be used to determine if running on OS X 10.10+ 33 | + (BOOL) supportsVibrantAppearances; 34 | 35 | /// Defines the window's titlebar height. Defaut: OS X default value. 36 | @property (nonatomic) IBInspectable CGFloat titleBarHeight; 37 | 38 | //// Returns the titlebar view of the window, which you can add arbitrary subviews to. 39 | @property (strong,readonly) IBOutlet NSView *titleBarView; 40 | 41 | /// If set to YES, the standard window button will be vertically centered. Default: YES. 42 | @property (nonatomic) IBInspectable BOOL centerTrafficLightButtons; 43 | 44 | /// Defines the left margin of the standard window buttons. Defaut: OS X default value. 45 | @property (nonatomic) IBInspectable CGFloat trafficLightButtonsLeftMargin; 46 | 47 | /// Defines the top margin of the standard window buttons. Used if not centered. Defaut: OS X default value. 48 | @property (nonatomic) IBInspectable CGFloat trafficLightButtonsTopMargin; 49 | 50 | /// If set to YES, the title of the window will be hidden. Default: YES. 51 | @property (nonatomic) IBInspectable BOOL hidesTitle; 52 | 53 | /// Replaces the window's content view with an instance of NSVisualEffectView and applies the Vibrant Dark look. Transfers all subviews to the new content view. 54 | - (void) setContentViewAppearanceVibrantDark; 55 | 56 | /// Replaces the window's content view with an instance of NSVisualEffectView and applies the Vibrant Light look. Transfers all subviews to the new content view. 57 | - (void) setContentViewAppearanceVibrantLight; 58 | 59 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantDark 60 | - (void) setVibrantDarkAppearance; 61 | 62 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantLight 63 | - (void) setVibrantLightAppearance; 64 | 65 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantAqua 66 | - (void) setAquaAppearance; 67 | 68 | /// Replaces a view of the window subview hierarchy with the specified view, and transfers all current subviews to the new one. The frame of the new view will be set to the frame of the old view, if flag is YES. 69 | - (void) replaceSubview: (NSView *) aView withView: (NSView *) newView resizing: (BOOL) flag; 70 | 71 | /// Replaces a view of the window subview hierarchy with a new view of the specified NSView class, and transfers all current subviews to the new one. 72 | - (NSView *) replaceSubview: (NSView *) aView withViewOfClass: (Class) newViewClass; 73 | 74 | /// Returns YES if the window is currently in full-screen. 75 | - (BOOL) isFullScreen; 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Inbox for Mac.xcodeproj/xcuserdata/amonk.xcuserdatad/xcschemes/Inbox for Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Inbox for Mac/Extensions/INWindowBackgroundView+CoreUIRendering.m: -------------------------------------------------------------------------------- 1 | // 2 | // INWindowBackgroundView+CoreUIRendering.m 3 | // 4 | // Copyright (c) 2014 Petroules Corporation. All rights reserved. 5 | // 6 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 7 | // code of this project. 8 | // 9 | 10 | #import "INAppStoreWindow.h" 11 | #import "INAppStoreWindowCompatibility.h" 12 | #import "INAppStoreWindowSwizzling.h" 13 | #import "INWindowBackgroundView+CoreUIRendering.h" 14 | #import 15 | 16 | #if !defined(INAPPSTOREWINDOW_NO_COREUI) || !INAPPSTOREWINDOW_NO_COREUI 17 | 18 | typedef CFTypeRef CUIRendererRef; 19 | typedef void (*_CUIDraw)(CUIRendererRef renderer, CGRect frame, CGContextRef context, CFDictionaryRef options, CFDictionaryRef *result); 20 | static _CUIDraw CUIDraw = 0; 21 | 22 | static NSString * const kCUIIsFlippedKey = @"is.flipped"; 23 | static NSString * const kCUIStateActive = @"normal"; 24 | static NSString * const kCUIStateInactive = @"inactive"; 25 | static NSString * const kCUIStateKey = @"state"; 26 | static NSString * const kCUIWidgetKey = @"widget"; 27 | static NSString * const kCUIWidgetWindowBottomBar = @"kCUIWidgetWindowBottomBar"; 28 | static NSString * const kCUIWidgetWindowFrame = @"kCUIWidgetWindowFrame"; 29 | static NSString * const kCUIWindowFrameBottomBarHeightKey = @"kCUIWindowFrameBottomBarHeightKey"; 30 | static NSString * const kCUIWindowFrameDrawBottomBarSeparatorKey = @"kCUIWindowFrameDrawBottomBarSeparatorKey"; 31 | static NSString * const kCUIWindowFrameDrawTitleSeparatorKey = @"kCUIWindowFrameDrawTitleSeparatorKey"; 32 | static NSString * const kCUIWindowFrameRoundedBottomCornersKey = @"kCUIWindowFrameRoundedBottomCornersKey"; 33 | static NSString * const kCUIWindowFrameRoundedTopCornersKey = @"kCUIWindowFrameRoundedTopCornersKey"; 34 | static NSString * const kCUIWindowFrameUnifiedTitleBarHeightKey = @"kCUIWindowFrameUnifiedTitleBarHeightKey"; 35 | static NSString * const kCUIWindowTypeDocument = @"regularwin"; 36 | static NSString * const kCUIWindowTypeKey = @"windowtype"; 37 | 38 | @interface NSWindow (NSWindowPrivate) 39 | 40 | + (CUIRendererRef)coreUIRenderer; 41 | 42 | @end 43 | 44 | @interface /* NSAppearance */ NSObject (NSAppearancePrivate) 45 | 46 | - (void)_drawInRect:(CGRect)rect context:(CGContextRef)cgContext options:(CFDictionaryRef)options; 47 | 48 | @end 49 | 50 | @interface INWindowBackgroundView () 51 | 52 | - (void)drawWindowBackgroundLayersInRect:(NSRect)drawingRect forEdge:(NSRectEdge)drawingEdge showsSeparator:(BOOL)showsSeparator clippingPath:(CGPathRef)clippingPath; 53 | 54 | @end 55 | 56 | #endif // !defined(INAPPSTOREWINDOW_NO_COREUI) || !INAPPSTOREWINDOW_NO_COREUI 57 | 58 | @implementation INWindowBackgroundView (CoreUIRendering) 59 | 60 | #if !defined(INAPPSTOREWINDOW_NO_COREUI) || !INAPPSTOREWINDOW_NO_COREUI 61 | 62 | + (void)load 63 | { 64 | CFBundleRef bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.coreui")); 65 | if ((CUIDraw = CFBundleGetFunctionPointerForName(bundle, CFSTR("CUIDraw"))) && 66 | [NSWindow respondsToSelector:@selector(coreUIRenderer)]) { 67 | INAppStoreWindowSwizzle(self, 68 | @selector(drawWindowBackgroundLayersInRect:forEdge:showsSeparator:clippingPath:), 69 | @selector(drawCUIWindowBackgroundLayersInRect:forEdge:showsSeparator:clippingPath:)); 70 | 71 | [self loadConstant:&kCUIIsFlippedKey named:@"kCUIIsFlippedKey" fromBundle:bundle]; 72 | [self loadConstant:&kCUIStateActive named:@"kCUIStateActive" fromBundle:bundle]; 73 | [self loadConstant:&kCUIStateInactive named:@"kCUIStateInactive" fromBundle:bundle]; 74 | [self loadConstant:&kCUIStateKey named:@"kCUIStateKey" fromBundle:bundle]; 75 | [self loadConstant:&kCUIWidgetKey named:@"kCUIWidgetKey" fromBundle:bundle]; 76 | [self loadConstant:&kCUIWidgetWindowBottomBar named:@"kCUIWidgetWindowBottomBar" fromBundle:bundle]; 77 | [self loadConstant:&kCUIWidgetWindowFrame named:@"kCUIWidgetWindowFrame" fromBundle:bundle]; 78 | [self loadConstant:&kCUIWindowFrameBottomBarHeightKey named:@"kCUIWindowFrameBottomBarHeightKey" fromBundle:bundle]; 79 | [self loadConstant:&kCUIWindowFrameDrawBottomBarSeparatorKey named:@"kCUIWindowFrameDrawBottomBarSeparatorKey" fromBundle:bundle]; 80 | [self loadConstant:&kCUIWindowFrameDrawTitleSeparatorKey named:@"kCUIWindowFrameDrawTitleSeparatorKey" fromBundle:bundle]; 81 | [self loadConstant:&kCUIWindowFrameRoundedBottomCornersKey named:@"kCUIWindowFrameRoundedBottomCornersKey" fromBundle:bundle]; 82 | [self loadConstant:&kCUIWindowFrameRoundedTopCornersKey named:@"kCUIWindowFrameRoundedTopCornersKey" fromBundle:bundle]; 83 | [self loadConstant:&kCUIWindowFrameUnifiedTitleBarHeightKey named:@"kCUIWindowFrameUnifiedTitleBarHeightKey" fromBundle:bundle]; 84 | [self loadConstant:&kCUIWindowTypeDocument named:@"kCUIWindowTypeDocument" fromBundle:bundle]; 85 | [self loadConstant:&kCUIWindowTypeKey named:@"kCUIWindowTypeKey" fromBundle:bundle]; 86 | } else { 87 | NSLog(@"Failed to load CoreUI, falling back to custom drawing"); 88 | } 89 | } 90 | 91 | + (void)loadConstant:(NSString * const *)constant named:(NSString *)constantName fromBundle:(CFBundleRef)bundle 92 | { 93 | NSString * const *_constant = (NSString * const *)(CFBundleGetDataPointerForName(bundle, (__bridge CFStringRef)(constantName))); 94 | if (_constant) { 95 | *((NSString **)constant) = *_constant; 96 | } else { 97 | NSLog(@"Failed to load %@, using fallback value %@", constantName, *constant); 98 | } 99 | } 100 | 101 | - (void)drawCUIWindowBackgroundLayersInRect:(CGRect)drawingRect forEdge:(CGRectEdge)edge showsSeparator:(BOOL)showsSeparator clippingPath:(CGPathRef)clippingPath 102 | { 103 | INAppStoreWindow *window = (INAppStoreWindow *)self.window; 104 | NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary: 105 | @{kCUIStateKey: (window.isMainWindow ? kCUIStateActive : kCUIStateInactive), 106 | kCUIWidgetKey: kCUIWidgetWindowFrame, 107 | kCUIWindowTypeKey: kCUIWindowTypeDocument, 108 | kCUIIsFlippedKey: @(self.isFlipped)}]; 109 | if (edge == CGRectMaxYEdge) { 110 | options[kCUIWindowFrameUnifiedTitleBarHeightKey] = @(window.titleBarHeight + window.toolbarHeight); 111 | options[kCUIWindowFrameDrawTitleSeparatorKey] = @(showsSeparator); 112 | options[kCUIWindowFrameRoundedBottomCornersKey] = @(NO); 113 | options[kCUIWindowFrameRoundedTopCornersKey] = @(YES); 114 | } else if (edge == CGRectMinYEdge) { 115 | // NOTE: While kCUIWidgetWindowBottomBar can be used to draw a bottom bar, this only allows 116 | // it to be drawn with the separator shown as kCUIWindowFrameDrawBottomBarSeparatorKey only 117 | // applies to the kCUIWidgetWindowFrame widget. So we use that instead; it produces 118 | // identical results... except in Yosemite where the other options work correctly. 119 | if (INRunningYosemite()) { 120 | options[kCUIWidgetKey] = kCUIWidgetWindowBottomBar; 121 | } 122 | options[kCUIWindowFrameBottomBarHeightKey] = @(window.bottomBarHeight); 123 | options[kCUIWindowFrameDrawBottomBarSeparatorKey] = @(showsSeparator); 124 | options[kCUIWindowFrameRoundedBottomCornersKey] = @(YES); 125 | options[kCUIWindowFrameRoundedTopCornersKey] = @(NO); 126 | } 127 | 128 | id appearance = nil; 129 | if (INRunningMavericks()) { 130 | Class clazz = NSClassFromString(@"NSAppearance"); 131 | if ([clazz respondsToSelector:@selector(currentAppearance)]) { 132 | appearance = [clazz performSelector:@selector(currentAppearance)]; 133 | } 134 | } 135 | 136 | if ([appearance respondsToSelector:@selector(_drawInRect:context:options:)]) { 137 | [appearance _drawInRect:drawingRect context:[[NSGraphicsContext currentContext] graphicsPort] options:(__bridge CFDictionaryRef)options]; 138 | } else { 139 | CUIDraw([NSWindow coreUIRenderer], drawingRect, [[NSGraphicsContext currentContext] graphicsPort], (__bridge CFDictionaryRef) options, nil); 140 | } 141 | } 142 | 143 | #endif // !defined(INAPPSTOREWINDOW_NO_COREUI) || !INAPPSTOREWINDOW_NO_COREUI 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /Inbox for Mac/INWindowButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // INWindowButton.m 3 | // 4 | // Copyright 2013-2014 Vladislav Alexeev. All rights reserved. 5 | // 6 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 7 | // code of this project. 8 | // 9 | 10 | #import "INAppStoreWindowCompatibility.h" 11 | #import "INWindowButton.h" 12 | 13 | #pragma mark - Window Button Group 14 | 15 | NSString *const INWindowButtonGroupDidUpdateRolloverStateNotification = @"INWindowButtonGroupDidUpdateRolloverStateNotification"; 16 | NSString *const kINWindowButtonGroupDefault = @"com.indragie.inappstorewindow.defaultWindowButtonGroup"; 17 | 18 | @interface INWindowButtonGroup : NSObject 19 | 20 | + (instancetype)groupWithIdentifier:(NSString *)identifier; 21 | @property (nonatomic, copy, readonly) NSString *identifier; 22 | 23 | - (void)didCaptureMousePointer; 24 | - (void)didReleaseMousePointer; 25 | - (BOOL)shouldDisplayRollOver; 26 | 27 | - (void)resetMouseCaptures; 28 | 29 | @end 30 | 31 | @interface INWindowButtonGroup () 32 | @property (nonatomic, assign) NSInteger numberOfCaptures; 33 | @end 34 | 35 | @implementation INWindowButtonGroup 36 | 37 | + (instancetype)groupWithIdentifier:(NSString *)identifier 38 | { 39 | static NSMutableDictionary *groups = nil; 40 | if (groups == nil) { 41 | groups = [[NSMutableDictionary alloc] init]; 42 | } 43 | 44 | if (identifier == nil) { 45 | identifier = kINWindowButtonGroupDefault; 46 | } 47 | 48 | INWindowButtonGroup *group = groups[identifier]; 49 | if (group == nil) { 50 | group = [[[self class] alloc] initWithIdentifier:identifier]; 51 | groups[identifier] = group; 52 | } 53 | return group; 54 | } 55 | 56 | - (instancetype)initWithIdentifier:(NSString *)identifier 57 | { 58 | self = [super init]; 59 | if (self) { 60 | _identifier = [identifier copy]; 61 | } 62 | return self; 63 | } 64 | 65 | - (void)setNumberOfCaptures:(NSInteger)numberOfCaptures 66 | { 67 | if (_numberOfCaptures != numberOfCaptures && numberOfCaptures >= 0) { 68 | _numberOfCaptures = numberOfCaptures; 69 | [[NSNotificationCenter defaultCenter] postNotificationName:INWindowButtonGroupDidUpdateRolloverStateNotification 70 | object:self]; 71 | } 72 | } 73 | 74 | - (void)didCaptureMousePointer 75 | { 76 | self.numberOfCaptures++; 77 | } 78 | 79 | - (void)didReleaseMousePointer 80 | { 81 | self.numberOfCaptures--; 82 | } 83 | 84 | - (BOOL)shouldDisplayRollOver 85 | { 86 | return (self.numberOfCaptures > 0); 87 | } 88 | 89 | - (void)resetMouseCaptures 90 | { 91 | self.numberOfCaptures = 0; 92 | } 93 | 94 | @end 95 | 96 | #pragma mark - Window Button 97 | 98 | @interface INWindowButton () 99 | @property (nonatomic, copy) NSString *groupIdentifier; 100 | @property (nonatomic, strong, readonly) INWindowButtonGroup *group; 101 | @property (nonatomic, strong) NSTrackingArea *mouseTrackingArea; 102 | 103 | @end 104 | 105 | @implementation INWindowButton 106 | 107 | + (instancetype)windowButtonWithSize:(NSSize)size groupIdentifier:(NSString *)groupIdentifier 108 | { 109 | INWindowButton *button = [[self alloc] initWithSize:size groupIdentifier:groupIdentifier]; 110 | return button; 111 | } 112 | 113 | #pragma mark - Init and Dealloc 114 | 115 | - (instancetype)initWithSize:(NSSize)size groupIdentifier:(NSString *)groupIdentifier 116 | { 117 | self = [super initWithFrame:NSMakeRect(0, 0, size.width, size.height)]; 118 | if (self) { 119 | _groupIdentifier = [groupIdentifier copy]; 120 | [self setButtonType:NSMomentaryChangeButton]; 121 | [self setBordered:NO]; 122 | [self setTitle:@""]; 123 | [self.cell setHighlightsBy:NSContentsCellMask]; 124 | [self.cell setImageDimsWhenDisabled:NO]; 125 | 126 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowButtonGroupDidUpdateRolloverStateNotification:) name:INWindowButtonGroupDidUpdateRolloverStateNotification object:self.group]; 127 | } 128 | return self; 129 | } 130 | 131 | - (void)dealloc 132 | { 133 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 134 | } 135 | 136 | #pragma mark - Group 137 | 138 | - (INWindowButtonGroup *)group 139 | { 140 | return [INWindowButtonGroup groupWithIdentifier:self.groupIdentifier]; 141 | } 142 | 143 | - (void)windowButtonGroupDidUpdateRolloverStateNotification:(NSNotification *)n 144 | { 145 | [self updateRollOverImage]; 146 | } 147 | 148 | #pragma mark - Tracking Area 149 | 150 | - (void)updateTrackingAreas 151 | { 152 | [super updateTrackingAreas]; 153 | 154 | if (self.mouseTrackingArea) { 155 | [self removeTrackingArea:self.mouseTrackingArea]; 156 | } 157 | 158 | NSTrackingArea *mouseTrackingArea = [[NSTrackingArea alloc] initWithRect:NSInsetRect(self.bounds, -4, -4) 159 | options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways 160 | owner:self 161 | userInfo:nil]; 162 | 163 | [self addTrackingArea:self.mouseTrackingArea = mouseTrackingArea]; 164 | } 165 | 166 | #pragma mark - Window State Handling 167 | 168 | - (void)viewDidMoveToWindow 169 | { 170 | if (self.window) { 171 | [self updateImage]; 172 | } 173 | } 174 | 175 | - (void)viewWillMoveToWindow:(NSWindow *)newWindow 176 | { 177 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 178 | if (self.window) { 179 | [nc removeObserver:self name:NSWindowDidBecomeKeyNotification object:self.window]; 180 | [nc removeObserver:self name:NSWindowDidResignKeyNotification object:self.window]; 181 | [nc removeObserver:self name:NSWindowDidMiniaturizeNotification object:self.window]; 182 | if ([NSWindow instancesRespondToSelector:@selector(toggleFullScreen:)]) { 183 | [nc removeObserver:self name:NSWindowWillEnterFullScreenNotification object:self.window]; 184 | [nc removeObserver:self name:NSWindowWillExitFullScreenNotification object:self.window]; 185 | } 186 | } 187 | if (newWindow != nil) { 188 | [nc addObserver:self selector:@selector(windowDidChangeFocus:) name:NSWindowDidBecomeKeyNotification object:newWindow]; 189 | [nc addObserver:self selector:@selector(windowDidChangeFocus:) name:NSWindowDidResignKeyNotification object:newWindow]; 190 | [nc addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:newWindow]; 191 | if ([NSWindow instancesRespondToSelector:@selector(toggleFullScreen:)]) { 192 | [nc addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:newWindow]; 193 | [nc addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:newWindow]; 194 | } 195 | } 196 | } 197 | 198 | - (void)windowDidChangeFocus:(NSNotification *)n 199 | { 200 | [self updateImage]; 201 | } 202 | 203 | - (void)windowWillEnterFullScreen:(NSNotification *)n 204 | { 205 | [self.group resetMouseCaptures]; 206 | self.hidden = YES; 207 | } 208 | 209 | - (void)windowWillExitFullScreen:(NSNotification *)n 210 | { 211 | [self.group resetMouseCaptures]; 212 | self.hidden = NO; 213 | } 214 | 215 | - (void)windowDidMiniaturize:(NSNotification *)notification 216 | { 217 | [self.group resetMouseCaptures]; 218 | } 219 | 220 | #pragma mark - Event Handling 221 | 222 | - (void)viewDidEndLiveResize 223 | { 224 | [super viewDidEndLiveResize]; 225 | [self.group resetMouseCaptures]; 226 | } 227 | 228 | - (void)mouseEntered:(NSEvent *)theEvent 229 | { 230 | [super mouseEntered:theEvent]; 231 | [self.group didCaptureMousePointer]; 232 | [self updateRollOverImage]; 233 | } 234 | 235 | - (void)mouseExited:(NSEvent *)theEvent 236 | { 237 | [super mouseExited:theEvent]; 238 | [self.group didReleaseMousePointer]; 239 | [self updateRollOverImage]; 240 | } 241 | 242 | #pragma mark - Button Appearance 243 | 244 | - (void)setPressedImage:(NSImage *)pressedImage 245 | { 246 | self.alternateImage = pressedImage; 247 | } 248 | 249 | - (NSImage *)pressedImage 250 | { 251 | return self.alternateImage; 252 | } 253 | 254 | - (void)setEnabled:(BOOL)enabled 255 | { 256 | super.enabled = enabled; 257 | [self updateActiveImage]; 258 | } 259 | 260 | - (void)updateRollOverImage 261 | { 262 | if (self.group.shouldDisplayRollOver && self.isEnabled) { 263 | self.image = self.rolloverImage; 264 | } else { 265 | [self updateImage]; 266 | } 267 | } 268 | 269 | - (void)updateImage 270 | { 271 | if (self.window.isKeyWindow) { 272 | [self updateActiveImage]; 273 | } else { 274 | self.image = self.activeNotKeyWindowImage; 275 | } 276 | } 277 | 278 | - (void)updateActiveImage 279 | { 280 | self.image = self.isEnabled ? self.activeImage : self.inactiveImage; 281 | } 282 | 283 | @end 284 | -------------------------------------------------------------------------------- /Inbox for Mac/INAppStoreWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // INAppStoreWindow.h 3 | // 4 | // Copyright (c) 2011-2014 Indragie Karunaratne. All rights reserved. 5 | // Copyright (c) 2014 Petroules Corporation. All rights reserved. 6 | // 7 | // Licensed under the BSD 2-clause License. See LICENSE file distributed in the source 8 | // code of this project. 9 | // 10 | 11 | #import 12 | 13 | /** 14 | Height of a small bottom bar of a window. Currently, this is 22 points. 15 | */ 16 | APPKIT_EXTERN const NSInteger kINAppStoreWindowSmallBottomBarHeight; 17 | 18 | /** 19 | Height of a large bottom bar of a window. Currently, this is 32 points. 20 | */ 21 | APPKIT_EXTERN const NSInteger kINAppStoreWindowLargeBottomBarHeight; 22 | 23 | @class INWindowButton; 24 | 25 | /** 26 | * Draws default style OS X window backgrounds and separators. 27 | */ 28 | @interface INWindowBackgroundView : NSView 29 | 30 | @end 31 | 32 | /** 33 | Draws a default style OS X title bar. 34 | */ 35 | @interface INTitlebarView : INWindowBackgroundView 36 | 37 | @end 38 | 39 | /** 40 | Draws a default style OS X bottom bar. 41 | */ 42 | @interface INBottomBarView : INWindowBackgroundView 43 | 44 | @end 45 | 46 | /** 47 | Creates a window similar to the Mac App Store window, with centered traffic lights and an 48 | enlarged title bar. This does not handle creating the toolbar. 49 | */ 50 | @interface INAppStoreWindow : NSWindow 51 | 52 | /** 53 | Prototype for a block used to implement custom drawing code for a window's title bar or bottom bar. 54 | @param drawsAsMainWindow Whether the window should be drawn in main state. 55 | @param drawingRect Drawing area of the window's title bar. 56 | @param edge NSMinYEdge to draw a bottom bar, NSMaxYEdge to draw a title bar. 57 | @param clippingPath Path to clip drawing according to window's rounded corners. 58 | */ 59 | typedef void (^INAppStoreWindowBackgroundDrawingBlock)(BOOL drawsAsMainWindow, CGRect drawingRect, 60 | CGRectEdge edge, CGPathRef clippingPath); 61 | 62 | /** 63 | The height of the title bar. By default, this is set to the standard title bar height. 64 | */ 65 | @property (nonatomic) CGFloat titleBarHeight; 66 | 67 | /** 68 | Container view for custom views added to the title bar. 69 | 70 | Add subviews to this view that you want to show in the title bar (e.g. buttons, a toolbar, etc.). 71 | This view can also be set if you want to use a different style title bar from the default one 72 | (textured, etc.). 73 | */ 74 | @property (nonatomic, strong) NSView *titleBarView; 75 | 76 | /** 77 | The height of the bottom bar. By default, this is set to 0. 78 | */ 79 | @property (nonatomic) CGFloat bottomBarHeight; 80 | 81 | /** 82 | Container view for custom views added to the bottom bar. 83 | 84 | Add subviews to this view that you want to show in the bottom bar (e.g. labels, sliders, etc.). 85 | This view can also be set if you want to use a different style bottom bar from the default one 86 | (textured, etc.). 87 | */ 88 | @property (nonatomic, strong) NSView *bottomBarView; 89 | 90 | /** 91 | Whether the fullscreen button is vertically centered. 92 | */ 93 | @property (nonatomic) BOOL centerFullScreenButton; 94 | 95 | /** 96 | Whether the traffic light buttons are vertically centered. 97 | */ 98 | @property (nonatomic) BOOL centerTrafficLightButtons; 99 | 100 | /** 101 | Whether the traffic light buttons are displayed in vertical orientation. 102 | */ 103 | @property (nonatomic) BOOL verticalTrafficLightButtons; 104 | 105 | /** 106 | Whether the title is centered vertically. 107 | */ 108 | @property (nonatomic) BOOL verticallyCenterTitle; 109 | 110 | /** 111 | Whether to hide the title bar in fullscreen mode. 112 | */ 113 | @property (nonatomic) BOOL hideTitleBarInFullScreen; 114 | 115 | /** 116 | Whether to display the baseline separator between the window's title bar and content area. 117 | */ 118 | @property (nonatomic) BOOL showsBaselineSeparator; 119 | 120 | /** 121 | Whether to display the bottom separator between the window's bottom bar and content area. 122 | */ 123 | @property (nonatomic) BOOL showsBottomBarSeparator; 124 | 125 | /** 126 | Distance between the traffic light buttons and the left edge of the window. 127 | */ 128 | @property (nonatomic) CGFloat trafficLightButtonsLeftMargin; 129 | 130 | /** 131 | * Distance between the traffic light buttons and the top edge of the window. 132 | */ 133 | @property (nonatomic) CGFloat trafficLightButtonsTopMargin; 134 | 135 | /** 136 | Distance between the fullscreen button and the right edge of the window. 137 | */ 138 | @property (nonatomic) CGFloat fullScreenButtonRightMargin; 139 | 140 | /** 141 | Distance between the fullscreen button and the top edge of the window. 142 | */ 143 | @property (nonatomic) CGFloat fullScreenButtonTopMargin; 144 | 145 | /** 146 | Spacing between the traffic light buttons. 147 | */ 148 | @property (nonatomic) CGFloat trafficLightSeparation; 149 | 150 | /** 151 | Number of points in any direction above which the window will be allowed to reposition. 152 | A Higher value indicates coarser movements but much reduced CPU overhead. Defaults to 1. 153 | */ 154 | @property (nonatomic) CGFloat mouseDragDetectionThreshold; 155 | 156 | /** 157 | Whether to show the window's title text. If \c YES, the title will be shown even if 158 | \a titleBarDrawingBlock is set. To draw the title manually, set this property to \c NO 159 | and draw the title using \a titleBarDrawingBlock. 160 | */ 161 | @property (nonatomic) BOOL showsTitle; 162 | 163 | /** 164 | Whether to show the window's title text in fullscreen mode. 165 | */ 166 | @property (nonatomic) BOOL showsTitleInFullscreen; 167 | 168 | /** 169 | Whether the window displays the document proxy icon (for document-based applications). 170 | */ 171 | @property (nonatomic) BOOL showsDocumentProxyIcon; 172 | 173 | /** 174 | The button to use as the window's close button. 175 | If this property is nil, the default button will be used. 176 | */ 177 | @property (nonatomic, strong) INWindowButton *closeButton; 178 | 179 | /** 180 | The button to use as the window's minimize button. 181 | If this property is nil, the default button will be used. 182 | */ 183 | @property (nonatomic, strong) INWindowButton *minimizeButton; 184 | 185 | /** 186 | The button to use as the window's zoom button. 187 | If this property is nil, the default button will be used. 188 | */ 189 | @property (nonatomic, strong) INWindowButton *zoomButton; 190 | 191 | /** 192 | The button to use as the window's fullscreen button. 193 | If this property is nil, the default button will be used. 194 | */ 195 | @property (nonatomic, strong) INWindowButton *fullScreenButton; 196 | 197 | /** 198 | The divider line between the window title and document versions button. 199 | */ 200 | @property (nonatomic, readonly) NSTextField *titleDivider; 201 | 202 | /** 203 | The font used to draw the window's title text. 204 | */ 205 | @property (nonatomic, strong) NSFont *titleFont; 206 | 207 | /** 208 | Gradient used to draw the window's title bar, when the window is main. 209 | 210 | If this property is \c nil, the system gradient will be used. 211 | */ 212 | @property (nonatomic, strong) NSGradient *titleBarGradient; 213 | 214 | /** 215 | Gradient used to draw the window's bottom bar, when the window is main. 216 | 217 | If this property is \c nil, the system gradient will be used. 218 | */ 219 | @property (nonatomic, strong) NSGradient *bottomBarGradient; 220 | 221 | /** 222 | Color of the separator line between a window's title bar and content area, 223 | when the window is main. 224 | 225 | If this property is \c nil, the default color will be used. 226 | */ 227 | @property (nonatomic, strong) NSColor *baselineSeparatorColor; 228 | 229 | /** 230 | Color of the window's title text, when the window is main. 231 | 232 | If this property is \c nil, the default color will be used. 233 | */ 234 | @property (nonatomic, strong) NSColor *titleTextColor; 235 | 236 | /** 237 | Drop shadow under the window's title text, when the window is main. 238 | 239 | If this property is \c nil, the default shadow will be used. 240 | */ 241 | @property (nonatomic, strong) NSShadow *titleTextShadow; 242 | 243 | /** 244 | Gradient used to draw the window's title bar, when the window is not main. 245 | 246 | If this property is \c nil, the system gradient will be used. 247 | */ 248 | @property (nonatomic, strong) NSGradient *inactiveTitleBarGradient; 249 | 250 | /** 251 | Gradient used to draw the window's bottom bar, when the window is not main. 252 | 253 | If this property is \c nil, the system gradient will be used. 254 | */ 255 | @property (nonatomic, strong) NSGradient *inactiveBottomBarGradient; 256 | 257 | /** 258 | Color of the separator line between a window's title bar and content area, 259 | when the window is not main. 260 | 261 | If this property is \c nil, the default color will be used. 262 | */ 263 | @property (nonatomic, strong) NSColor *inactiveBaselineSeparatorColor; 264 | 265 | /** 266 | Color of the window's title text, when the window is not main. 267 | 268 | If this property is \c nil, the default color will be used. 269 | */ 270 | @property (nonatomic, strong) NSColor *inactiveTitleTextColor; 271 | 272 | /** 273 | Drop shadow under the window's title text, when the window is not main. 274 | 275 | If this property is \c nil, the default shadow will be used. 276 | */ 277 | @property (nonatomic, strong) NSShadow *inactiveTitleTextShadow; 278 | 279 | /** 280 | Block to override the drawing of the window title bar with a custom implementation. 281 | */ 282 | @property (nonatomic, copy) INAppStoreWindowBackgroundDrawingBlock titleBarDrawingBlock; 283 | 284 | /** 285 | Block to override the drawing of the window bottom bar with a custom implementation. 286 | */ 287 | @property (nonatomic, copy) INAppStoreWindowBackgroundDrawingBlock bottomBarDrawingBlock; 288 | 289 | /** 290 | Whether to draw a noise pattern overlay on the title bar on OS X 10.7-10.9. This 291 | property has no effect when running on OS X 10.10 or higher. 292 | */ 293 | @property (nonatomic) BOOL drawsTitlePatternOverlay; 294 | 295 | /*! 296 | Default system gradient used to draw a window's title bar. 297 | @param drawsAsMainWindow \c YES to return the gradient used when the window is drawn in its main 298 | state, \c NO to return the color used when the window is inactive. 299 | 300 | @note This gradient is identical to the one used by AppKit in OS X versions 10.7 through 10.9. 301 | For OS X 10.6 it is currently an approximation. 302 | */ 303 | + (NSGradient *)defaultTitleBarGradient:(BOOL)drawsAsMainWindow; 304 | 305 | /*! 306 | Default system gradient used to draw a window's bottom bar. 307 | @param drawsAsMainWindow \c YES to return the gradient used when the window is drawn in its main 308 | state, \c NO to return the color used when the window is inactive. 309 | */ 310 | + (NSGradient *)defaultBottomBarGradient:(BOOL)drawsAsMainWindow; 311 | 312 | /*! 313 | Default system color of the separator line between a window's title bar and content area. 314 | @param drawsAsMainWindow \c YES to return the color used when the window is drawn in its main 315 | state, \c NO to return the color used when the window is inactive. 316 | 317 | @note This color may be an approximation and is subject to change at any time. 318 | */ 319 | + (NSColor *)defaultBaselineSeparatorColor:(BOOL)drawsAsMainWindow; 320 | 321 | /*! 322 | Default system color of a window's title text. 323 | @param drawsAsMainWindow \c YES to return the color used when the window is drawn in its main 324 | state, \c NO to return the color used when the window is inactive. 325 | 326 | @note This color may be an approximation and is subject to change at any time. 327 | */ 328 | + (NSColor *)defaultTitleTextColor:(BOOL)drawsAsMainWindow; 329 | 330 | /** 331 | Sets the height of the title bar. By default, this is set to the standard title bar height. 332 | 333 | @param adjustWindowFrame Whether to adjust the window frame in response to the change in 334 | the title bar height. By default, the window frame is adjusted when the title bar height 335 | is changed. 336 | */ 337 | - (void)setTitleBarHeight:(CGFloat)titleBarHeight adjustWindowFrame:(BOOL)adjustWindowFrame; 338 | 339 | /** 340 | Returns the height of the window's NSToolbar. If the window has no NSToolbar, or if it's not visible, returns 0. 341 | */ 342 | - (CGFloat)toolbarHeight; 343 | 344 | @end 345 | -------------------------------------------------------------------------------- /Inbox for Mac/WAYAppStoreWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // WAYAppStoreWindow.h 3 | // WAYAppStoreWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 Raffael Hannemann. All rights reserved. 7 | // Visit weAreYeah.com or follow @weareYeah for updates. 8 | // 9 | // Licensed under the BSD License 10 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 11 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 12 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 13 | // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 14 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 15 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 16 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 17 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 18 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | // 20 | 21 | // Please note: lots of the following code is copied from INAppStoreWindow by Indragie Karunaratne, et al. 22 | 23 | #import 24 | 25 | @class INWindowButton; 26 | 27 | /** This NSWindow subclass allows you to use create NSWindow that provide INAppStoreWindow like capabilities. The class switches between either WAYWindow or INAppStoreWindow at runtime based on the OS version. The way it is done is kind of experimental and currently only basic functionality of the original INAppStoreWindow is supported. Lots of INAppStoreWindow's properties probably do not work. Basically, only the functions that WAYWindow is implementing, are currently supported. 28 | */ 29 | @interface WAYAppStoreWindow : NSWindow 30 | 31 | /** Note: The following properties are shamelessly copied from INAppStoreWindow. All credits to the author. We need to copy these properties here in order to get the same ivar layout in the class façade class. Please note that not all of the listed properties have an effect on OS X Yosemite, where WAYWindow will be used internally. */ 32 | 33 | /** 34 | Prototype for a block used to implement custom drawing code for a window's title bar or bottom bar. 35 | @param drawsAsMainWindow Whether the window should be drawn in main state. 36 | @param drawingRect Drawing area of the window's title bar. 37 | @param edge NSMinYEdge to draw a bottom bar, NSMaxYEdge to draw a title bar. 38 | @param clippingPath Path to clip drawing according to window's rounded corners. 39 | */ 40 | typedef void (^INAppStoreWindowBackgroundDrawingBlock)(BOOL drawsAsMainWindow, CGRect drawingRect, 41 | CGRectEdge edge, CGPathRef clippingPath); 42 | 43 | /** 44 | The height of the title bar. By default, this is set to the standard title bar height. 45 | */ 46 | @property (nonatomic) CGFloat titleBarHeight; 47 | 48 | /** 49 | Container view for custom views added to the title bar. 50 | 51 | Add subviews to this view that you want to show in the title bar (e.g. buttons, a toolbar, etc.). 52 | This view can also be set if you want to use a different style title bar from the default one 53 | (textured, etc.). 54 | */ 55 | @property (nonatomic, strong) NSView *titleBarView; 56 | 57 | /** 58 | The height of the bottom bar. By default, this is set to 0. 59 | */ 60 | @property (nonatomic) CGFloat bottomBarHeight; 61 | 62 | /** 63 | Container view for custom views added to the bottom bar. 64 | 65 | Add subviews to this view that you want to show in the bottom bar (e.g. labels, sliders, etc.). 66 | This view can also be set if you want to use a different style bottom bar from the default one 67 | (textured, etc.). 68 | */ 69 | @property (nonatomic, strong) NSView *bottomBarView; 70 | 71 | /** 72 | Whether the fullscreen button is vertically centered. 73 | */ 74 | @property (nonatomic) BOOL centerFullScreenButton; 75 | 76 | /** 77 | Whether the traffic light buttons are vertically centered. 78 | */ 79 | @property (nonatomic) BOOL centerTrafficLightButtons; 80 | 81 | /** 82 | Whether the traffic light buttons are displayed in vertical orientation. 83 | */ 84 | @property (nonatomic) BOOL verticalTrafficLightButtons; 85 | 86 | /** 87 | Whether the title is centered vertically. 88 | */ 89 | @property (nonatomic) BOOL verticallyCenterTitle; 90 | 91 | /** 92 | Whether to hide the title bar in fullscreen mode. 93 | */ 94 | @property (nonatomic) BOOL hideTitleBarInFullScreen; 95 | 96 | /** 97 | Whether to display the baseline separator between the window's title bar and content area. 98 | */ 99 | @property (nonatomic) BOOL showsBaselineSeparator; 100 | 101 | /** 102 | Whether to display the bottom separator between the window's bottom bar and content area. 103 | */ 104 | @property (nonatomic) BOOL showsBottomBarSeparator; 105 | 106 | /** 107 | Distance between the traffic light buttons and the left edge of the window. 108 | */ 109 | @property (nonatomic) CGFloat trafficLightButtonsLeftMargin; 110 | 111 | /** 112 | * Distance between the traffic light buttons and the top edge of the window. 113 | */ 114 | @property (nonatomic) CGFloat trafficLightButtonsTopMargin; 115 | 116 | /** 117 | Distance between the fullscreen button and the right edge of the window. 118 | */ 119 | @property (nonatomic) CGFloat fullScreenButtonRightMargin; 120 | 121 | /** 122 | Distance between the fullscreen button and the top edge of the window. 123 | */ 124 | @property (nonatomic) CGFloat fullScreenButtonTopMargin; 125 | 126 | /** 127 | Spacing between the traffic light buttons. 128 | */ 129 | @property (nonatomic) CGFloat trafficLightSeparation; 130 | 131 | /** 132 | Number of points in any direction above which the window will be allowed to reposition. 133 | A Higher value indicates coarser movements but much reduced CPU overhead. Defaults to 1. 134 | */ 135 | @property (nonatomic) CGFloat mouseDragDetectionThreshold; 136 | 137 | /** 138 | Whether to show the window's title text. If \c YES, the title will be shown even if 139 | \a titleBarDrawingBlock is set. To draw the title manually, set this property to \c NO 140 | and draw the title using \a titleBarDrawingBlock. 141 | */ 142 | @property (nonatomic) BOOL showsTitle; 143 | 144 | /** 145 | Whether to show the window's title text in fullscreen mode. 146 | */ 147 | @property (nonatomic) BOOL showsTitleInFullscreen; 148 | 149 | /** 150 | Whether the window displays the document proxy icon (for document-based applications). 151 | */ 152 | @property (nonatomic) BOOL showsDocumentProxyIcon; 153 | 154 | /** 155 | The button to use as the window's close button. 156 | If this property is nil, the default button will be used. 157 | */ 158 | @property (nonatomic, strong) INWindowButton *closeButton; 159 | 160 | /** 161 | The button to use as the window's minimize button. 162 | If this property is nil, the default button will be used. 163 | */ 164 | @property (nonatomic, strong) INWindowButton *minimizeButton; 165 | 166 | /** 167 | The button to use as the window's zoom button. 168 | If this property is nil, the default button will be used. 169 | */ 170 | @property (nonatomic, strong) INWindowButton *zoomButton; 171 | 172 | /** 173 | The button to use as the window's fullscreen button. 174 | If this property is nil, the default button will be used. 175 | */ 176 | @property (nonatomic, strong) INWindowButton *fullScreenButton; 177 | 178 | /** 179 | The divider line between the window title and document versions button. 180 | */ 181 | @property (nonatomic, readonly) NSTextField *titleDivider; 182 | 183 | /** 184 | The font used to draw the window's title text. 185 | */ 186 | @property (nonatomic, strong) NSFont *titleFont; 187 | 188 | /** 189 | Gradient used to draw the window's title bar, when the window is main. 190 | 191 | If this property is \c nil, the system gradient will be used. 192 | */ 193 | @property (nonatomic, strong) NSGradient *titleBarGradient; 194 | 195 | /** 196 | Gradient used to draw the window's bottom bar, when the window is main. 197 | 198 | If this property is \c nil, the system gradient will be used. 199 | */ 200 | @property (nonatomic, strong) NSGradient *bottomBarGradient; 201 | 202 | /** 203 | Color of the separator line between a window's title bar and content area, 204 | when the window is main. 205 | 206 | If this property is \c nil, the default color will be used. 207 | */ 208 | @property (nonatomic, strong) NSColor *baselineSeparatorColor; 209 | 210 | /** 211 | Color of the window's title text, when the window is main. 212 | 213 | If this property is \c nil, the default color will be used. 214 | */ 215 | @property (nonatomic, strong) NSColor *titleTextColor; 216 | 217 | /** 218 | Drop shadow under the window's title text, when the window is main. 219 | 220 | If this property is \c nil, the default shadow will be used. 221 | */ 222 | @property (nonatomic, strong) NSShadow *titleTextShadow; 223 | 224 | /** 225 | Gradient used to draw the window's title bar, when the window is not main. 226 | 227 | If this property is \c nil, the system gradient will be used. 228 | */ 229 | @property (nonatomic, strong) NSGradient *inactiveTitleBarGradient; 230 | 231 | /** 232 | Gradient used to draw the window's bottom bar, when the window is not main. 233 | 234 | If this property is \c nil, the system gradient will be used. 235 | */ 236 | @property (nonatomic, strong) NSGradient *inactiveBottomBarGradient; 237 | 238 | /** 239 | Color of the separator line between a window's title bar and content area, 240 | when the window is not main. 241 | 242 | If this property is \c nil, the default color will be used. 243 | */ 244 | @property (nonatomic, strong) NSColor *inactiveBaselineSeparatorColor; 245 | 246 | /** 247 | Color of the window's title text, when the window is not main. 248 | 249 | If this property is \c nil, the default color will be used. 250 | */ 251 | @property (nonatomic, strong) NSColor *inactiveTitleTextColor; 252 | 253 | /** 254 | Drop shadow under the window's title text, when the window is not main. 255 | 256 | If this property is \c nil, the default shadow will be used. 257 | */ 258 | @property (nonatomic, strong) NSShadow *inactiveTitleTextShadow; 259 | 260 | /** 261 | Block to override the drawing of the window title bar with a custom implementation. 262 | */ 263 | @property (nonatomic, copy) INAppStoreWindowBackgroundDrawingBlock titleBarDrawingBlock; 264 | 265 | /** 266 | Block to override the drawing of the window bottom bar with a custom implementation. 267 | */ 268 | @property (nonatomic, copy) INAppStoreWindowBackgroundDrawingBlock bottomBarDrawingBlock; 269 | 270 | /** 271 | Whether to draw a noise pattern overlay on the title bar on OS X 10.7-10.9. This 272 | property has no effect when running on OS X 10.10 or higher. 273 | */ 274 | @property (nonatomic) BOOL drawsTitlePatternOverlay; 275 | 276 | @end 277 | 278 | 279 | @interface WAYAppStoreWindow (WAYWindowAdditionalInterfaces) 280 | 281 | /// Returns YES, if the class supports vibrant appearances. Can be used to determine if running on OS X 10.10+ 282 | + (BOOL) supportsVibrantAppearances; 283 | /// If set to YES, the title of the window will be hidden. 284 | @property (nonatomic) IBInspectable BOOL hidesTitle; 285 | 286 | /// Replaces the window's content view with an instance of NSVisualEffectView and applies the Vibrant Dark look. Transfers all subviews to the new content view. 287 | - (void) setContentViewAppearanceVibrantDark; 288 | 289 | /// Replaces the window's content view with an instance of NSVisualEffectView and applies the Vibrant Light look. Transfers all subviews to the new content view. 290 | - (void) setContentViewAppearanceVibrantLight; 291 | 292 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantDark 293 | - (void) setVibrantDarkAppearance; 294 | 295 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantLight 296 | - (void) setVibrantLightAppearance; 297 | 298 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantAqua 299 | - (void) setAquaAppearance; 300 | 301 | /// Replaces a view of the window subview hierarchy with the specified view, and transfers all current subviews to the new one. The frame of the new view will be set to the frame of the old view, if flag is YES. 302 | - (void) replaceSubview: (NSView *) aView withView: (NSView *) newView resizing: (BOOL) flag; 303 | 304 | /// Replaces a view of the window subview hierarchy with a new view of the specified NSView class, and transfers all current subviews to the new one. 305 | - (NSView *) replaceSubview: (NSView *) aView withViewOfClass: (Class) newViewClass; 306 | 307 | /// Returns YES if the window is currently in full-screen. 308 | - (BOOL) isFullScreen; 309 | 310 | @end -------------------------------------------------------------------------------- /Inbox for Mac/WAYWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // WAYWindow.m 3 | // WAYWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 Raffael Hannemann. All rights reserved. 7 | // Visit weAreYeah.com or follow @weareYeah for updates. 8 | // 9 | // Licensed under the BSD License 10 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 11 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 12 | // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 13 | // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 14 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 15 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 16 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 17 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 18 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | // 20 | 21 | #import "WAYWindow.h" 22 | 23 | /** 24 | Convenience methods to make NSPointerArray act like a stack of selectors. It would be a subclass, but NSPointerArray 25 | is a class cluster and doesn't really like being subclassed. 26 | */ 27 | #pragma mark - WAY_SelectorStack 28 | @interface NSPointerArray (WAY_SelectorStack) 29 | - (instancetype)initWAYSelectorStack; 30 | - (BOOL)way_containsSelector:(SEL)aSelector; 31 | - (void)way_pushSelector:(SEL)aSelector; 32 | - (SEL)way_pop; 33 | @end 34 | 35 | @implementation NSPointerArray (WAY_SelectorStack) 36 | - (instancetype)initWAYSelectorStack { 37 | NSPointerFunctions *pointerFunctions = [NSPointerFunctions pointerFunctionsWithOptions:(NSPointerFunctionsOpaqueMemory | 38 | NSPointerFunctionsOpaquePersonality)]; 39 | self = [self initWithPointerFunctions:pointerFunctions]; 40 | return self; 41 | } 42 | 43 | - (BOOL)way_containsSelector:(SEL)aSelector { 44 | NSInteger count = self.count; 45 | for (NSInteger i=0; i 71 | @property (nonatomic, weak) id secondaryDelegate; 72 | @property (nonatomic, weak) id firstDelegate; 73 | @end 74 | 75 | /** Since the window needs to update itself at specific events, e.g., windowDidResize:;, we need to set the window as its own delegate. To allow proper window delegates as usual, we need to make use of a proxy object, which forwards all method invovations first to the WAYWindow instance, and then to the real delegate. */ 76 | #pragma mark - WAYWindowDelegateProxy 77 | @implementation WAYWindowDelegateProxy { 78 | NSPointerArray *_selectorStack; 79 | } 80 | 81 | - (instancetype)init { 82 | _selectorStack = [[NSPointerArray alloc] initWAYSelectorStack]; 83 | return self; 84 | } 85 | 86 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 87 | NSMethodSignature *signature = [[self.firstDelegate class] instanceMethodSignatureForSelector:selector]; 88 | if (!signature) { 89 | signature = [[self.secondaryDelegate class] instanceMethodSignatureForSelector:selector]; 90 | if (!signature) { 91 | signature = [super methodSignatureForSelector:selector]; 92 | } 93 | } 94 | return signature; 95 | } 96 | 97 | - (BOOL)respondsToSelector:(SEL)aSelector { 98 | if (aSelector==@selector(windowDidResize:)) { 99 | return YES; 100 | } else if ([self.secondaryDelegate respondsToSelector:aSelector]) { 101 | return YES; 102 | } else { 103 | return NO; 104 | } 105 | } 106 | 107 | - (void)forwardInvocation:(NSInvocation *)anInvocation { 108 | SEL selector = anInvocation.selector; 109 | if ([_selectorStack way_containsSelector:selector]) { 110 | // We're already in the middle of forwarding this selector; stop the infinite recursion right here. 111 | return; 112 | } 113 | 114 | [_selectorStack way_pushSelector:selector]; 115 | { 116 | if ([self.firstDelegate respondsToSelector:selector]) { 117 | [anInvocation invokeWithTarget:self.firstDelegate]; 118 | } 119 | if ([self.secondaryDelegate respondsToSelector:selector]) { 120 | [anInvocation invokeWithTarget:self.secondaryDelegate]; 121 | } 122 | } 123 | [_selectorStack way_pop]; 124 | } 125 | 126 | - (BOOL)isKindOfClass:(Class)aClass { 127 | if (self.secondaryDelegate) { 128 | return [self.secondaryDelegate isKindOfClass:aClass]; 129 | } 130 | return NO; 131 | } 132 | @end 133 | 134 | 135 | #pragma mark - WAYWindow 136 | @interface WAYWindow () 137 | @property (strong) WAYWindowDelegateProxy* delegateProxy; 138 | @property (strong) NSArray* standardButtons; 139 | @property (strong) NSTitlebarAccessoryViewController *dummyTitlebarAccessoryViewController; 140 | 141 | @end 142 | 143 | static float kWAYWindowDefaultTrafficLightButtonsLeftMargin = 0; 144 | static float kWAYWindowDefaultTrafficLightButtonsTopMargin = 0; 145 | 146 | @implementation WAYWindow 147 | 148 | + (BOOL) supportsVibrantAppearances { 149 | return (NSClassFromString(@"NSVisualEffectView")!=nil); 150 | } 151 | 152 | + (float) defaultTitleBarHeight { 153 | NSRect frame = NSMakeRect(0, 0, 800, 600); 154 | NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask: NSTitledWindowMask]; 155 | return NSHeight(frame) - NSHeight(contentRect); 156 | } 157 | 158 | #pragma mark - NSWindow Overwritings 159 | 160 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { 161 | if ((self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag])) { 162 | [self _setUp]; 163 | } 164 | return self; 165 | } 166 | 167 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)screen { 168 | if ((self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag screen:screen])) { 169 | [self _setUp]; 170 | } 171 | return self; 172 | } 173 | 174 | - (void) setDelegate:(id)delegate { 175 | [_delegateProxy setSecondaryDelegate:delegate]; 176 | [super setDelegate:nil]; 177 | [super setDelegate:_delegateProxy]; 178 | } 179 | 180 | - (id) delegate { 181 | return [_delegateProxy secondaryDelegate]; 182 | } 183 | 184 | - (void) setFrame:(NSRect)frameRect display:(BOOL)flag { 185 | [super setFrame:frameRect display:flag]; 186 | [self _setNeedsLayout]; 187 | } 188 | 189 | - (void) restoreStateWithCoder:(NSCoder *)coder { 190 | [super restoreStateWithCoder:coder]; 191 | [self _setNeedsLayout]; 192 | } 193 | 194 | - (void) orderFront:(id)sender { 195 | [super orderFront:sender]; 196 | [self _setNeedsLayout]; 197 | } 198 | 199 | #pragma mark - Public 200 | 201 | - (NSView *) titleBarView { 202 | return [_standardButtons[0] superview]; 203 | } 204 | 205 | - (void) setCenterTrafficLightButtons:(BOOL)centerTrafficLightButtons { 206 | _centerTrafficLightButtons = centerTrafficLightButtons; 207 | [self _setNeedsLayout]; 208 | } 209 | 210 | - (void) setTitleBarHeight:(CGFloat)titleBarHeight { 211 | 212 | titleBarHeight = MAX(titleBarHeight,[[self class] defaultTitleBarHeight]); 213 | CGFloat delta = titleBarHeight - _titleBarHeight; 214 | _titleBarHeight = titleBarHeight; 215 | 216 | if (_dummyTitlebarAccessoryViewController) { 217 | [self removeTitlebarAccessoryViewControllerAtIndex:0]; 218 | } 219 | 220 | NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, titleBarHeight-[WAYWindow defaultTitleBarHeight])]; 221 | _dummyTitlebarAccessoryViewController = [NSTitlebarAccessoryViewController new]; 222 | _dummyTitlebarAccessoryViewController.view = view; 223 | _dummyTitlebarAccessoryViewController.fullScreenMinHeight = titleBarHeight; 224 | [self addTitlebarAccessoryViewController:_dummyTitlebarAccessoryViewController]; 225 | 226 | NSRect frame = self.frame; 227 | frame.size.height += delta; 228 | frame.origin.y -= delta; 229 | 230 | [self _setNeedsLayout]; 231 | [self setFrame:frame display:NO]; // NO is important. 232 | } 233 | 234 | - (void) setHidesTitle:(BOOL)hidesTitle { 235 | _hidesTitle = hidesTitle; 236 | [self setTitleVisibility:hidesTitle ? NSWindowTitleHidden : NSWindowTitleVisible]; 237 | } 238 | 239 | - (void) setContentViewAppearanceVibrantDark { 240 | [self setContentViewAppearance:NSVisualEffectMaterialDark]; 241 | } 242 | 243 | - (void) setContentViewAppearanceVibrantLight { 244 | [self setContentViewAppearance:NSVisualEffectMaterialLight]; 245 | } 246 | 247 | - (void) setContentViewAppearance: (int) material { 248 | if (![WAYWindow supportsVibrantAppearances]) 249 | return; 250 | 251 | NSVisualEffectView *newContentView = (NSVisualEffectView *)[self replaceSubview:self.contentView withViewOfClass:[NSVisualEffectView class]]; 252 | [newContentView setMaterial:material]; 253 | [self setContentView:newContentView]; 254 | } 255 | 256 | - (void) setVibrantDarkAppearance { 257 | [self setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]]; 258 | } 259 | 260 | - (void) setVibrantLightAppearance { 261 | [self setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]]; 262 | } 263 | 264 | - (void) setAquaAppearance { 265 | [self setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]]; 266 | } 267 | 268 | - (BOOL) isFullScreen { 269 | return (([self styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask); 270 | } 271 | 272 | - (void) replaceSubview: (NSView *) aView withView: (NSView *) newView resizing:(BOOL)flag { 273 | if (flag) { 274 | [newView setFrame:aView.frame]; 275 | } 276 | 277 | [newView setAutoresizesSubviews:aView.autoresizesSubviews]; 278 | [aView.subviews.copy enumerateObjectsUsingBlock:^(NSView *subview, NSUInteger idx, BOOL *stop) { 279 | NSRect frame = subview.frame; 280 | if (subview.constraints.count>0) { 281 | // Note: so far, constraint based contentView subviews are not supported yet 282 | NSLog(@"WARNING: [%@ %@] does not work yet with NSView instances, that use auto-layout.", 283 | NSStringFromClass([self class]), 284 | NSStringFromSelector(_cmd)); 285 | } 286 | [subview removeFromSuperview]; 287 | [newView addSubview:subview]; 288 | [subview setFrame:frame]; 289 | }]; 290 | 291 | if (aView==self.contentView) { 292 | [self setContentView: newView]; 293 | } else { 294 | [aView.superview replaceSubview:aView with:newView]; 295 | } 296 | [self _setNeedsLayout]; 297 | } 298 | 299 | - (NSView *) replaceSubview:(NSView *)aView withViewOfClass:(Class)newViewClass { 300 | NSView *view = [[newViewClass alloc] initWithFrame:aView.frame]; 301 | [self replaceSubview:aView withView:view resizing:YES]; 302 | return view; 303 | } 304 | 305 | #pragma mark - Private 306 | 307 | - (void) _setUp { 308 | _delegateProxy = [[WAYWindowDelegateProxy alloc] init]; 309 | _delegateProxy.firstDelegate = self; 310 | super.delegate = _delegateProxy; 311 | 312 | _standardButtons = @[[self standardWindowButton:NSWindowCloseButton], 313 | [self standardWindowButton:NSWindowMiniaturizeButton], 314 | [self standardWindowButton:NSWindowZoomButton]]; 315 | _centerTrafficLightButtons = YES; 316 | 317 | NSButton *closeButton = [self standardWindowButton:NSWindowCloseButton]; 318 | kWAYWindowDefaultTrafficLightButtonsLeftMargin = NSMinX(closeButton.frame); 319 | kWAYWindowDefaultTrafficLightButtonsTopMargin = NSHeight(closeButton.superview.frame)-NSMaxY(closeButton.frame); 320 | 321 | self.styleMask |= NSFullSizeContentViewWindowMask; 322 | _trafficLightButtonsLeftMargin = kWAYWindowDefaultTrafficLightButtonsLeftMargin; 323 | _trafficLightButtonsTopMargin = kWAYWindowDefaultTrafficLightButtonsTopMargin; 324 | 325 | self.hidesTitle = YES; 326 | 327 | [super setDelegate:self]; 328 | [self _setNeedsLayout]; 329 | } 330 | 331 | - (void) _setNeedsLayout { 332 | [_standardButtons enumerateObjectsUsingBlock:^(NSButton *standardButton, NSUInteger idx, BOOL *stop) { 333 | NSRect frame = standardButton.frame; 334 | if (_centerTrafficLightButtons) 335 | frame.origin.y = NSHeight(standardButton.superview.frame)/2-NSHeight(standardButton.frame)/2; 336 | else 337 | frame.origin.y = NSHeight(standardButton.superview.frame)-NSHeight(standardButton.frame)-_trafficLightButtonsTopMargin; 338 | 339 | frame.origin.x = _trafficLightButtonsLeftMargin +idx*(NSWidth(frame) + 6); 340 | [standardButton setFrame:frame]; 341 | }]; 342 | } 343 | 344 | #pragma mark - NSWindow Delegate 345 | 346 | - (void) windowDidResize:(NSNotification *)notification { 347 | [self _setNeedsLayout]; 348 | } 349 | 350 | @end 351 | -------------------------------------------------------------------------------- /Inbox for Mac.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9F836A311BA9C09B00DE4D39 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A301BA9C09B00DE4D39 /* AppDelegate.m */; }; 11 | 9F836A331BA9C09C00DE4D39 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A321BA9C09C00DE4D39 /* main.m */; }; 12 | 9F836A361BA9C09C00DE4D39 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A351BA9C09C00DE4D39 /* ViewController.m */; }; 13 | 9F836A381BA9C09C00DE4D39 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F836A371BA9C09C00DE4D39 /* Images.xcassets */; }; 14 | 9F836A3B1BA9C09C00DE4D39 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9F836A391BA9C09C00DE4D39 /* Main.storyboard */; }; 15 | 9F836A471BA9C09C00DE4D39 /* Inbox_for_MacTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A461BA9C09C00DE4D39 /* Inbox_for_MacTests.m */; }; 16 | 9F836A511BA9C0ED00DE4D39 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F836A501BA9C0ED00DE4D39 /* WebKit.framework */; }; 17 | 9F836A541BA9CA5500DE4D39 /* WAYAppStoreWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A531BA9CA5500DE4D39 /* WAYAppStoreWindow.m */; }; 18 | 9F836A571BA9CB1200DE4D39 /* WAYWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A561BA9CB1200DE4D39 /* WAYWindow.m */; }; 19 | 9F836A5E1BA9CB2D00DE4D39 /* Extensions in Resources */ = {isa = PBXBuildFile; fileRef = 9F836A581BA9CB2D00DE4D39 /* Extensions */; }; 20 | 9F836A5F1BA9CB2D00DE4D39 /* INAppStoreWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A5A1BA9CB2D00DE4D39 /* INAppStoreWindow.m */; }; 21 | 9F836A601BA9CB2D00DE4D39 /* INWindowButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F836A5D1BA9CB2D00DE4D39 /* INWindowButton.m */; }; 22 | 9FA5291C1BAA1EFE003BB8CF /* appicon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 9FA5291B1BAA1EFE003BB8CF /* appicon.icns */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 9F836A411BA9C09C00DE4D39 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 9F836A221BA9C09B00DE4D39 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 9F836A291BA9C09B00DE4D39; 31 | remoteInfo = "Inbox for Mac"; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 9F836A2A1BA9C09B00DE4D39 /* Inbox for Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Inbox for Mac.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 9F836A2E1BA9C09B00DE4D39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 9F836A2F1BA9C09B00DE4D39 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | 9F836A301BA9C09B00DE4D39 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | 9F836A321BA9C09C00DE4D39 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | 9F836A341BA9C09C00DE4D39 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 42 | 9F836A351BA9C09C00DE4D39 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 43 | 9F836A371BA9C09C00DE4D39 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 44 | 9F836A3A1BA9C09C00DE4D39 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 9F836A401BA9C09C00DE4D39 /* Inbox for MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Inbox for MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 9F836A451BA9C09C00DE4D39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | 9F836A461BA9C09C00DE4D39 /* Inbox_for_MacTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Inbox_for_MacTests.m; sourceTree = ""; }; 48 | 9F836A501BA9C0ED00DE4D39 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 49 | 9F836A521BA9CA5500DE4D39 /* WAYAppStoreWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAYAppStoreWindow.h; sourceTree = ""; }; 50 | 9F836A531BA9CA5500DE4D39 /* WAYAppStoreWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WAYAppStoreWindow.m; sourceTree = ""; }; 51 | 9F836A551BA9CB1200DE4D39 /* WAYWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAYWindow.h; sourceTree = ""; }; 52 | 9F836A561BA9CB1200DE4D39 /* WAYWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WAYWindow.m; sourceTree = ""; }; 53 | 9F836A581BA9CB2D00DE4D39 /* Extensions */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Extensions; sourceTree = ""; }; 54 | 9F836A591BA9CB2D00DE4D39 /* INAppStoreWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = INAppStoreWindow.h; sourceTree = ""; }; 55 | 9F836A5A1BA9CB2D00DE4D39 /* INAppStoreWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = INAppStoreWindow.m; sourceTree = ""; }; 56 | 9F836A5B1BA9CB2D00DE4D39 /* INAppStoreWindowCompatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = INAppStoreWindowCompatibility.h; sourceTree = ""; }; 57 | 9F836A5C1BA9CB2D00DE4D39 /* INWindowButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = INWindowButton.h; sourceTree = ""; }; 58 | 9F836A5D1BA9CB2D00DE4D39 /* INWindowButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = INWindowButton.m; sourceTree = ""; }; 59 | 9FA5291B1BAA1EFE003BB8CF /* appicon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = appicon.icns; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 9F836A271BA9C09B00DE4D39 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | 9F836A511BA9C0ED00DE4D39 /* WebKit.framework in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | 9F836A3D1BA9C09C00DE4D39 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | 9F836A211BA9C09B00DE4D39 = { 82 | isa = PBXGroup; 83 | children = ( 84 | 9F836A501BA9C0ED00DE4D39 /* WebKit.framework */, 85 | 9F836A2C1BA9C09B00DE4D39 /* Inbox for Mac */, 86 | 9F836A431BA9C09C00DE4D39 /* Inbox for MacTests */, 87 | 9F836A2B1BA9C09B00DE4D39 /* Products */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | 9F836A2B1BA9C09B00DE4D39 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 9F836A2A1BA9C09B00DE4D39 /* Inbox for Mac.app */, 95 | 9F836A401BA9C09C00DE4D39 /* Inbox for MacTests.xctest */, 96 | ); 97 | name = Products; 98 | sourceTree = ""; 99 | }; 100 | 9F836A2C1BA9C09B00DE4D39 /* Inbox for Mac */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 9FA5291B1BAA1EFE003BB8CF /* appicon.icns */, 104 | 9F836A2F1BA9C09B00DE4D39 /* AppDelegate.h */, 105 | 9F836A301BA9C09B00DE4D39 /* AppDelegate.m */, 106 | 9F836A341BA9C09C00DE4D39 /* ViewController.h */, 107 | 9F836A351BA9C09C00DE4D39 /* ViewController.m */, 108 | 9F836A521BA9CA5500DE4D39 /* WAYAppStoreWindow.h */, 109 | 9F836A551BA9CB1200DE4D39 /* WAYWindow.h */, 110 | 9F836A561BA9CB1200DE4D39 /* WAYWindow.m */, 111 | 9F836A531BA9CA5500DE4D39 /* WAYAppStoreWindow.m */, 112 | 9F836A581BA9CB2D00DE4D39 /* Extensions */, 113 | 9F836A591BA9CB2D00DE4D39 /* INAppStoreWindow.h */, 114 | 9F836A5A1BA9CB2D00DE4D39 /* INAppStoreWindow.m */, 115 | 9F836A5B1BA9CB2D00DE4D39 /* INAppStoreWindowCompatibility.h */, 116 | 9F836A5C1BA9CB2D00DE4D39 /* INWindowButton.h */, 117 | 9F836A5D1BA9CB2D00DE4D39 /* INWindowButton.m */, 118 | 9F836A371BA9C09C00DE4D39 /* Images.xcassets */, 119 | 9F836A391BA9C09C00DE4D39 /* Main.storyboard */, 120 | 9F836A2D1BA9C09B00DE4D39 /* Supporting Files */, 121 | ); 122 | path = "Inbox for Mac"; 123 | sourceTree = ""; 124 | }; 125 | 9F836A2D1BA9C09B00DE4D39 /* Supporting Files */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 9F836A2E1BA9C09B00DE4D39 /* Info.plist */, 129 | 9F836A321BA9C09C00DE4D39 /* main.m */, 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | 9F836A431BA9C09C00DE4D39 /* Inbox for MacTests */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 9F836A461BA9C09C00DE4D39 /* Inbox_for_MacTests.m */, 138 | 9F836A441BA9C09C00DE4D39 /* Supporting Files */, 139 | ); 140 | path = "Inbox for MacTests"; 141 | sourceTree = ""; 142 | }; 143 | 9F836A441BA9C09C00DE4D39 /* Supporting Files */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 9F836A451BA9C09C00DE4D39 /* Info.plist */, 147 | ); 148 | name = "Supporting Files"; 149 | sourceTree = ""; 150 | }; 151 | /* End PBXGroup section */ 152 | 153 | /* Begin PBXNativeTarget section */ 154 | 9F836A291BA9C09B00DE4D39 /* Inbox for Mac */ = { 155 | isa = PBXNativeTarget; 156 | buildConfigurationList = 9F836A4A1BA9C09C00DE4D39 /* Build configuration list for PBXNativeTarget "Inbox for Mac" */; 157 | buildPhases = ( 158 | 9F836A261BA9C09B00DE4D39 /* Sources */, 159 | 9F836A271BA9C09B00DE4D39 /* Frameworks */, 160 | 9F836A281BA9C09B00DE4D39 /* Resources */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | ); 166 | name = "Inbox for Mac"; 167 | productName = "Inbox for Mac"; 168 | productReference = 9F836A2A1BA9C09B00DE4D39 /* Inbox for Mac.app */; 169 | productType = "com.apple.product-type.application"; 170 | }; 171 | 9F836A3F1BA9C09C00DE4D39 /* Inbox for MacTests */ = { 172 | isa = PBXNativeTarget; 173 | buildConfigurationList = 9F836A4D1BA9C09C00DE4D39 /* Build configuration list for PBXNativeTarget "Inbox for MacTests" */; 174 | buildPhases = ( 175 | 9F836A3C1BA9C09C00DE4D39 /* Sources */, 176 | 9F836A3D1BA9C09C00DE4D39 /* Frameworks */, 177 | 9F836A3E1BA9C09C00DE4D39 /* Resources */, 178 | ); 179 | buildRules = ( 180 | ); 181 | dependencies = ( 182 | 9F836A421BA9C09C00DE4D39 /* PBXTargetDependency */, 183 | ); 184 | name = "Inbox for MacTests"; 185 | productName = "Inbox for MacTests"; 186 | productReference = 9F836A401BA9C09C00DE4D39 /* Inbox for MacTests.xctest */; 187 | productType = "com.apple.product-type.bundle.unit-test"; 188 | }; 189 | /* End PBXNativeTarget section */ 190 | 191 | /* Begin PBXProject section */ 192 | 9F836A221BA9C09B00DE4D39 /* Project object */ = { 193 | isa = PBXProject; 194 | attributes = { 195 | LastUpgradeCheck = 0640; 196 | ORGANIZATIONNAME = "Alasdair Lampon-Monk"; 197 | TargetAttributes = { 198 | 9F836A291BA9C09B00DE4D39 = { 199 | CreatedOnToolsVersion = 6.4; 200 | }; 201 | 9F836A3F1BA9C09C00DE4D39 = { 202 | CreatedOnToolsVersion = 6.4; 203 | TestTargetID = 9F836A291BA9C09B00DE4D39; 204 | }; 205 | }; 206 | }; 207 | buildConfigurationList = 9F836A251BA9C09B00DE4D39 /* Build configuration list for PBXProject "Inbox for Mac" */; 208 | compatibilityVersion = "Xcode 3.2"; 209 | developmentRegion = English; 210 | hasScannedForEncodings = 0; 211 | knownRegions = ( 212 | en, 213 | Base, 214 | ); 215 | mainGroup = 9F836A211BA9C09B00DE4D39; 216 | productRefGroup = 9F836A2B1BA9C09B00DE4D39 /* Products */; 217 | projectDirPath = ""; 218 | projectRoot = ""; 219 | targets = ( 220 | 9F836A291BA9C09B00DE4D39 /* Inbox for Mac */, 221 | 9F836A3F1BA9C09C00DE4D39 /* Inbox for MacTests */, 222 | ); 223 | }; 224 | /* End PBXProject section */ 225 | 226 | /* Begin PBXResourcesBuildPhase section */ 227 | 9F836A281BA9C09B00DE4D39 /* Resources */ = { 228 | isa = PBXResourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | 9F836A5E1BA9CB2D00DE4D39 /* Extensions in Resources */, 232 | 9FA5291C1BAA1EFE003BB8CF /* appicon.icns in Resources */, 233 | 9F836A381BA9C09C00DE4D39 /* Images.xcassets in Resources */, 234 | 9F836A3B1BA9C09C00DE4D39 /* Main.storyboard in Resources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | 9F836A3E1BA9C09C00DE4D39 /* Resources */ = { 239 | isa = PBXResourcesBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | /* End PBXResourcesBuildPhase section */ 246 | 247 | /* Begin PBXSourcesBuildPhase section */ 248 | 9F836A261BA9C09B00DE4D39 /* Sources */ = { 249 | isa = PBXSourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | 9F836A5F1BA9CB2D00DE4D39 /* INAppStoreWindow.m in Sources */, 253 | 9F836A361BA9C09C00DE4D39 /* ViewController.m in Sources */, 254 | 9F836A541BA9CA5500DE4D39 /* WAYAppStoreWindow.m in Sources */, 255 | 9F836A601BA9CB2D00DE4D39 /* INWindowButton.m in Sources */, 256 | 9F836A331BA9C09C00DE4D39 /* main.m in Sources */, 257 | 9F836A311BA9C09B00DE4D39 /* AppDelegate.m in Sources */, 258 | 9F836A571BA9CB1200DE4D39 /* WAYWindow.m in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | 9F836A3C1BA9C09C00DE4D39 /* Sources */ = { 263 | isa = PBXSourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | 9F836A471BA9C09C00DE4D39 /* Inbox_for_MacTests.m in Sources */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXSourcesBuildPhase section */ 271 | 272 | /* Begin PBXTargetDependency section */ 273 | 9F836A421BA9C09C00DE4D39 /* PBXTargetDependency */ = { 274 | isa = PBXTargetDependency; 275 | target = 9F836A291BA9C09B00DE4D39 /* Inbox for Mac */; 276 | targetProxy = 9F836A411BA9C09C00DE4D39 /* PBXContainerItemProxy */; 277 | }; 278 | /* End PBXTargetDependency section */ 279 | 280 | /* Begin PBXVariantGroup section */ 281 | 9F836A391BA9C09C00DE4D39 /* Main.storyboard */ = { 282 | isa = PBXVariantGroup; 283 | children = ( 284 | 9F836A3A1BA9C09C00DE4D39 /* Base */, 285 | ); 286 | name = Main.storyboard; 287 | sourceTree = ""; 288 | }; 289 | /* End PBXVariantGroup section */ 290 | 291 | /* Begin XCBuildConfiguration section */ 292 | 9F836A481BA9C09C00DE4D39 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ALWAYS_SEARCH_USER_PATHS = NO; 296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 297 | CLANG_CXX_LIBRARY = "libc++"; 298 | CLANG_ENABLE_MODULES = YES; 299 | CLANG_ENABLE_OBJC_ARC = YES; 300 | CLANG_WARN_BOOL_CONVERSION = YES; 301 | CLANG_WARN_CONSTANT_CONVERSION = YES; 302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 303 | CLANG_WARN_EMPTY_BODY = YES; 304 | CLANG_WARN_ENUM_CONVERSION = YES; 305 | CLANG_WARN_INT_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_UNREACHABLE_CODE = YES; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | CODE_SIGN_IDENTITY = "-"; 310 | COPY_PHASE_STRIP = NO; 311 | DEBUG_INFORMATION_FORMAT = dwarf; 312 | ENABLE_STRICT_OBJC_MSGSEND = YES; 313 | GCC_C_LANGUAGE_STANDARD = gnu99; 314 | GCC_DYNAMIC_NO_PIC = NO; 315 | GCC_NO_COMMON_BLOCKS = YES; 316 | GCC_OPTIMIZATION_LEVEL = 0; 317 | GCC_PREPROCESSOR_DEFINITIONS = ( 318 | "DEBUG=1", 319 | "$(inherited)", 320 | ); 321 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 322 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 323 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 324 | GCC_WARN_UNDECLARED_SELECTOR = YES; 325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 326 | GCC_WARN_UNUSED_FUNCTION = YES; 327 | GCC_WARN_UNUSED_VARIABLE = YES; 328 | MACOSX_DEPLOYMENT_TARGET = 10.10; 329 | MTL_ENABLE_DEBUG_INFO = YES; 330 | ONLY_ACTIVE_ARCH = YES; 331 | SDKROOT = macosx; 332 | }; 333 | name = Debug; 334 | }; 335 | 9F836A491BA9C09C00DE4D39 /* Release */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ALWAYS_SEARCH_USER_PATHS = NO; 339 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 340 | CLANG_CXX_LIBRARY = "libc++"; 341 | CLANG_ENABLE_MODULES = YES; 342 | CLANG_ENABLE_OBJC_ARC = YES; 343 | CLANG_WARN_BOOL_CONVERSION = YES; 344 | CLANG_WARN_CONSTANT_CONVERSION = YES; 345 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 346 | CLANG_WARN_EMPTY_BODY = YES; 347 | CLANG_WARN_ENUM_CONVERSION = YES; 348 | CLANG_WARN_INT_CONVERSION = YES; 349 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 350 | CLANG_WARN_UNREACHABLE_CODE = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | CODE_SIGN_IDENTITY = "-"; 353 | COPY_PHASE_STRIP = NO; 354 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 355 | ENABLE_NS_ASSERTIONS = NO; 356 | ENABLE_STRICT_OBJC_MSGSEND = YES; 357 | GCC_C_LANGUAGE_STANDARD = gnu99; 358 | GCC_NO_COMMON_BLOCKS = YES; 359 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 360 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 361 | GCC_WARN_UNDECLARED_SELECTOR = YES; 362 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 363 | GCC_WARN_UNUSED_FUNCTION = YES; 364 | GCC_WARN_UNUSED_VARIABLE = YES; 365 | MACOSX_DEPLOYMENT_TARGET = 10.10; 366 | MTL_ENABLE_DEBUG_INFO = NO; 367 | SDKROOT = macosx; 368 | }; 369 | name = Release; 370 | }; 371 | 9F836A4B1BA9C09C00DE4D39 /* Debug */ = { 372 | isa = XCBuildConfiguration; 373 | buildSettings = { 374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 375 | COMBINE_HIDPI_IMAGES = YES; 376 | INFOPLIST_FILE = "Inbox for Mac/Info.plist"; 377 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | }; 380 | name = Debug; 381 | }; 382 | 9F836A4C1BA9C09C00DE4D39 /* Release */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 386 | COMBINE_HIDPI_IMAGES = YES; 387 | INFOPLIST_FILE = "Inbox for Mac/Info.plist"; 388 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | }; 391 | name = Release; 392 | }; 393 | 9F836A4E1BA9C09C00DE4D39 /* Debug */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | BUNDLE_LOADER = "$(TEST_HOST)"; 397 | COMBINE_HIDPI_IMAGES = YES; 398 | FRAMEWORK_SEARCH_PATHS = ( 399 | "$(DEVELOPER_FRAMEWORKS_DIR)", 400 | "$(inherited)", 401 | ); 402 | GCC_PREPROCESSOR_DEFINITIONS = ( 403 | "DEBUG=1", 404 | "$(inherited)", 405 | ); 406 | INFOPLIST_FILE = "Inbox for MacTests/Info.plist"; 407 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Inbox for Mac.app/Contents/MacOS/Inbox for Mac"; 410 | }; 411 | name = Debug; 412 | }; 413 | 9F836A4F1BA9C09C00DE4D39 /* Release */ = { 414 | isa = XCBuildConfiguration; 415 | buildSettings = { 416 | BUNDLE_LOADER = "$(TEST_HOST)"; 417 | COMBINE_HIDPI_IMAGES = YES; 418 | FRAMEWORK_SEARCH_PATHS = ( 419 | "$(DEVELOPER_FRAMEWORKS_DIR)", 420 | "$(inherited)", 421 | ); 422 | INFOPLIST_FILE = "Inbox for MacTests/Info.plist"; 423 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 424 | PRODUCT_NAME = "$(TARGET_NAME)"; 425 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Inbox for Mac.app/Contents/MacOS/Inbox for Mac"; 426 | }; 427 | name = Release; 428 | }; 429 | /* End XCBuildConfiguration section */ 430 | 431 | /* Begin XCConfigurationList section */ 432 | 9F836A251BA9C09B00DE4D39 /* Build configuration list for PBXProject "Inbox for Mac" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | 9F836A481BA9C09C00DE4D39 /* Debug */, 436 | 9F836A491BA9C09C00DE4D39 /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | 9F836A4A1BA9C09C00DE4D39 /* Build configuration list for PBXNativeTarget "Inbox for Mac" */ = { 442 | isa = XCConfigurationList; 443 | buildConfigurations = ( 444 | 9F836A4B1BA9C09C00DE4D39 /* Debug */, 445 | 9F836A4C1BA9C09C00DE4D39 /* Release */, 446 | ); 447 | defaultConfigurationIsVisible = 0; 448 | defaultConfigurationName = Release; 449 | }; 450 | 9F836A4D1BA9C09C00DE4D39 /* Build configuration list for PBXNativeTarget "Inbox for MacTests" */ = { 451 | isa = XCConfigurationList; 452 | buildConfigurations = ( 453 | 9F836A4E1BA9C09C00DE4D39 /* Debug */, 454 | 9F836A4F1BA9C09C00DE4D39 /* Release */, 455 | ); 456 | defaultConfigurationIsVisible = 0; 457 | defaultConfigurationName = Release; 458 | }; 459 | /* End XCConfigurationList section */ 460 | }; 461 | rootObject = 9F836A221BA9C09B00DE4D39 /* Project object */; 462 | } 463 | -------------------------------------------------------------------------------- /Inbox for Mac/Base.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 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | --------------------------------------------------------------------------------