├── .gitignore ├── LICENSE ├── README.md ├── WAYWindow Example.png ├── WAYWindow ├── WAYWindow.h └── WAYWindow.m ├── WAYWindowDemo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── WAYWindow.xccheckout │ └── WAYWindowDemo.xccheckout └── WAYWindowDemo ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj └── MainMenu.xib ├── Info.plist ├── WAYWindow.h ├── WAYWindow.m ├── calculatorIcon@2x.png ├── dummyBackground@2x.png ├── main.m └── viewIcon@2x.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ##### 3 | # OS X temporary files that should never be committed 4 | # 5 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 6 | 7 | .DS_Store 8 | 9 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 10 | 11 | .Trashes 12 | 13 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 14 | 15 | *.swp 16 | 17 | # 18 | # *.lock - this is used and abused by many editors for many different things. 19 | # For the main ones I use (e.g. Eclipse), it should be excluded 20 | # from source-control, but YMMV. 21 | # (lock files are usually local-only file-synchronization on the local FS that should NOT go in git) 22 | # c.f. the "OPTIONAL" section at bottom though, for tool-specific variations! 23 | 24 | *.lock 25 | 26 | 27 | # 28 | # profile - REMOVED temporarily (on double-checking, I can't find it in OS X docs?) 29 | #profile 30 | 31 | 32 | #### 33 | # Xcode temporary files that should never be committed 34 | # 35 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this... 36 | 37 | *~.nib 38 | 39 | 40 | #### 41 | # Xcode build files - 42 | # 43 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" 44 | 45 | DerivedData/ 46 | 47 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" 48 | 49 | build/ 50 | 51 | 52 | ##### 53 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) 54 | # 55 | # This is complicated: 56 | # 57 | # SOMETIMES you need to put this file in version control. 58 | # Apple designed it poorly - if you use "custom executables", they are 59 | # saved in this file. 60 | # 99% of projects do NOT use those, so they do NOT want to version control this file. 61 | # ..but if you're in the 1%, comment out the line "*.pbxuser" 62 | 63 | # .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html 64 | 65 | *.pbxuser 66 | 67 | # .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html 68 | 69 | *.mode1v3 70 | 71 | # .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html 72 | 73 | *.mode2v3 74 | 75 | # .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file 76 | 77 | *.perspectivev3 78 | 79 | # NB: also, whitelist the default ones, some projects need to use these 80 | !default.pbxuser 81 | !default.mode1v3 82 | !default.mode2v3 83 | !default.perspectivev3 84 | 85 | 86 | #### 87 | # Xcode 4 - semi-personal settings 88 | # 89 | # 90 | # OPTION 1: --------------------------------- 91 | # throw away ALL personal settings (including custom schemes! 92 | # - unless they are "shared") 93 | # 94 | # NB: this is exclusive with OPTION 2 below 95 | xcuserdata 96 | 97 | # OPTION 2: --------------------------------- 98 | # get rid of ALL personal settings, but KEEP SOME OF THEM 99 | # - NB: you must manually uncomment the bits you want to keep 100 | # 101 | # NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X, 102 | # or manually install git over the top of the OS X version 103 | # NB: this is exclusive with OPTION 1 above 104 | # 105 | #xcuserdata/**/* 106 | 107 | # (requires option 2 above): Personal Schemes 108 | # 109 | #!xcuserdata/**/xcschemes/* 110 | 111 | #### 112 | # XCode 4 workspaces - more detailed 113 | # 114 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :) 115 | # 116 | # Workspace layout is quite spammy. For reference: 117 | # 118 | # /(root)/ 119 | # /(project-name).xcodeproj/ 120 | # project.pbxproj 121 | # /project.xcworkspace/ 122 | # contents.xcworkspacedata 123 | # /xcuserdata/ 124 | # /(your name)/xcuserdatad/ 125 | # UserInterfaceState.xcuserstate 126 | # /xcsshareddata/ 127 | # /xcschemes/ 128 | # (shared scheme name).xcscheme 129 | # /xcuserdata/ 130 | # /(your name)/xcuserdatad/ 131 | # (private scheme).xcscheme 132 | # xcschememanagement.plist 133 | # 134 | # 135 | 136 | #### 137 | # Xcode 4 - Deprecated classes 138 | # 139 | # Allegedly, if you manually "deprecate" your classes, they get moved here. 140 | # 141 | # We're using source-control, so this is a "feature" that we do not want! 142 | 143 | *.moved-aside 144 | 145 | #### 146 | # OPTIONAL: Some well-known tools that people use side-by-side with Xcode / iOS development 147 | # 148 | # NB: I'd rather not include these here, but gitignore's design is weak and doesn't allow 149 | # modular gitignore: you have to put EVERYTHING in one file. 150 | # 151 | # COCOAPODS: 152 | # 153 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#what-is-a-podfilelock 154 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 155 | # 156 | #!Podfile.lock 157 | # 158 | # RUBY: 159 | # 160 | # c.f. http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/ 161 | # 162 | #!Gemfile.lock 163 | # 164 | # IDEA: 165 | # 166 | #.idea 167 | # 168 | # TEXTMATE: 169 | # 170 | # -- UNVERIFIED: c.f. http://stackoverflow.com/a/50283/153422 171 | # 172 | #tm_build_errors 173 | 174 | #### 175 | # UNKNOWN: recommended by others, but I can't discover what these files are 176 | # 177 | # Community suggestions (unverified, no evidence available - DISABLED by default) 178 | # 179 | # 1. Xcode 5 - VCS file 180 | # 181 | # "The data in this file not represent state of your project. 182 | # If you'll leave this file in git - you will have merge conflicts during 183 | # pull your cahnges to other's repo" 184 | # 185 | #*.xccheckout -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | WAYWindow 2 | by Raffael Hannemann (@raffael_me, @weAreYeah) 3 | 4 | Licensed under the BSD License http://www.opensource.org/licenses/bsd-license THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WAYWindow 2 | ========= 3 | 4 | ```NSWindow``` subclass that simplifies Yosemite exclusive features: 5 | 6 | - custom titlebar height 7 | - custom traffic lights margings 8 | - simplified NSAppearance switching 9 | - and more 10 | 11 | This NSWindow subclass provides an interface to enable OS X 10.10 Yosemite exclusive features conveniently. 12 | Next to customizing the look of the ```WAYWindow``` content view, you can also customize the title bar and standard window buttons ('traffic lights'). 13 | The public interface is generally similar to ```INAppStoreWindow``` to facilitate the migration. 14 | Whenever it makes sense, the properties of your ```WAYWindow``` instance in Interface Builder are inspectable. 15 | 16 | 17 | Tips: 18 | - 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. 19 | - Also check out the new APIs in ```NSScrollView``` to make use of contentInsets, scrollInsets, and more. 20 | 21 | Many thanks to [@indragie](http://twitter.com/indragie) for his [INAppStoreWindow](https://github.com/indragiek/INAppStoreWindow/), which has been the inspiration for this class. 22 | 23 | Example 24 | ------- 25 | 26 | ![WAYWindow](WAYWindow%20Example.png) 27 | 28 | 29 | Usage 30 | ----- 31 | 32 | 1. Drag a new ```NSWindow``` instance to your XIB 33 | 2. Set the class of the instance to ```WAYWindow``` 34 | 3. Customize the properties via Interface Builder or programmatically 35 | 36 | **Note: You should probably consider using [WAYAppStoreWindow](https://github.com/weAreYeah/WAYAppStoreWindow/) instead of this class directly!** 37 | 38 | 39 | 40 | Interesting 41 | ----------- 42 | We are new, weAreYeah.com. 43 | Follow us on [@weAreYeah](http://twitter.com/weAreYeah) for upcoming goodies. 44 | 45 | License 46 | ------- 47 | 48 | Licensed under the BSD License 49 | 50 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 51 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 52 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 53 | SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 54 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 55 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 56 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 57 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 58 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | 60 | 61 | -------------------------------------------------------------------------------- /WAYWindow Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weAreYeah/WAYWindow/7d25185d0a7f3e327d4892b2aeb240c756d0f7b4/WAYWindow Example.png -------------------------------------------------------------------------------- /WAYWindow/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 | -------------------------------------------------------------------------------- /WAYWindow/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 | -------------------------------------------------------------------------------- /WAYWindowDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4D06F6551A18C13600B725C6 /* WAYWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D06F6541A18C13600B725C6 /* WAYWindow.m */; }; 11 | 4DF97AD11A17DA7700351BC9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DF97AD01A17DA7700351BC9 /* AppDelegate.m */; }; 12 | 4DF97AD31A17DA7700351BC9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DF97AD21A17DA7700351BC9 /* main.m */; }; 13 | 4DF97AD81A17DA7700351BC9 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4DF97AD61A17DA7700351BC9 /* MainMenu.xib */; }; 14 | 4DF97AFA1A17F11900351BC9 /* calculatorIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF97AF81A17F11900351BC9 /* calculatorIcon@2x.png */; }; 15 | 4DF97AFB1A17F11900351BC9 /* viewIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF97AF91A17F11900351BC9 /* viewIcon@2x.png */; }; 16 | 4DF97AFD1A17F1E600351BC9 /* dummyBackground@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF97AFC1A17F1E600351BC9 /* dummyBackground@2x.png */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 4D06F6531A18C13600B725C6 /* WAYWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAYWindow.h; sourceTree = ""; }; 21 | 4D06F6541A18C13600B725C6 /* WAYWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WAYWindow.m; sourceTree = ""; }; 22 | 4DF97ACA1A17DA7700351BC9 /* WAYWindowDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WAYWindowDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 4DF97ACE1A17DA7700351BC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | 4DF97ACF1A17DA7700351BC9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.objj.h; path = AppDelegate.h; sourceTree = ""; }; 25 | 4DF97AD01A17DA7700351BC9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 26 | 4DF97AD21A17DA7700351BC9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 27 | 4DF97AD71A17DA7700351BC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 28 | 4DF97AF81A17F11900351BC9 /* calculatorIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "calculatorIcon@2x.png"; sourceTree = ""; }; 29 | 4DF97AF91A17F11900351BC9 /* viewIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "viewIcon@2x.png"; sourceTree = ""; }; 30 | 4DF97AFC1A17F1E600351BC9 /* dummyBackground@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dummyBackground@2x.png"; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | 4DF97AC71A17DA7700351BC9 /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | 4D06F6521A18C13600B725C6 /* WAYWindow */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | 4D06F6531A18C13600B725C6 /* WAYWindow.h */, 48 | 4D06F6541A18C13600B725C6 /* WAYWindow.m */, 49 | ); 50 | path = WAYWindow; 51 | sourceTree = SOURCE_ROOT; 52 | }; 53 | 4DF97AC11A17DA7700351BC9 = { 54 | isa = PBXGroup; 55 | children = ( 56 | 4DF97ACC1A17DA7700351BC9 /* WAYWindowDemo */, 57 | 4DF97ACB1A17DA7700351BC9 /* Products */, 58 | ); 59 | sourceTree = ""; 60 | }; 61 | 4DF97ACB1A17DA7700351BC9 /* Products */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 4DF97ACA1A17DA7700351BC9 /* WAYWindowDemo.app */, 65 | ); 66 | name = Products; 67 | sourceTree = ""; 68 | }; 69 | 4DF97ACC1A17DA7700351BC9 /* WAYWindowDemo */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 4D06F6521A18C13600B725C6 /* WAYWindow */, 73 | 4DF97ACF1A17DA7700351BC9 /* AppDelegate.h */, 74 | 4DF97AD01A17DA7700351BC9 /* AppDelegate.m */, 75 | 4DF97AF81A17F11900351BC9 /* calculatorIcon@2x.png */, 76 | 4DF97AF91A17F11900351BC9 /* viewIcon@2x.png */, 77 | 4DF97AFC1A17F1E600351BC9 /* dummyBackground@2x.png */, 78 | 4DF97AD61A17DA7700351BC9 /* MainMenu.xib */, 79 | 4DF97ACD1A17DA7700351BC9 /* Supporting Files */, 80 | ); 81 | path = WAYWindowDemo; 82 | sourceTree = ""; 83 | }; 84 | 4DF97ACD1A17DA7700351BC9 /* Supporting Files */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 4DF97ACE1A17DA7700351BC9 /* Info.plist */, 88 | 4DF97AD21A17DA7700351BC9 /* main.m */, 89 | ); 90 | name = "Supporting Files"; 91 | sourceTree = ""; 92 | }; 93 | /* End PBXGroup section */ 94 | 95 | /* Begin PBXNativeTarget section */ 96 | 4DF97AC91A17DA7700351BC9 /* WAYWindowDemo */ = { 97 | isa = PBXNativeTarget; 98 | buildConfigurationList = 4DF97AE71A17DA7700351BC9 /* Build configuration list for PBXNativeTarget "WAYWindowDemo" */; 99 | buildPhases = ( 100 | 4DF97AC61A17DA7700351BC9 /* Sources */, 101 | 4DF97AC71A17DA7700351BC9 /* Frameworks */, 102 | 4DF97AC81A17DA7700351BC9 /* Resources */, 103 | ); 104 | buildRules = ( 105 | ); 106 | dependencies = ( 107 | ); 108 | name = WAYWindowDemo; 109 | productName = WAYWindow; 110 | productReference = 4DF97ACA1A17DA7700351BC9 /* WAYWindowDemo.app */; 111 | productType = "com.apple.product-type.application"; 112 | }; 113 | /* End PBXNativeTarget section */ 114 | 115 | /* Begin PBXProject section */ 116 | 4DF97AC21A17DA7700351BC9 /* Project object */ = { 117 | isa = PBXProject; 118 | attributes = { 119 | LastUpgradeCheck = 0610; 120 | ORGANIZATIONNAME = "We Are Yeah!"; 121 | TargetAttributes = { 122 | 4DF97AC91A17DA7700351BC9 = { 123 | CreatedOnToolsVersion = 6.1; 124 | }; 125 | }; 126 | }; 127 | buildConfigurationList = 4DF97AC51A17DA7700351BC9 /* Build configuration list for PBXProject "WAYWindowDemo" */; 128 | compatibilityVersion = "Xcode 3.2"; 129 | developmentRegion = English; 130 | hasScannedForEncodings = 0; 131 | knownRegions = ( 132 | en, 133 | Base, 134 | ); 135 | mainGroup = 4DF97AC11A17DA7700351BC9; 136 | productRefGroup = 4DF97ACB1A17DA7700351BC9 /* Products */; 137 | projectDirPath = ""; 138 | projectRoot = ""; 139 | targets = ( 140 | 4DF97AC91A17DA7700351BC9 /* WAYWindowDemo */, 141 | ); 142 | }; 143 | /* End PBXProject section */ 144 | 145 | /* Begin PBXResourcesBuildPhase section */ 146 | 4DF97AC81A17DA7700351BC9 /* Resources */ = { 147 | isa = PBXResourcesBuildPhase; 148 | buildActionMask = 2147483647; 149 | files = ( 150 | 4DF97AD81A17DA7700351BC9 /* MainMenu.xib in Resources */, 151 | 4DF97AFB1A17F11900351BC9 /* viewIcon@2x.png in Resources */, 152 | 4DF97AFA1A17F11900351BC9 /* calculatorIcon@2x.png in Resources */, 153 | 4DF97AFD1A17F1E600351BC9 /* dummyBackground@2x.png in Resources */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | /* End PBXResourcesBuildPhase section */ 158 | 159 | /* Begin PBXSourcesBuildPhase section */ 160 | 4DF97AC61A17DA7700351BC9 /* Sources */ = { 161 | isa = PBXSourcesBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | 4D06F6551A18C13600B725C6 /* WAYWindow.m in Sources */, 165 | 4DF97AD31A17DA7700351BC9 /* main.m in Sources */, 166 | 4DF97AD11A17DA7700351BC9 /* AppDelegate.m in Sources */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXSourcesBuildPhase section */ 171 | 172 | /* Begin PBXVariantGroup section */ 173 | 4DF97AD61A17DA7700351BC9 /* MainMenu.xib */ = { 174 | isa = PBXVariantGroup; 175 | children = ( 176 | 4DF97AD71A17DA7700351BC9 /* Base */, 177 | ); 178 | name = MainMenu.xib; 179 | sourceTree = ""; 180 | }; 181 | /* End PBXVariantGroup section */ 182 | 183 | /* Begin XCBuildConfiguration section */ 184 | 4DF97AE51A17DA7700351BC9 /* Debug */ = { 185 | isa = XCBuildConfiguration; 186 | buildSettings = { 187 | ALWAYS_SEARCH_USER_PATHS = NO; 188 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 189 | CLANG_CXX_LIBRARY = "libc++"; 190 | CLANG_ENABLE_MODULES = YES; 191 | CLANG_ENABLE_OBJC_ARC = YES; 192 | CLANG_WARN_BOOL_CONVERSION = YES; 193 | CLANG_WARN_CONSTANT_CONVERSION = YES; 194 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 195 | CLANG_WARN_EMPTY_BODY = YES; 196 | CLANG_WARN_ENUM_CONVERSION = YES; 197 | CLANG_WARN_INT_CONVERSION = YES; 198 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 199 | CLANG_WARN_UNREACHABLE_CODE = YES; 200 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 201 | CODE_SIGN_IDENTITY = "-"; 202 | COPY_PHASE_STRIP = NO; 203 | ENABLE_STRICT_OBJC_MSGSEND = YES; 204 | GCC_C_LANGUAGE_STANDARD = gnu99; 205 | GCC_DYNAMIC_NO_PIC = NO; 206 | GCC_OPTIMIZATION_LEVEL = 0; 207 | GCC_PREPROCESSOR_DEFINITIONS = ( 208 | "DEBUG=1", 209 | "$(inherited)", 210 | ); 211 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 212 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 213 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 214 | GCC_WARN_UNDECLARED_SELECTOR = YES; 215 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 216 | GCC_WARN_UNUSED_FUNCTION = YES; 217 | GCC_WARN_UNUSED_VARIABLE = YES; 218 | MACOSX_DEPLOYMENT_TARGET = 10.10; 219 | MTL_ENABLE_DEBUG_INFO = YES; 220 | ONLY_ACTIVE_ARCH = YES; 221 | SDKROOT = macosx; 222 | }; 223 | name = Debug; 224 | }; 225 | 4DF97AE61A17DA7700351BC9 /* Release */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_WARN_BOOL_CONVERSION = YES; 234 | CLANG_WARN_CONSTANT_CONVERSION = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | CODE_SIGN_IDENTITY = "-"; 243 | COPY_PHASE_STRIP = YES; 244 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 245 | ENABLE_NS_ASSERTIONS = NO; 246 | ENABLE_STRICT_OBJC_MSGSEND = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 250 | GCC_WARN_UNDECLARED_SELECTOR = YES; 251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 252 | GCC_WARN_UNUSED_FUNCTION = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | MACOSX_DEPLOYMENT_TARGET = 10.10; 255 | MTL_ENABLE_DEBUG_INFO = NO; 256 | SDKROOT = macosx; 257 | }; 258 | name = Release; 259 | }; 260 | 4DF97AE81A17DA7700351BC9 /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 264 | COMBINE_HIDPI_IMAGES = YES; 265 | INFOPLIST_FILE = "$(SRCROOT)/WAYWindowDemo/Info.plist"; 266 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 267 | PRODUCT_NAME = WAYWindowDemo; 268 | }; 269 | name = Debug; 270 | }; 271 | 4DF97AE91A17DA7700351BC9 /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 275 | COMBINE_HIDPI_IMAGES = YES; 276 | INFOPLIST_FILE = "$(SRCROOT)/WAYWindowDemo/Info.plist"; 277 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 278 | PRODUCT_NAME = WAYWindowDemo; 279 | }; 280 | name = Release; 281 | }; 282 | /* End XCBuildConfiguration section */ 283 | 284 | /* Begin XCConfigurationList section */ 285 | 4DF97AC51A17DA7700351BC9 /* Build configuration list for PBXProject "WAYWindowDemo" */ = { 286 | isa = XCConfigurationList; 287 | buildConfigurations = ( 288 | 4DF97AE51A17DA7700351BC9 /* Debug */, 289 | 4DF97AE61A17DA7700351BC9 /* Release */, 290 | ); 291 | defaultConfigurationIsVisible = 0; 292 | defaultConfigurationName = Release; 293 | }; 294 | 4DF97AE71A17DA7700351BC9 /* Build configuration list for PBXNativeTarget "WAYWindowDemo" */ = { 295 | isa = XCConfigurationList; 296 | buildConfigurations = ( 297 | 4DF97AE81A17DA7700351BC9 /* Debug */, 298 | 4DF97AE91A17DA7700351BC9 /* Release */, 299 | ); 300 | defaultConfigurationIsVisible = 0; 301 | defaultConfigurationName = Release; 302 | }; 303 | /* End XCConfigurationList section */ 304 | }; 305 | rootObject = 4DF97AC21A17DA7700351BC9 /* Project object */; 306 | } 307 | -------------------------------------------------------------------------------- /WAYWindowDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WAYWindowDemo.xcodeproj/project.xcworkspace/xcshareddata/WAYWindow.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | A133E621-7D99-47BA-83AB-1FBAB9AE441B 9 | IDESourceControlProjectOriginsDictionary 10 | 11 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 12 | https://github.com/weAreYeah/WAYWindow.git 13 | 14 | IDESourceControlProjectRelativeInstallPathDictionary 15 | 16 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 17 | WAYWindow/ 18 | 19 | IDESourceControlProjectURL 20 | https://github.com/weAreYeah/WAYWindow.git 21 | IDESourceControlProjectVersion 22 | 111 23 | IDESourceControlProjectWCCIdentifier 24 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 25 | IDESourceControlProjectWCConfigurations 26 | 27 | 28 | IDESourceControlRepositoryExtensionIdentifierKey 29 | public.vcs.git 30 | IDESourceControlWCCIdentifierKey 31 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 32 | IDESourceControlWCCName 33 | WAYWindow 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /WAYWindowDemo.xcodeproj/project.xcworkspace/xcshareddata/WAYWindowDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | D7D9DF91-EC69-454D-809B-D007E8C6135B 9 | IDESourceControlProjectName 10 | WAYWindowDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 14 | https://github.com/weAreYeah/WAYWindow.git 15 | 16 | IDESourceControlProjectPath 17 | WAYWindowDemo.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/weAreYeah/WAYWindow.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C1421C99D055D3A535089DA2BBEC5EFC9A0200F0 36 | IDESourceControlWCCName 37 | WAYWindow 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /WAYWindowDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // WAYWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 We Are Yeah!. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /WAYWindowDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // WAYWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 We Are Yeah!. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "WAYWindow.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @property (weak) IBOutlet WAYWindow *window; 15 | @property (weak) IBOutlet NSView *titlebar; 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 21 | // Insert code here to initialize your application 22 | [_window setVibrantDarkAppearance]; 23 | [_window setContentViewAppearanceVibrantDark]; 24 | [_window.titleBarView addSubview:_titlebar]; 25 | } 26 | 27 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 28 | // Insert code here to tear down your application 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /WAYWindowDemo/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 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 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | Default 540 | 541 | 542 | 543 | 544 | 545 | 546 | Left to Right 547 | 548 | 549 | 550 | 551 | 552 | 553 | Right to Left 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | Default 565 | 566 | 567 | 568 | 569 | 570 | 571 | Left to Right 572 | 573 | 574 | 575 | 576 | 577 | 578 | Right to Left 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | -------------------------------------------------------------------------------- /WAYWindowDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.weareyeah.$(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 © 2014 We Are Yeah!. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /WAYWindowDemo/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 facilitate 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. 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) NSView *titleBarView; 40 | 41 | /// If set to YES, the standard window button will be vertically centered. 42 | @property (nonatomic) IBInspectable BOOL centerTrafficLightButtons; 43 | 44 | /// Defines the left margin of the standard window buttons 45 | @property (nonatomic) IBInspectable CGFloat trafficLightButtonsLeftMargin; 46 | 47 | /// If set to YES, the title of the window will be hidden. 48 | @property (nonatomic) IBInspectable BOOL hidesTitle; 49 | 50 | /// 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. 51 | - (void) setContentViewAppearanceVibrantDark; 52 | 53 | /// 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. 54 | - (void) setContentViewAppearanceVibrantLight; 55 | 56 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantDark 57 | - (void) setVibrantDarkAppearance; 58 | 59 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantLight 60 | - (void) setVibrantLightAppearance; 61 | 62 | /// Convenient method to set the NSAppearance of the window to NSAppearanceNameVibrantAqua 63 | - (void) setAquaAppearance; 64 | 65 | /// 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. 66 | - (void) replaceSubview: (NSView *) aView withView: (NSView *) newView resizing: (BOOL) flag; 67 | 68 | /// 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. 69 | - (NSView *) replaceSubview: (NSView *) aView withViewOfClass: (Class) newViewClass; 70 | 71 | /// Returns YES if the window is currently in full-screen. 72 | - (BOOL) isFullScreen; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /WAYWindowDemo/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 | @interface WAYWindowDelegateProxy : NSProxy 24 | @property (nonatomic, assign) id secondaryDelegate; 25 | @end 26 | 27 | @implementation WAYWindowDelegateProxy 28 | @end 29 | 30 | @interface WAYWindow () 31 | @property (strong) WAYWindowDelegateProxy* delegateProxy; 32 | @property (strong) NSArray* standardButtons; 33 | @property (strong) NSTitlebarAccessoryViewController *dummyTitlebarAccessoryViewController; 34 | 35 | @end 36 | 37 | static float kWAYWindowDefaultTrafficLightButtonsLeftMargin = 0; 38 | static float kWAYWindowDefaultTrafficLightButtonsTopMargin = 0; 39 | 40 | @implementation WAYWindow 41 | 42 | + (BOOL) supportsVibrantAppearances { 43 | return (NSClassFromString(@"NSVisualEffectView")!=nil); 44 | } 45 | 46 | + (float) defaultTitleBarHeight { 47 | NSRect frame = NSMakeRect(0, 0, 800, 600); 48 | NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask: NSTitledWindowMask]; 49 | return NSHeight(frame) - NSHeight(contentRect); 50 | } 51 | 52 | #pragma mark - NSWindow Overwritings 53 | 54 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { 55 | if ((self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag])) { 56 | [self setUp]; 57 | } 58 | return self; 59 | } 60 | 61 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)screen { 62 | if ((self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag screen:screen])) { 63 | [self setUp]; 64 | } 65 | return self; 66 | } 67 | 68 | - (void) setDelegate:(id)delegate { 69 | [_delegateProxy setSecondaryDelegate:delegate]; 70 | [super setDelegate:_delegateProxy]; 71 | } 72 | 73 | - (id) delegate { 74 | return [_delegateProxy secondaryDelegate]; 75 | } 76 | 77 | - (void) setFrame:(NSRect)frameRect display:(BOOL)flag { 78 | [super setFrame:frameRect display:flag]; 79 | [self setNeedsLayout]; 80 | } 81 | 82 | #pragma mark - Public 83 | 84 | - (NSView *) titleBarView { 85 | return [_standardButtons[0] superview]; 86 | } 87 | 88 | - (void) setCenterTrafficLightButtons:(BOOL)centerTrafficLightButtons { 89 | _centerTrafficLightButtons = centerTrafficLightButtons; 90 | [self setNeedsLayout]; 91 | } 92 | 93 | - (void) setTitleBarHeight:(CGFloat)titleBarHeight { 94 | if (_dummyTitlebarAccessoryViewController) { 95 | [self removeTitlebarAccessoryViewControllerAtIndex:0]; 96 | } 97 | 98 | NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, titleBarHeight-[WAYWindow defaultTitleBarHeight])]; 99 | _dummyTitlebarAccessoryViewController = [NSTitlebarAccessoryViewController new]; 100 | _dummyTitlebarAccessoryViewController.view = view; 101 | [self addTitlebarAccessoryViewController:_dummyTitlebarAccessoryViewController]; 102 | } 103 | 104 | - (void) setHidesTitle:(BOOL)hidesTitle { 105 | _hidesTitle = hidesTitle; 106 | [self setTitleVisibility:hidesTitle ? NSWindowTitleHidden : NSWindowTitleVisible]; 107 | } 108 | 109 | - (void) setContentViewAppearanceVibrantDark { 110 | [self setContentViewAppearance:NSVisualEffectMaterialDark]; 111 | } 112 | 113 | - (void) setContentViewAppearanceVibrantLight { 114 | [self setContentViewAppearance:NSVisualEffectMaterialLight]; 115 | } 116 | 117 | - (void) setContentViewAppearance: (int) material { 118 | if (![WAYWindow supportsVibrantAppearances]) 119 | return; 120 | 121 | NSVisualEffectView *newContentView = [self replaceSubview:self.contentView withViewOfClass:[NSVisualEffectView class]]; 122 | [newContentView setMaterial:material]; 123 | [self setContentView:newContentView]; 124 | } 125 | 126 | - (void) setVibrantDarkAppearance { 127 | [self setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]]; 128 | } 129 | 130 | - (void) setVibrantLightAppearance { 131 | [self setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]]; 132 | } 133 | 134 | - (void) setAquaAppearance { 135 | [self setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]]; 136 | } 137 | 138 | - (BOOL) isFullScreen { 139 | return (([self styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask); 140 | } 141 | 142 | - (void) replaceSubview: (NSView *) aView withView: (NSView *) newView resizing:(BOOL)flag { 143 | if (flag) { 144 | [newView setFrame:aView.frame]; 145 | } 146 | 147 | [newView setAutoresizesSubviews:aView.autoresizesSubviews]; 148 | [aView.subviews.copy enumerateObjectsUsingBlock:^(NSView *subview, NSUInteger idx, BOOL *stop) { 149 | NSRect frame = subview.frame; 150 | if (subview.constraints.count>0) { 151 | NSLog(@"WARNING: [%@ %@] does not work yet with NSView instances, that use auto-layout.", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); 152 | } 153 | [subview removeFromSuperview]; 154 | [newView addSubview:subview]; 155 | [subview setFrame:frame]; 156 | }]; 157 | 158 | if (aView==self.contentView) { 159 | [self setContentView: newView]; 160 | } else { 161 | [aView.superview replaceSubview:aView with:newView]; 162 | } 163 | } 164 | 165 | - (NSView *) replaceSubview:(NSView *)aView withViewOfClass:(Class)newViewClass { 166 | NSView *view = [[newViewClass alloc] initWithFrame:aView.frame]; 167 | [self replaceSubview:aView withView:view resizing:YES]; 168 | return view; 169 | } 170 | 171 | #pragma mark - Private 172 | 173 | - (void) setUp { 174 | _delegateProxy = [WAYWindowDelegateProxy alloc]; 175 | _standardButtons = @[[self standardWindowButton:NSWindowCloseButton], 176 | [self standardWindowButton:NSWindowMiniaturizeButton], 177 | [self standardWindowButton:NSWindowZoomButton]]; 178 | _centerTrafficLightButtons = YES; 179 | 180 | NSButton *closeButton = [self standardWindowButton:NSWindowCloseButton]; 181 | kWAYWindowDefaultTrafficLightButtonsLeftMargin = NSMinX(closeButton.frame); 182 | kWAYWindowDefaultTrafficLightButtonsTopMargin = NSHeight(closeButton.superview.frame)-NSMaxY(closeButton.frame); 183 | 184 | self.styleMask |= NSFullSizeContentViewWindowMask; 185 | _trafficLightButtonsLeftMargin = kWAYWindowDefaultTrafficLightButtonsLeftMargin; 186 | 187 | [super setDelegate:self]; 188 | [self setNeedsLayout]; 189 | } 190 | 191 | - (void) setNeedsLayout { 192 | [_standardButtons enumerateObjectsUsingBlock:^(NSButton *standardButton, NSUInteger idx, BOOL *stop) { 193 | NSRect frame = standardButton.frame; 194 | if (_centerTrafficLightButtons) frame.origin.y = NSHeight(standardButton.superview.frame)/2-NSHeight(standardButton.frame)/2; 195 | else frame.origin.y = NSHeight(standardButton.superview.frame)-NSHeight(standardButton.frame)-kWAYWindowDefaultTrafficLightButtonsTopMargin; 196 | 197 | frame.origin.x = _trafficLightButtonsLeftMargin +idx*(NSWidth(frame) + 6); 198 | [standardButton setFrame:frame]; 199 | }]; 200 | } 201 | 202 | #pragma mark - NSWindow Delegate 203 | 204 | - (void) windowDidResize:(NSNotification *)notification { 205 | [self setNeedsLayout]; 206 | } 207 | 208 | @end 209 | -------------------------------------------------------------------------------- /WAYWindowDemo/calculatorIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weAreYeah/WAYWindow/7d25185d0a7f3e327d4892b2aeb240c756d0f7b4/WAYWindowDemo/calculatorIcon@2x.png -------------------------------------------------------------------------------- /WAYWindowDemo/dummyBackground@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weAreYeah/WAYWindow/7d25185d0a7f3e327d4892b2aeb240c756d0f7b4/WAYWindowDemo/dummyBackground@2x.png -------------------------------------------------------------------------------- /WAYWindowDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WAYWindow 4 | // 5 | // Created by Raffael Hannemann on 15.11.14. 6 | // Copyright (c) 2014 We Are Yeah!. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /WAYWindowDemo/viewIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weAreYeah/WAYWindow/7d25185d0a7f3e327d4892b2aeb240c756d0f7b4/WAYWindowDemo/viewIcon@2x.png --------------------------------------------------------------------------------