From 9b4664daa57fb84a011048636d96c884b2c23256 Mon Sep 17 00:00:00 2001 From: mst128256 Date: Fri, 17 Mar 2017 21:18:05 +0100 Subject: [PATCH 01/16] Area near the top border in frameless window is clickable --- atom/browser/native_window_mac.mm | 143 +++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 20 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index e5192c8b629..be5d754a246 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -46,6 +46,95 @@ bool ScopedDisableResize::disable_resize_ = false; } // namespace +// This view encapsuate Quit, Minimize and Full Screen buttons. It is being +// used for frameless window. +@interface SemaphoreView : NSView +@end + +@implementation SemaphoreView + +BOOL mouseInside = NO; + +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) { + + // create buttons + NSButton *closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSTitledWindowMask]; + NSButton *minitButton = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSTitledWindowMask]; + NSButton *fullScreenButton = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSTitledWindowMask]; + + // size view for buttons + const int top = 3; + const int bottom = 3; + const int left = 7; + const int between = 6; + const int right = 6; + auto buttonsSize = NSMakeRect(0, + 0, + left + closeButton.frame.size.width + between + minitButton.frame.size.width + between + fullScreenButton.frame.size.width + right, + top + closeButton.frame.size.height + bottom); + // NSView* buttons = [[SemaphoreView alloc] initWithFrame:buttonsSize]; + [self setFrame:buttonsSize]; + + //set their location + [closeButton setFrame:NSMakeRect(7, + buttonsSize.size.height - closeButton.frame.size.height - 3, + closeButton.frame.size.width, + closeButton.frame.size.height)]; + [minitButton setFrame:NSMakeRect(7 + closeButton.frame.size.width + 6, + buttonsSize.size.height - minitButton.frame.size.height - 3, + minitButton.frame.size.width, + minitButton.frame.size.height)]; + [fullScreenButton setFrame:NSMakeRect(7 + closeButton.frame.size.width + 6 + minitButton.frame.size.width + 6, + buttonsSize.size.height - fullScreenButton.frame.size.height - 3, + fullScreenButton.frame.size.width, + fullScreenButton.frame.size.height)]; + + //add buttons to the window + [self addSubview:closeButton]; + [self addSubview:minitButton]; + [self addSubview:fullScreenButton]; + + // stay in upper left corner + [self setAutoresizingMask: NSViewMaxXMargin | NSViewMinYMargin]; + + // refresh for initial conditions + [self setNeedsDisplayForButtons]; + } + return self; +} + +- (BOOL)_mouseInGroup:(NSButton *)button { + return mouseInside; +} + +- (void)updateTrackingAreas { + NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil]; + [self addTrackingArea:trackingArea]; +} + +- (void)mouseEntered:(NSEvent *)event { + [super mouseEntered:event]; + mouseInside = YES; + [self setNeedsDisplayForButtons]; +} + +- (void)mouseExited:(NSEvent *)event { + [super mouseExited:event]; + mouseInside = NO; + [self setNeedsDisplayForButtons]; +} + +- (void)setNeedsDisplayForButtons { + for (NSView *subview in self.subviews) { + [subview setHidden:!mouseInside]; + [subview setNeedsDisplay:YES]; + } +} + +@end + // This view always takes the size of its superview. It is intended to be used // as a NSWindow's contentView. It is needed because NSWindow's implementation // explicitly resizes the contentView at inopportune times. @@ -596,6 +685,28 @@ enum { [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil]; } +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + return ([menuItem action] == @selector(performClose:) || [menuItem action] == @selector(performMiniaturize:)) ? YES : [super validateMenuItem:menuItem]; +} + +- (BOOL)windowShouldClose:(id)sender { + return YES; +} + +- (void)performClose:(id)sender { + if([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) { + if(![[self delegate] windowShouldClose:self]) return; + } + else if([self respondsToSelector:@selector(windowShouldClose:)]) { + if(![self windowShouldClose:self]) return; + } + [self close]; +} + +- (void)performMiniaturize:(id)sender { + [self miniaturize:self]; +} + @end @interface ControlRegionView : NSView @@ -725,7 +836,7 @@ NativeWindowMac::NativeWindowMac( useStandardWindow = false; } - NSUInteger styleMask = NSTitledWindowMask; + NSUInteger styleMask = (base::mac::IsAtLeastOS10_10() && (!useStandardWindow || transparent() || !has_frame()))? NSFullSizeContentViewWindowMask : NSTitledWindowMask; if (minimizable) { styleMask |= NSMiniaturizableWindowMask; } @@ -780,6 +891,7 @@ NativeWindowMac::NativeWindowMac( if (transparent() || !has_frame()) { if (base::mac::IsAtLeastOS10_10()) { // Don't show title bar. + [window_ setTitlebarAppearsTransparent:YES]; [window_ setTitleVisibility:NSWindowTitleHidden]; } // Remove non-transparent corners, see http://git.io/vfonD. @@ -1530,10 +1642,10 @@ void NativeWindowMac::UpdateDraggableRegions( UpdateDraggableRegionViews(regions); } -void NativeWindowMac::ShowWindowButton(NSWindowButton button) { - auto view = [window_ standardWindowButton:button]; - [view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil]; -} +// void NativeWindowMac::ShowWindowButton(NSWindowButton button) { +// auto view = [window_ standardWindowButton:button]; +// [view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil]; +// } void NativeWindowMac::InstallView() { // Make sure the bottom corner is rounded for non-modal windows: http://crbug.com/396264. @@ -1560,28 +1672,19 @@ void NativeWindowMac::InstallView() { [view setFrame:[content_view_ bounds]]; [content_view_ addSubview:view]; + // add semaphore + NSView* buttons = [[SemaphoreView alloc] initWithFrame:NSZeroRect]; + buttons.frame = CGRectMake(0, [content_view_ bounds].size.height - buttons.frame.size.height, buttons.frame.size.width, buttons.frame.size.height); + [content_view_ addSubview:buttons]; + // The fullscreen button should always be hidden for frameless window. [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES]; - if (title_bar_style_ != NORMAL) { - if (base::mac::IsOS10_9()) { - ShowWindowButton(NSWindowZoomButton); - ShowWindowButton(NSWindowMiniaturizeButton); - ShowWindowButton(NSWindowCloseButton); - } - - return; - } - - // Hide the window buttons. - [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; - [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; - [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; - // Some third-party macOS utilities check the zoom button's enabled state to // determine whether to show custom UI on hover, so we disable it here to // prevent them from doing so in a frameless app window. [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO]; + } } From 96251e55decbceb0b1a0057892f5e00fecc90c46 Mon Sep 17 00:00:00 2001 From: mst128256 Date: Fri, 17 Mar 2017 21:55:56 +0100 Subject: [PATCH 02/16] Removed commented code --- atom/browser/native_window_mac.mm | 6 ------ 1 file changed, 6 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index be5d754a246..4cd8d1d2b01 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1642,11 +1642,6 @@ void NativeWindowMac::UpdateDraggableRegions( UpdateDraggableRegionViews(regions); } -// void NativeWindowMac::ShowWindowButton(NSWindowButton button) { -// auto view = [window_ standardWindowButton:button]; -// [view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil]; -// } - void NativeWindowMac::InstallView() { // Make sure the bottom corner is rounded for non-modal windows: http://crbug.com/396264. // But do not enable it on OS X 10.9 for transparent window, otherwise a @@ -1684,7 +1679,6 @@ void NativeWindowMac::InstallView() { // determine whether to show custom UI on hover, so we disable it here to // prevent them from doing so in a frameless app window. [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO]; - } } From 2880cfdc9c8a6877a0657c5f227d46fab412645b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 11:08:05 -0700 Subject: [PATCH 03/16] :art: Minor formatting tweaks --- atom/browser/native_window_mac.mm | 147 ++++++++++++++++-------------- 1 file changed, 79 insertions(+), 68 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 4cd8d1d2b01..940ce89fb01 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -56,81 +56,91 @@ bool ScopedDisableResize::disable_resize_ = false; BOOL mouseInside = NO; - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; - if (self) { + self = [super initWithFrame:frame]; - // create buttons - NSButton *closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSTitledWindowMask]; - NSButton *minitButton = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSTitledWindowMask]; - NSButton *fullScreenButton = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSTitledWindowMask]; + if (self) { + // create buttons + NSButton* closeButton = [NSWindow standardWindowButton:NSWindowCloseButton + forStyleMask:NSTitledWindowMask]; + NSButton* minitButton = [NSWindow standardWindowButton:NSWindowMiniaturizeButton + forStyleMask:NSTitledWindowMask]; + NSButton* fullScreenButton = [NSWindow standardWindowButton:NSWindowZoomButton + forStyleMask:NSTitledWindowMask]; - // size view for buttons - const int top = 3; - const int bottom = 3; - const int left = 7; - const int between = 6; - const int right = 6; - auto buttonsSize = NSMakeRect(0, - 0, - left + closeButton.frame.size.width + between + minitButton.frame.size.width + between + fullScreenButton.frame.size.width + right, - top + closeButton.frame.size.height + bottom); - // NSView* buttons = [[SemaphoreView alloc] initWithFrame:buttonsSize]; - [self setFrame:buttonsSize]; + // size view for buttons + const int top = 3; + const int bottom = 3; + const int left = 7; + const int between = 6; + const int right = 6; - //set their location - [closeButton setFrame:NSMakeRect(7, - buttonsSize.size.height - closeButton.frame.size.height - 3, - closeButton.frame.size.width, - closeButton.frame.size.height)]; - [minitButton setFrame:NSMakeRect(7 + closeButton.frame.size.width + 6, - buttonsSize.size.height - minitButton.frame.size.height - 3, - minitButton.frame.size.width, - minitButton.frame.size.height)]; - [fullScreenButton setFrame:NSMakeRect(7 + closeButton.frame.size.width + 6 + minitButton.frame.size.width + 6, - buttonsSize.size.height - fullScreenButton.frame.size.height - 3, - fullScreenButton.frame.size.width, - fullScreenButton.frame.size.height)]; + auto buttonsSize = NSMakeRect(0, + 0, + left + closeButton.frame.size.width + between + minitButton.frame.size.width + between + fullScreenButton.frame.size.width + right, + top + closeButton.frame.size.height + bottom); + [self setFrame:buttonsSize]; - //add buttons to the window - [self addSubview:closeButton]; - [self addSubview:minitButton]; - [self addSubview:fullScreenButton]; + //set their location + [closeButton setFrame:NSMakeRect(left, + buttonsSize.size.height - closeButton.frame.size.height - top, + closeButton.frame.size.width, + closeButton.frame.size.height)]; + [minitButton setFrame:NSMakeRect( + left + closeButton.frame.size.width + between, + buttonsSize.size.height - minitButton.frame.size.height - top, + minitButton.frame.size.width, + minitButton.frame.size.height)]; + [fullScreenButton setFrame:NSMakeRect( + left + closeButton.frame.size.width + between + minitButton.frame.size.width + between, + buttonsSize.size.height - fullScreenButton.frame.size.height - top, + fullScreenButton.frame.size.width, + fullScreenButton.frame.size.height)]; - // stay in upper left corner - [self setAutoresizingMask: NSViewMaxXMargin | NSViewMinYMargin]; + //add buttons to the window + [self addSubview:closeButton]; + [self addSubview:minitButton]; + [self addSubview:fullScreenButton]; - // refresh for initial conditions - [self setNeedsDisplayForButtons]; - } - return self; + // stay in upper left corner + [self setAutoresizingMask: NSViewMaxXMargin | NSViewMinYMargin]; + + // refresh for initial conditions + [self setNeedsDisplayForButtons]; + } + + return self; } -- (BOOL)_mouseInGroup:(NSButton *)button { - return mouseInside; +- (BOOL)_mouseInGroup:(NSButton*)button { + return mouseInside; } - (void)updateTrackingAreas { - NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil]; - [self addTrackingArea:trackingArea]; + NSTrackingArea* const trackingArea = + [[NSTrackingArea alloc] initWithRect:NSZeroRect + options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea]; } -- (void)mouseEntered:(NSEvent *)event { - [super mouseEntered:event]; - mouseInside = YES; - [self setNeedsDisplayForButtons]; +- (void)mouseEntered:(NSEvent*)event { + [super mouseEntered:event]; + mouseInside = YES; + [self setNeedsDisplayForButtons]; } -- (void)mouseExited:(NSEvent *)event { - [super mouseExited:event]; - mouseInside = NO; - [self setNeedsDisplayForButtons]; +- (void)mouseExited:(NSEvent*)event { + [super mouseExited:event]; + mouseInside = NO; + [self setNeedsDisplayForButtons]; } - (void)setNeedsDisplayForButtons { - for (NSView *subview in self.subviews) { - [subview setHidden:!mouseInside]; - [subview setNeedsDisplay:YES]; - } + for (NSView* subview in self.subviews) { + [subview setHidden:!mouseInside]; + [subview setNeedsDisplay:YES]; + } } @end @@ -685,26 +695,27 @@ enum { [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil]; } -- (BOOL)validateMenuItem:(NSMenuItem *)menuItem { - return ([menuItem action] == @selector(performClose:) || [menuItem action] == @selector(performMiniaturize:)) ? YES : [super validateMenuItem:menuItem]; +// Custom window button methods + +- (BOOL)validateMenuItem:(NSMenuItem*)menuItem { + return ([menuItem action] == @selector(performClose:) || [menuItem action] == @selector(performMiniaturize:)) ? YES : [super validateMenuItem:menuItem]; } - (BOOL)windowShouldClose:(id)sender { - return YES; + return YES; } - (void)performClose:(id)sender { - if([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) { - if(![[self delegate] windowShouldClose:self]) return; - } - else if([self respondsToSelector:@selector(windowShouldClose:)]) { - if(![self windowShouldClose:self]) return; - } - [self close]; + if ([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) { + if (![[self delegate] windowShouldClose:self]) return; + } else if ([self respondsToSelector:@selector(windowShouldClose:)]) { + if (![self windowShouldClose:self]) return; + } + [self close]; } - (void)performMiniaturize:(id)sender { - [self miniaturize:self]; + [self miniaturize:self]; } @end From 1493d6763c2d0522c79344f5279e12196e5a9bf0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 12:50:18 -0700 Subject: [PATCH 04/16] Make custom window buttons an option --- atom/browser/native_window_mac.h | 4 ++ atom/browser/native_window_mac.mm | 75 ++++++++++++++++++++++--------- atom/common/options_switches.cc | 3 ++ atom/common/options_switches.h | 1 + 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index b5271e4d436..161ba5bbc0a 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -132,6 +132,8 @@ class NativeWindowMac : public NativeWindow, bool zoom_to_page_width() const { return zoom_to_page_width_; } + bool custom_window_buttons() const { return custom_window_buttons_; } + protected: // Return a vector of non-draggable regions that fill a window of size // |width| by |height|, but leave gaps where the window should be draggable. @@ -176,6 +178,8 @@ class NativeWindowMac : public NativeWindow, bool zoom_to_page_width_; + bool custom_window_buttons_; + NSInteger attention_request_id_; // identifier from requestUserAttention // The presentation options before entering kiosk mode. diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 940ce89fb01..1ffe708a8a5 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -398,7 +398,7 @@ BOOL mouseInside = NO; - (BOOL)windowShouldClose:(id)window { // When user tries to close the window by clicking the close button, we do // not close the window immediately, instead we try to close the web page - // fisrt, and when the web page is closed the window will also be closed. + // first, and when the web page is closed the window will also be closed. shell_->RequestToClosePage(); return NO; } @@ -697,25 +697,22 @@ enum { // Custom window button methods -- (BOOL)validateMenuItem:(NSMenuItem*)menuItem { - return ([menuItem action] == @selector(performClose:) || [menuItem action] == @selector(performMiniaturize:)) ? YES : [super validateMenuItem:menuItem]; -} - -- (BOOL)windowShouldClose:(id)sender { - return YES; -} - - (void)performClose:(id)sender { - if ([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) { - if (![[self delegate] windowShouldClose:self]) return; - } else if ([self respondsToSelector:@selector(windowShouldClose:)]) { - if (![self windowShouldClose:self]) return; + if (shell_->custom_window_buttons()) { + [[self delegate] windowShouldClose:self]; + return; } - [self close]; + + [super performClose:sender]; } - (void)performMiniaturize:(id)sender { - [self miniaturize:self]; + if (shell_->custom_window_buttons()) { + [self miniaturize:self]; + return; + } + + [super performMiniaturize:sender]; } @end @@ -806,6 +803,7 @@ NativeWindowMac::NativeWindowMac( is_kiosk_(false), was_fullscreen_(false), zoom_to_page_width_(false), + custom_window_buttons_(false), attention_request_id_(0), title_bar_style_(NORMAL) { int width = 800, height = 600; @@ -847,7 +845,15 @@ NativeWindowMac::NativeWindowMac( useStandardWindow = false; } - NSUInteger styleMask = (base::mac::IsAtLeastOS10_10() && (!useStandardWindow || transparent() || !has_frame()))? NSFullSizeContentViewWindowMask : NSTitledWindowMask; + options.Get(options::kCustomWindowButtons, &custom_window_buttons_); + + NSUInteger styleMask = NSTitledWindowMask; + + if (custom_window_buttons_ && + base::mac::IsAtLeastOS10_10() && + (!useStandardWindow || transparent() || !has_frame())) { + styleMask = NSFullSizeContentViewWindowMask; + } if (minimizable) { styleMask |= NSMiniaturizableWindowMask; } @@ -902,7 +908,9 @@ NativeWindowMac::NativeWindowMac( if (transparent() || !has_frame()) { if (base::mac::IsAtLeastOS10_10()) { // Don't show title bar. - [window_ setTitlebarAppearsTransparent:YES]; + if (custom_window_buttons_) { + [window_ setTitlebarAppearsTransparent:YES]; + } [window_ setTitleVisibility:NSWindowTitleHidden]; } // Remove non-transparent corners, see http://git.io/vfonD. @@ -1653,6 +1661,11 @@ void NativeWindowMac::UpdateDraggableRegions( UpdateDraggableRegionViews(regions); } +void NativeWindowMac::ShowWindowButton(NSWindowButton button) { + auto view = [window_ standardWindowButton:button]; + [view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil]; +} + void NativeWindowMac::InstallView() { // Make sure the bottom corner is rounded for non-modal windows: http://crbug.com/396264. // But do not enable it on OS X 10.9 for transparent window, otherwise a @@ -1678,14 +1691,32 @@ void NativeWindowMac::InstallView() { [view setFrame:[content_view_ bounds]]; [content_view_ addSubview:view]; - // add semaphore - NSView* buttons = [[SemaphoreView alloc] initWithFrame:NSZeroRect]; - buttons.frame = CGRectMake(0, [content_view_ bounds].size.height - buttons.frame.size.height, buttons.frame.size.width, buttons.frame.size.height); - [content_view_ addSubview:buttons]; - // The fullscreen button should always be hidden for frameless window. [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES]; + if (custom_window_buttons_) { + NSView* buttons = [[SemaphoreView alloc] initWithFrame:NSZeroRect]; + buttons.frame = CGRectMake(0, + [content_view_ bounds].size.height - buttons.frame.size.height, + buttons.frame.size.width, + buttons.frame.size.height); + [content_view_ addSubview:buttons]; + } else { + if (title_bar_style_ != NORMAL) { + if (base::mac::IsOS10_9()) { + ShowWindowButton(NSWindowZoomButton); + ShowWindowButton(NSWindowMiniaturizeButton); + ShowWindowButton(NSWindowCloseButton); + } + return; + } + + // Hide the window buttons. + [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; + [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; + [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; + } + // Some third-party macOS utilities check the zoom button's enabled state to // determine whether to show custom UI on hover, so we disable it here to // prevent them from doing so in a frameless app window. diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index ce63fc716a3..30593cee24f 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -90,6 +90,9 @@ const char kWebPreferences[] = "webPreferences"; // Add a vibrancy effect to the browser window const char kVibrancyType[] = "vibrancy"; +// Use custom buttons for window close, minimize, maximize on macOS +const char kCustomWindowButtons[] = "customWindowButtons"; + // The factor of which page should be zoomed. const char kZoomFactor[] = "zoomFactor"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 6fda408ee5c..33db0077205 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -49,6 +49,7 @@ extern const char kHasShadow[]; extern const char kFocusable[]; extern const char kWebPreferences[]; extern const char kVibrancyType[]; +extern const char kCustomWindowButtons[]; // WebPreferences. extern const char kZoomFactor[]; From 37ba1b0a6be5d8607b4b0693f0319a4654d4f8ee Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 12:55:39 -0700 Subject: [PATCH 05/16] Declare mouse inside variable in interface --- atom/browser/native_window_mac.mm | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 1ffe708a8a5..7763098e778 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -46,19 +46,22 @@ bool ScopedDisableResize::disable_resize_ = false; } // namespace -// This view encapsuate Quit, Minimize and Full Screen buttons. It is being -// used for frameless window. -@interface SemaphoreView : NSView +// This view encapsuates the Quit, Minimize and Full Screen buttons. It is being +// used for frameless windows. +@interface SemaphoreView : NSView { + @private + BOOL mouse_inside_; +} @end @implementation SemaphoreView -BOOL mouseInside = NO; - - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { + mouse_inside_ = NO; + // create buttons NSButton* closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSTitledWindowMask]; @@ -112,7 +115,7 @@ BOOL mouseInside = NO; } - (BOOL)_mouseInGroup:(NSButton*)button { - return mouseInside; + return mouse_inside_; } - (void)updateTrackingAreas { @@ -126,19 +129,19 @@ BOOL mouseInside = NO; - (void)mouseEntered:(NSEvent*)event { [super mouseEntered:event]; - mouseInside = YES; + mouse_inside_ = YES; [self setNeedsDisplayForButtons]; } - (void)mouseExited:(NSEvent*)event { [super mouseExited:event]; - mouseInside = NO; + mouse_inside_ = NO; [self setNeedsDisplayForButtons]; } - (void)setNeedsDisplayForButtons { for (NSView* subview in self.subviews) { - [subview setHidden:!mouseInside]; + [subview setHidden:!mouse_inside_]; [subview setNeedsDisplay:YES]; } } From 410e5bce60bff204203d99da534f58d36b24497e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 13:04:17 -0700 Subject: [PATCH 06/16] Document customWindowButtons option --- docs/api/browser-window.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index cb709c7a0c7..977ec783d7a 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -214,6 +214,11 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `tabbingIdentifier` String (optional) - Tab group name, allows opening the window as a native tab on macOS 10.12+. Windows with the same tabbing identifier will be grouped together. + * `customWindowButtons` Boolean (optional) - Draw custom close, minimize, + and full screen buttons on macOS frameless windows. These buttons will not + display unless hovered over in the top left of the window. These custom + buttons prevent issues with mouse events that occur with the standard + window toolbar buttons. **Note:** This option is currently experimental. * `webPreferences` Object (optional) - Settings of web page's features. * `devTools` Boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. * `nodeIntegration` Boolean (optional) - Whether node integration is enabled. Default From 566e04f1c0fee47f35fcf3e9169c87c416ba5785 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 13:13:16 -0700 Subject: [PATCH 07/16] :art: --- atom/browser/native_window_mac.mm | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 7763098e778..6000b175cbc 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -701,21 +701,17 @@ enum { // Custom window button methods - (void)performClose:(id)sender { - if (shell_->custom_window_buttons()) { + if (shell_->custom_window_buttons()) [[self delegate] windowShouldClose:self]; - return; - } - - [super performClose:sender]; + else + [super performClose:sender]; } - (void)performMiniaturize:(id)sender { - if (shell_->custom_window_buttons()) { + if (shell_->custom_window_buttons()) [self miniaturize:self]; - return; - } - - [super performMiniaturize:sender]; + else + [super performMiniaturize:sender]; } @end @@ -851,7 +847,6 @@ NativeWindowMac::NativeWindowMac( options.Get(options::kCustomWindowButtons, &custom_window_buttons_); NSUInteger styleMask = NSTitledWindowMask; - if (custom_window_buttons_ && base::mac::IsAtLeastOS10_10() && (!useStandardWindow || transparent() || !has_frame())) { From 7d10bf229ddafd208ace633dbcd4f9d4b1c295a5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 13:30:08 -0700 Subject: [PATCH 08/16] Switch to titleBarStyle for custom window buttons on hover --- atom/browser/native_window_mac.h | 5 +---- atom/browser/native_window_mac.mm | 15 +++++++-------- docs/api/browser-window.md | 15 ++++++++------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 161ba5bbc0a..e3c5525b849 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -127,13 +127,12 @@ class NativeWindowMac : public NativeWindow, NORMAL, HIDDEN, HIDDEN_INSET, + CUSTOM_BUTTONS_ON_HOVER, }; TitleBarStyle title_bar_style() const { return title_bar_style_; } bool zoom_to_page_width() const { return zoom_to_page_width_; } - bool custom_window_buttons() const { return custom_window_buttons_; } - protected: // Return a vector of non-draggable regions that fill a window of size // |width| by |height|, but leave gaps where the window should be draggable. @@ -178,8 +177,6 @@ class NativeWindowMac : public NativeWindow, bool zoom_to_page_width_; - bool custom_window_buttons_; - NSInteger attention_request_id_; // identifier from requestUserAttention // The presentation options before entering kiosk mode. diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 6000b175cbc..796a40f356c 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -701,14 +701,14 @@ enum { // Custom window button methods - (void)performClose:(id)sender { - if (shell_->custom_window_buttons()) + if (shell_->title_bar_style() == atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER) [[self delegate] windowShouldClose:self]; else [super performClose:sender]; } - (void)performMiniaturize:(id)sender { - if (shell_->custom_window_buttons()) + if (shell_->title_bar_style() == atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER) [self miniaturize:self]; else [super performMiniaturize:sender]; @@ -782,6 +782,8 @@ struct Converter { } else if (title_bar_style == "hidden-inset" || // Deprecate this after 2.0 title_bar_style == "hiddenInset") { *out = atom::NativeWindowMac::HIDDEN_INSET; + } else if (title_bar_style == "customButtonsOnHover") { + *out = atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER; } else { return false; } @@ -802,7 +804,6 @@ NativeWindowMac::NativeWindowMac( is_kiosk_(false), was_fullscreen_(false), zoom_to_page_width_(false), - custom_window_buttons_(false), attention_request_id_(0), title_bar_style_(NORMAL) { int width = 800, height = 600; @@ -844,10 +845,8 @@ NativeWindowMac::NativeWindowMac( useStandardWindow = false; } - options.Get(options::kCustomWindowButtons, &custom_window_buttons_); - NSUInteger styleMask = NSTitledWindowMask; - if (custom_window_buttons_ && + if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER && base::mac::IsAtLeastOS10_10() && (!useStandardWindow || transparent() || !has_frame())) { styleMask = NSFullSizeContentViewWindowMask; @@ -906,7 +905,7 @@ NativeWindowMac::NativeWindowMac( if (transparent() || !has_frame()) { if (base::mac::IsAtLeastOS10_10()) { // Don't show title bar. - if (custom_window_buttons_) { + if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) { [window_ setTitlebarAppearsTransparent:YES]; } [window_ setTitleVisibility:NSWindowTitleHidden]; @@ -1692,7 +1691,7 @@ void NativeWindowMac::InstallView() { // The fullscreen button should always be hidden for frameless window. [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES]; - if (custom_window_buttons_) { + if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) { NSView* buttons = [[SemaphoreView alloc] initWithFrame:NSZeroRect]; buttons.frame = CGRectMake(0, [content_view_ bounds].size.height - buttons.frame.size.height, diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 977ec783d7a..83b4a338310 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -191,14 +191,20 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. Default is `false`. * `type` String (optional) - The type of window, default is normal window. See more about this below. - * `titleBarStyle` String (optional) - The style of window title bar. Default is `default`. Possible values are: + * `titleBarStyle` String (optional) - The style of window title bar. + Default is `default`. Possible values are: * `default` - Results in the standard gray opaque Mac title bar. * `hidden` - Results in a hidden title bar and a full size content window, yet the title bar still has the standard window controls ("traffic lights") in the top left. - * `hidden-inset` - Results in a hidden title bar with an alternative look + * `hiddenInset` - Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge. + * `customButtonsOnHover` Boolean (optional) - Draw custom close, minimize, + and full screen buttons on macOS frameless windows. These buttons will not + display unless hovered over in the top left of the window. These custom + buttons prevent issues with mouse events that occur with the standard + window toolbar buttons. **Note:** This option is currently experimental. * `thickFrame` Boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on Windows, which adds standard window frame. Setting it to `false` will remove window shadow and window animations. Default is `true`. @@ -214,11 +220,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `tabbingIdentifier` String (optional) - Tab group name, allows opening the window as a native tab on macOS 10.12+. Windows with the same tabbing identifier will be grouped together. - * `customWindowButtons` Boolean (optional) - Draw custom close, minimize, - and full screen buttons on macOS frameless windows. These buttons will not - display unless hovered over in the top left of the window. These custom - buttons prevent issues with mouse events that occur with the standard - window toolbar buttons. **Note:** This option is currently experimental. * `webPreferences` Object (optional) - Settings of web page's features. * `devTools` Boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. * `nodeIntegration` Boolean (optional) - Whether node integration is enabled. Default From de0daa24819217dca35ec30c01c320531b37687b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 13:48:30 -0700 Subject: [PATCH 09/16] Autorelease tracking area --- atom/browser/native_window_mac.mm | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 796a40f356c..3bfacda6d32 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -119,11 +119,10 @@ bool ScopedDisableResize::disable_resize_ = false; } - (void)updateTrackingAreas { - NSTrackingArea* const trackingArea = - [[NSTrackingArea alloc] initWithRect:NSZeroRect - options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect - owner:self - userInfo:nil]; + auto trackingArea = [[[NSTrackingArea alloc] initWithRect:NSZeroRect + options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect + owner:self + userInfo:nil] autorelease]; [self addTrackingArea:trackingArea]; } From 9537303e9ad13651b2a833a04fdc25a7382860bb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 13:57:18 -0700 Subject: [PATCH 10/16] Remove unused customWindowButtons switch --- atom/common/options_switches.cc | 3 --- atom/common/options_switches.h | 1 - 2 files changed, 4 deletions(-) diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 30593cee24f..ce63fc716a3 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -90,9 +90,6 @@ const char kWebPreferences[] = "webPreferences"; // Add a vibrancy effect to the browser window const char kVibrancyType[] = "vibrancy"; -// Use custom buttons for window close, minimize, maximize on macOS -const char kCustomWindowButtons[] = "customWindowButtons"; - // The factor of which page should be zoomed. const char kZoomFactor[] = "zoomFactor"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 33db0077205..6fda408ee5c 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -49,7 +49,6 @@ extern const char kHasShadow[]; extern const char kFocusable[]; extern const char kWebPreferences[]; extern const char kVibrancyType[]; -extern const char kCustomWindowButtons[]; // WebPreferences. extern const char kZoomFactor[]; From 3a2abde804684cff183371635c37c7275c7dcebf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 13:58:50 -0700 Subject: [PATCH 11/16] Add TODO for hidden-inset deprecation --- atom/browser/native_window_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 3bfacda6d32..6a323e1cd1a 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -778,7 +778,7 @@ struct Converter { return false; if (title_bar_style == "hidden") { *out = atom::NativeWindowMac::HIDDEN; - } else if (title_bar_style == "hidden-inset" || // Deprecate this after 2.0 + } else if (title_bar_style == "hidden-inset" || // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings title_bar_style == "hiddenInset") { *out = atom::NativeWindowMac::HIDDEN_INSET; } else if (title_bar_style == "customButtonsOnHover") { From 594302fcff2311c95a576bd6ac432987aadbcb1e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 14:07:57 -0700 Subject: [PATCH 12/16] Update docs to use hiddenInset --- docs/api/frameless-window.md | 6 +++--- docs/api/touch-bar.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index 4f091ec6c3c..0bab1e55e3f 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -26,7 +26,7 @@ a chromeless window. Instead of setting `frame` to `false` which disables both the titlebar and window controls, you may want to have the title bar hidden and your content extend to the full window size, yet still preserve the window controls ("traffic lights") for standard window actions. -You can do so by specifying the new `titleBarStyle` option: +You can do so by specifying the `titleBarStyle` option: #### `hidden` @@ -38,13 +38,13 @@ let win = new BrowserWindow({titleBarStyle: 'hidden'}) win.show() ``` -#### `hidden-inset` +#### `hiddenInset` Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge. ```javascript const {BrowserWindow} = require('electron') -let win = new BrowserWindow({titleBarStyle: 'hidden-inset'}) +let win = new BrowserWindow({titleBarStyle: 'hiddenInset'}) win.show() ``` diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 8f1b8732f8b..914c22086a5 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -129,7 +129,7 @@ let window app.once('ready', () => { window = new BrowserWindow({ frame: false, - titleBarStyle: 'hidden-inset', + titleBarStyle: 'hiddenInset', width: 200, height: 200, backgroundColor: '#000' From 41d582f689acf13daa6619af42545ec935078f28 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 14:16:23 -0700 Subject: [PATCH 13/16] Add back hidden-inset as a deprecated option --- docs/api/browser-window.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 83b4a338310..69407ec2a71 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -198,6 +198,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `hidden` - Results in a hidden title bar and a full size content window, yet the title bar still has the standard window controls ("traffic lights") in the top left. + * `hidden-inset` - Deprecated, use `hiddenInset` instead. * `hiddenInset` - Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge. * `customButtonsOnHover` Boolean (optional) - Draw custom close, minimize, From d5dc849c7abf768bd8bee69f642ffafcd7a5aed4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 14:16:44 -0700 Subject: [PATCH 14/16] Doc customButtonsOnHover in frameless window guide --- docs/api/frameless-window.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index 0bab1e55e3f..6d66a6f6c6c 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -48,6 +48,18 @@ let win = new BrowserWindow({titleBarStyle: 'hiddenInset'}) win.show() ``` +#### `customButtonsOnHover` + +Uses custom drawn close, miniaturize, and fullscreen buttons that display +when hovering in the top left of the window. These custom buttons prevent issues +with mouse events that occur with the standard window toolbar buttons. + +```javascript +const {BrowserWindow} = require('electron') +let win = new BrowserWindow({titleBarStyle: 'customButtonsOnHover', frame: false}) +win.show() +``` + ## Transparent window By setting the `transparent` option to `true`, you can also make the frameless From 1adc94b650f3f05fcc6fda2dd57eec3e55b77fe5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 14:18:08 -0700 Subject: [PATCH 15/16] Mention customButtonsOnHover is for frameless windows --- docs/api/frameless-window.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index 6d66a6f6c6c..1ae02935225 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -52,7 +52,8 @@ win.show() Uses custom drawn close, miniaturize, and fullscreen buttons that display when hovering in the top left of the window. These custom buttons prevent issues -with mouse events that occur with the standard window toolbar buttons. +with mouse events that occur with the standard window toolbar buttons. This +option is only applicable for frameless windows. ```javascript const {BrowserWindow} = require('electron') From 4989b21dbca8d77f902c02065f917254f15e7a53 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 5 Jun 2017 14:28:58 -0700 Subject: [PATCH 16/16] Autorelease semaphore view --- atom/browser/native_window_mac.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 6a323e1cd1a..e4efaa477b3 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1691,7 +1691,8 @@ void NativeWindowMac::InstallView() { [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES]; if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) { - NSView* buttons = [[SemaphoreView alloc] initWithFrame:NSZeroRect]; + NSView* buttons = + [[[SemaphoreView alloc] initWithFrame:NSZeroRect] autorelease]; buttons.frame = CGRectMake(0, [content_view_ bounds].size.height - buttons.frame.size.height, buttons.frame.size.width,