From 88b21a59ad2a919115de60c7bfa96b468ffb765d Mon Sep 17 00:00:00 2001 From: Viktor Benei Date: Fri, 5 Jul 2013 14:43:45 +0200 Subject: [PATCH 1/5] Option to don't orderOut the Window if the app is still active (another Window of the app is keyWindow) --- Classes/OBMenuBarWindow.h | 8 ++++++++ Classes/OBMenuBarWindow.m | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Classes/OBMenuBarWindow.h b/Classes/OBMenuBarWindow.h index 6de34a7..301dcc2 100644 --- a/Classes/OBMenuBarWindow.h +++ b/Classes/OBMenuBarWindow.h @@ -102,6 +102,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; diff --git a/Classes/OBMenuBarWindow.m b/Classes/OBMenuBarWindow.m index 1a1af8c..1a623da 100644 --- a/Classes/OBMenuBarWindow.m +++ b/Classes/OBMenuBarWindow.m @@ -85,6 +85,7 @@ - (id)initWithContentRect:(NSRect)contentRect snapDistance = 30.0; hideWindowControlsWhenAttached = YES; isDetachable = YES; + self.isAllowOrderOutWindowIfAppActive = YES; [self initialSetup]; } return self; @@ -457,7 +458,9 @@ - (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]]; } From 9a285bd296331083516ea5dadf6233e8a286c989 Mon Sep 17 00:00:00 2001 From: Viktor Benei Date: Fri, 5 Jul 2013 15:49:57 +0200 Subject: [PATCH 2/5] Option to set the WindowTitleBar's Height without modifying the OBMenuBarWindow source code --- Classes/OBMenuBarWindow.h | 4 +++- Classes/OBMenuBarWindow.m | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Classes/OBMenuBarWindow.h b/Classes/OBMenuBarWindow.h index 301dcc2..53edd77 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; @@ -122,6 +121,9 @@ extern const CGFloat OBMenuBarWindowArrowWidth; 30.0 pixels). */ @property (assign) CGFloat snapDistance; +/** Height of the Title Bar */ +@property (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 1a623da..e4bf5ff 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; @@ -86,6 +86,7 @@ - (id)initWithContentRect:(NSRect)contentRect hideWindowControlsWhenAttached = YES; isDetachable = YES; self.isAllowOrderOutWindowIfAppActive = YES; + self.windowTitleBarHeight = OBMenuBarWindowTitleBarDefaultHeight; [self initialSetup]; } return self; @@ -205,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]; @@ -417,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 @@ -427,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 { @@ -701,7 +702,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); @@ -726,9 +727,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]; @@ -751,11 +752,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; @@ -821,7 +822,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); From 9c90d7b5759b547e0963297af9249d2006782ea0 Mon Sep 17 00:00:00 2001 From: Viktor Benei Date: Fri, 5 Jul 2013 17:02:27 +0200 Subject: [PATCH 3/5] setWindowTitleBarHeight setter now refreshes the layout (as the title setter does) --- Classes/OBMenuBarWindow.h | 2 +- Classes/OBMenuBarWindow.m | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Classes/OBMenuBarWindow.h b/Classes/OBMenuBarWindow.h index 53edd77..591832c 100644 --- a/Classes/OBMenuBarWindow.h +++ b/Classes/OBMenuBarWindow.h @@ -122,7 +122,7 @@ extern const CGFloat OBMenuBarWindowArrowWidth; @property (assign) CGFloat snapDistance; /** Height of the Title Bar */ -@property (assign) CGFloat windowTitleBarHeight; +@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). */ diff --git a/Classes/OBMenuBarWindow.m b/Classes/OBMenuBarWindow.m index e4bf5ff..dcd2d1c 100644 --- a/Classes/OBMenuBarWindow.m +++ b/Classes/OBMenuBarWindow.m @@ -438,6 +438,13 @@ - (NSRect)toolbarRect } } +#pragma mark - Property methods + +- (void)setWindowTitleBarHeight:(CGFloat)toTitleBarHeight { + _windowTitleBarHeight = toTitleBarHeight; + [self layoutContent]; +} + #pragma mark - Active/key events - (BOOL)canBecomeKeyWindow From aa2471d7b4bec24071a73c56dd6d9c00dffc72fc Mon Sep 17 00:00:00 2001 From: Viktor Benei Date: Sun, 21 Jul 2013 21:42:10 +0200 Subject: [PATCH 4/5] bugfix: the window is misplaced when the user connects an external monitor - the window will be presented at the same Y coordinate when it was before on the smaller screen [fixed] + some code DRY --- Classes/OBMenuBarWindow.m | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/Classes/OBMenuBarWindow.m b/Classes/OBMenuBarWindow.m index dcd2d1c..8359164 100644 --- a/Classes/OBMenuBarWindow.m +++ b/Classes/OBMenuBarWindow.m @@ -230,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 { @@ -460,6 +460,7 @@ - (void)applicationDidChangeActiveStatus:(NSNotification *)aNotification - (void)windowDidBecomeKey:(NSNotification *)aNotification { [[self.contentView superview] setNeedsDisplayInRect:[self titleBarRect]]; + [self updateWindowPositionByMenuBar]; } - (void)windowDidResignKey:(NSNotification *)aNotification @@ -481,9 +482,19 @@ - (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 + midPoint.y = [screenWithMenuBar visibleFrame].size.height; + } + + NSPoint originPoint = NSMakePoint(midPoint.x - (self.frame.size.width / 2), + midPoint.y - self.frame.size.height); + return originPoint; } else { @@ -493,10 +504,7 @@ - (NSPoint)originForAttachedState - (void)makeKeyAndOrderFront:(id)sender { - if (self.attachedToMenuBar) - { - [self setFrameOrigin:[self originForAttachedState]]; - } + [self updateWindowPositionByMenuBar]; [super makeKeyAndOrderFront:sender]; } @@ -597,7 +605,7 @@ - (void)windowDidMove:(NSNotification *)aNotification [self layoutContent]; } -- (void)statusItemViewDidMove:(NSNotification *)aNotification +- (void)updateWindowPositionByMenuBar { if (self.attachedToMenuBar) { @@ -605,6 +613,11 @@ - (void)statusItemViewDidMove:(NSNotification *)aNotification } } +- (void)statusItemViewDidMove:(NSNotification *)aNotification +{ + [self updateWindowPositionByMenuBar]; +} + - (void)setFrame:(NSRect)frameRect display:(BOOL)flag { if ([self inLiveResize] && self.attachedToMenuBar) From 7316389142b82f3a4bad7f9662d3f42aa5c5afb7 Mon Sep 17 00:00:00 2001 From: Viktor Benei Date: Mon, 22 Jul 2013 14:15:21 +0200 Subject: [PATCH 5/5] another external-monitor switch position fix - have to add the visibleRect's Y coordinate in case the Dock is at the bottom of the screen --- Classes/OBMenuBarWindow.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/OBMenuBarWindow.m b/Classes/OBMenuBarWindow.m index 8359164..1268fe9 100644 --- a/Classes/OBMenuBarWindow.m +++ b/Classes/OBMenuBarWindow.m @@ -489,7 +489,8 @@ - (NSPoint)originForAttachedState // 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 - midPoint.y = [screenWithMenuBar visibleFrame].size.height; + NSRect visibleRect = [screenWithMenuBar visibleFrame]; + midPoint.y = visibleRect.size.height + visibleRect.origin.y; } NSPoint originPoint = NSMakePoint(midPoint.x - (self.frame.size.width / 2),