diff --git a/Classes/OBMenuBarWindow.h b/Classes/OBMenuBarWindow.h index 6de34a7..591832c 100644 --- a/Classes/OBMenuBarWindow.h +++ b/Classes/OBMenuBarWindow.h @@ -35,7 +35,6 @@ extern NSString * const OBMenuBarWindowDidAttachToMenuBar; extern NSString * const OBMenuBarWindowDidDetachFromMenuBar; // Constants -extern const CGFloat OBMenuBarWindowTitleBarHeight; extern const CGFloat OBMenuBarWindowArrowHeight; extern const CGFloat OBMenuBarWindowArrowWidth; @@ -102,6 +101,14 @@ extern const CGFloat OBMenuBarWindowArrowWidth; is set to `YES`. */ @property (nonatomic, assign) BOOL attachedToMenuBar; +/** Whether the window should 'orderOut' if looses focus but the app remains active. + + Setting this to NO helps in case the window should remain visible if it opens a child Window, + like a Preferences Window. + Default is YES which will orderOut this Window if it opens another window, even if it is a child Window. + */ +@property (nonatomic, assign) BOOL isAllowOrderOutWindowIfAppActive; + /** Whether to hide the "traffic light" window controls when the window is attached to the menu bar (default is `YES`). */ @property (nonatomic, assign) BOOL hideWindowControlsWhenAttached; @@ -114,6 +121,9 @@ extern const CGFloat OBMenuBarWindowArrowWidth; 30.0 pixels). */ @property (assign) CGFloat snapDistance; +/** Height of the Title Bar */ +@property (nonatomic, assign) CGFloat windowTitleBarHeight; + /** The icon to show in the menu bar. The image should have a maximum height of 22 pixels (or 44 pixels for retina displays). */ @property (nonatomic, strong) NSImage *menuBarIcon; diff --git a/Classes/OBMenuBarWindow.m b/Classes/OBMenuBarWindow.m index 1a1af8c..1268fe9 100644 --- a/Classes/OBMenuBarWindow.m +++ b/Classes/OBMenuBarWindow.m @@ -35,7 +35,7 @@ NSString * const OBMenuBarWindowDidDetachFromMenuBar = @"OBMenuBarWindowDidDetachFromMenuBar"; // You can alter these constants to change the appearance of the window -const CGFloat OBMenuBarWindowTitleBarHeight = 22.0; +const CGFloat OBMenuBarWindowTitleBarDefaultHeight = 22.0; const CGFloat OBMenuBarWindowArrowHeight = 10.0; const CGFloat OBMenuBarWindowArrowWidth = 20.0; @@ -85,6 +85,8 @@ - (id)initWithContentRect:(NSRect)contentRect snapDistance = 30.0; hideWindowControlsWhenAttached = YES; isDetachable = YES; + self.isAllowOrderOutWindowIfAppActive = YES; + self.windowTitleBarHeight = OBMenuBarWindowTitleBarDefaultHeight; [self initialSetup]; } return self; @@ -204,7 +206,7 @@ - (void)layoutContent // Position the content view NSRect contentViewFrame = [self.contentView frame]; CGFloat currentTopMargin = NSHeight(self.frame) - NSHeight(contentViewFrame); - CGFloat titleBarHeight = OBMenuBarWindowTitleBarHeight + (self.attachedToMenuBar ? OBMenuBarWindowArrowHeight : 0) + 1; + CGFloat titleBarHeight = self.windowTitleBarHeight + (self.attachedToMenuBar ? OBMenuBarWindowArrowHeight : 0) + 1; CGFloat delta = titleBarHeight - currentTopMargin; contentViewFrame.size.height -= delta; [self.contentView setFrame:contentViewFrame]; @@ -228,7 +230,7 @@ - (void)setHasMenuBarIcon:(BOOL)flag statusItemView = [[OBMenuBarWindowIconView alloc] initWithFrame:NSMakeRect(0, 0, (self.menuBarIcon ? self.menuBarIcon.size.width : thickness) + 6, thickness)]; statusItemView.menuBarWindow = self; statusItem.view = statusItemView; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusItemViewDidMove:) name:NSWindowDidMoveNotification object:statusItem.view.window]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusItemViewDidMove:) name:NSWindowDidMoveNotification object:statusItemView.window]; } else { @@ -416,9 +418,9 @@ - (void)setTitle:(NSString *)aString - (NSRect)titleBarRect { return NSMakeRect(0, - self.frame.size.height - OBMenuBarWindowTitleBarHeight - (self.attachedToMenuBar ? OBMenuBarWindowArrowHeight : 0), + self.frame.size.height - self.windowTitleBarHeight - (self.attachedToMenuBar ? OBMenuBarWindowArrowHeight : 0), self.frame.size.width, - OBMenuBarWindowTitleBarHeight + (self.attachedToMenuBar ? OBMenuBarWindowArrowHeight : 0)); + self.windowTitleBarHeight + (self.attachedToMenuBar ? OBMenuBarWindowArrowHeight : 0)); } - (NSRect)toolbarRect @@ -426,9 +428,9 @@ - (NSRect)toolbarRect if (self.attachedToMenuBar) { return NSMakeRect(0, - self.frame.size.height - OBMenuBarWindowTitleBarHeight - OBMenuBarWindowArrowHeight, + self.frame.size.height - self.windowTitleBarHeight - OBMenuBarWindowArrowHeight, self.frame.size.width, - OBMenuBarWindowTitleBarHeight); + self.windowTitleBarHeight); } else { @@ -436,6 +438,13 @@ - (NSRect)toolbarRect } } +#pragma mark - Property methods + +- (void)setWindowTitleBarHeight:(CGFloat)toTitleBarHeight { + _windowTitleBarHeight = toTitleBarHeight; + [self layoutContent]; +} + #pragma mark - Active/key events - (BOOL)canBecomeKeyWindow @@ -451,13 +460,16 @@ - (void)applicationDidChangeActiveStatus:(NSNotification *)aNotification - (void)windowDidBecomeKey:(NSNotification *)aNotification { [[self.contentView superview] setNeedsDisplayInRect:[self titleBarRect]]; + [self updateWindowPositionByMenuBar]; } - (void)windowDidResignKey:(NSNotification *)aNotification { if (self.attachedToMenuBar) { - [self orderOut:self]; + if( self.isAllowOrderOutWindowIfAppActive || (!self.isAllowOrderOutWindowIfAppActive && ![NSApp keyWindow]) ) { + [self orderOut:self]; + } } [[self.contentView superview] setNeedsDisplayInRect:[self titleBarRect]]; } @@ -470,9 +482,20 @@ - (NSPoint)originForAttachedState { NSRect statusItemFrame = [[statusItemView window] frame]; NSPoint midPoint = NSMakePoint(NSMidX(statusItemFrame), - NSMinY(statusItemFrame)); - return NSMakePoint(midPoint.x - (self.frame.size.width / 2), - midPoint.y - self.frame.size.height); + statusItemFrame.origin.y); + + NSScreen *screenWithMenuBar = [[NSScreen screens] objectAtIndex:0]; + if( screenWithMenuBar ) { + // correct the top position by the 'screen with the MenuBar's height + // workaround: without this the window will be off-placed when the user plugs in an external display, + // a display with more height + NSRect visibleRect = [screenWithMenuBar visibleFrame]; + midPoint.y = visibleRect.size.height + visibleRect.origin.y; + } + + NSPoint originPoint = NSMakePoint(midPoint.x - (self.frame.size.width / 2), + midPoint.y - self.frame.size.height); + return originPoint; } else { @@ -482,10 +505,7 @@ - (NSPoint)originForAttachedState - (void)makeKeyAndOrderFront:(id)sender { - if (self.attachedToMenuBar) - { - [self setFrameOrigin:[self originForAttachedState]]; - } + [self updateWindowPositionByMenuBar]; [super makeKeyAndOrderFront:sender]; } @@ -586,7 +606,7 @@ - (void)windowDidMove:(NSNotification *)aNotification [self layoutContent]; } -- (void)statusItemViewDidMove:(NSNotification *)aNotification +- (void)updateWindowPositionByMenuBar { if (self.attachedToMenuBar) { @@ -594,6 +614,11 @@ - (void)statusItemViewDidMove:(NSNotification *)aNotification } } +- (void)statusItemViewDidMove:(NSNotification *)aNotification +{ + [self updateWindowPositionByMenuBar]; +} + - (void)setFrame:(NSRect)frameRect display:(BOOL)flag { if ([self inLiveResize] && self.attachedToMenuBar) @@ -698,7 +723,7 @@ - (void)drawRect:(NSRect)dirtyRect NSRectFill(dirtyRect); // Erase the default title bar - CGFloat titleBarHeight = OBMenuBarWindowTitleBarHeight + (isAttached ? OBMenuBarWindowArrowHeight : 0); + CGFloat titleBarHeight = window.windowTitleBarHeight + (isAttached ? OBMenuBarWindowArrowHeight : 0); [[NSColor clearColor] set]; NSRectFillUsingOperation([window titleBarRect], NSCompositeClear); @@ -723,9 +748,9 @@ - (void)drawRect:(NSRect)dirtyRect NSPoint topRight = NSMakePoint(originX + width, originY + height - (isAttached ? OBMenuBarWindowArrowHeight : 0)); NSPoint bottomLeft = NSMakePoint(originX, - originY + height - arrowHeight - OBMenuBarWindowTitleBarHeight); + originY + height - arrowHeight - window.windowTitleBarHeight); NSPoint bottomRight = NSMakePoint(originX + width, - originY + height - arrowHeight - OBMenuBarWindowTitleBarHeight); + originY + height - arrowHeight - window.windowTitleBarHeight); NSBezierPath *border = [NSBezierPath bezierPath]; [border moveToPoint:arrowPointLeft]; @@ -748,11 +773,11 @@ - (void)drawRect:(NSRect)dirtyRect NSRect headingRect = NSMakeRect(originX, originY + height - titleBarHeight, width, - OBMenuBarWindowTitleBarHeight); + window.windowTitleBarHeight); NSRect titleBarRect = NSMakeRect(originX, originY + height - titleBarHeight, width, - OBMenuBarWindowTitleBarHeight + OBMenuBarWindowArrowHeight); + window.windowTitleBarHeight + OBMenuBarWindowArrowHeight); // Colors NSColor *bottomColor, *topColor, *topColorTransparent; @@ -818,7 +843,7 @@ - (void)drawRect:(NSRect)dirtyRect // Draw separator line between the titlebar and the content view [[NSColor colorWithCalibratedWhite:0.5 alpha:1.0] set]; NSRect separatorRect = NSMakeRect(originX, - originY + height - OBMenuBarWindowTitleBarHeight - (isAttached ? OBMenuBarWindowArrowHeight : 0) - 1, + originY + height - window.windowTitleBarHeight - (isAttached ? OBMenuBarWindowArrowHeight : 0) - 1, width, 1); NSRectFill(separatorRect);