Merge pull request #8958 from mst128256/8730
Area near the top border in frameless window is clickable
This commit is contained in:
commit
dfa4af2210
5 changed files with 176 additions and 19 deletions
|
@ -127,6 +127,7 @@ class NativeWindowMac : public NativeWindow,
|
||||||
NORMAL,
|
NORMAL,
|
||||||
HIDDEN,
|
HIDDEN,
|
||||||
HIDDEN_INSET,
|
HIDDEN_INSET,
|
||||||
|
CUSTOM_BUTTONS_ON_HOVER,
|
||||||
};
|
};
|
||||||
TitleBarStyle title_bar_style() const { return title_bar_style_; }
|
TitleBarStyle title_bar_style() const { return title_bar_style_; }
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,107 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
- (id)initWithFrame:(NSRect)frame {
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
|
||||||
|
if (self) {
|
||||||
|
mouse_inside_ = NO;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
[self setFrame:buttonsSize];
|
||||||
|
|
||||||
|
//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)];
|
||||||
|
|
||||||
|
//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 mouse_inside_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateTrackingAreas {
|
||||||
|
auto trackingArea = [[[NSTrackingArea alloc] initWithRect:NSZeroRect
|
||||||
|
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect
|
||||||
|
owner:self
|
||||||
|
userInfo:nil] autorelease];
|
||||||
|
[self addTrackingArea:trackingArea];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseEntered:(NSEvent*)event {
|
||||||
|
[super mouseEntered:event];
|
||||||
|
mouse_inside_ = YES;
|
||||||
|
[self setNeedsDisplayForButtons];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseExited:(NSEvent*)event {
|
||||||
|
[super mouseExited:event];
|
||||||
|
mouse_inside_ = NO;
|
||||||
|
[self setNeedsDisplayForButtons];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setNeedsDisplayForButtons {
|
||||||
|
for (NSView* subview in self.subviews) {
|
||||||
|
[subview setHidden:!mouse_inside_];
|
||||||
|
[subview setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
// This view always takes the size of its superview. It is intended to be used
|
// 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
|
// as a NSWindow's contentView. It is needed because NSWindow's implementation
|
||||||
// explicitly resizes the contentView at inopportune times.
|
// explicitly resizes the contentView at inopportune times.
|
||||||
|
@ -299,7 +400,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||||
- (BOOL)windowShouldClose:(id)window {
|
- (BOOL)windowShouldClose:(id)window {
|
||||||
// When user tries to close the window by clicking the close button, we do
|
// 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
|
// 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();
|
shell_->RequestToClosePage();
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
@ -596,6 +697,22 @@ enum {
|
||||||
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
|
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom window button methods
|
||||||
|
|
||||||
|
- (void)performClose:(id)sender {
|
||||||
|
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_->title_bar_style() == atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER)
|
||||||
|
[self miniaturize:self];
|
||||||
|
else
|
||||||
|
[super performMiniaturize:sender];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface ControlRegionView : NSView
|
@interface ControlRegionView : NSView
|
||||||
|
@ -661,9 +778,11 @@ struct Converter<atom::NativeWindowMac::TitleBarStyle> {
|
||||||
return false;
|
return false;
|
||||||
if (title_bar_style == "hidden") {
|
if (title_bar_style == "hidden") {
|
||||||
*out = atom::NativeWindowMac::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") {
|
title_bar_style == "hiddenInset") {
|
||||||
*out = atom::NativeWindowMac::HIDDEN_INSET;
|
*out = atom::NativeWindowMac::HIDDEN_INSET;
|
||||||
|
} else if (title_bar_style == "customButtonsOnHover") {
|
||||||
|
*out = atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -726,6 +845,11 @@ NativeWindowMac::NativeWindowMac(
|
||||||
}
|
}
|
||||||
|
|
||||||
NSUInteger styleMask = NSTitledWindowMask;
|
NSUInteger styleMask = NSTitledWindowMask;
|
||||||
|
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER &&
|
||||||
|
base::mac::IsAtLeastOS10_10() &&
|
||||||
|
(!useStandardWindow || transparent() || !has_frame())) {
|
||||||
|
styleMask = NSFullSizeContentViewWindowMask;
|
||||||
|
}
|
||||||
if (minimizable) {
|
if (minimizable) {
|
||||||
styleMask |= NSMiniaturizableWindowMask;
|
styleMask |= NSMiniaturizableWindowMask;
|
||||||
}
|
}
|
||||||
|
@ -780,6 +904,9 @@ NativeWindowMac::NativeWindowMac(
|
||||||
if (transparent() || !has_frame()) {
|
if (transparent() || !has_frame()) {
|
||||||
if (base::mac::IsAtLeastOS10_10()) {
|
if (base::mac::IsAtLeastOS10_10()) {
|
||||||
// Don't show title bar.
|
// Don't show title bar.
|
||||||
|
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
|
||||||
|
[window_ setTitlebarAppearsTransparent:YES];
|
||||||
|
}
|
||||||
[window_ setTitleVisibility:NSWindowTitleHidden];
|
[window_ setTitleVisibility:NSWindowTitleHidden];
|
||||||
}
|
}
|
||||||
// Remove non-transparent corners, see http://git.io/vfonD.
|
// Remove non-transparent corners, see http://git.io/vfonD.
|
||||||
|
@ -1563,13 +1690,21 @@ void NativeWindowMac::InstallView() {
|
||||||
// The fullscreen button should always be hidden for frameless window.
|
// The fullscreen button should always be hidden for frameless window.
|
||||||
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
||||||
|
|
||||||
|
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
|
||||||
|
NSView* buttons =
|
||||||
|
[[[SemaphoreView alloc] initWithFrame:NSZeroRect] autorelease];
|
||||||
|
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 (title_bar_style_ != NORMAL) {
|
||||||
if (base::mac::IsOS10_9()) {
|
if (base::mac::IsOS10_9()) {
|
||||||
ShowWindowButton(NSWindowZoomButton);
|
ShowWindowButton(NSWindowZoomButton);
|
||||||
ShowWindowButton(NSWindowMiniaturizeButton);
|
ShowWindowButton(NSWindowMiniaturizeButton);
|
||||||
ShowWindowButton(NSWindowCloseButton);
|
ShowWindowButton(NSWindowCloseButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1577,6 +1712,7 @@ void NativeWindowMac::InstallView() {
|
||||||
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||||
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||||
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||||
|
}
|
||||||
|
|
||||||
// Some third-party macOS utilities check the zoom button's enabled state to
|
// 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
|
// determine whether to show custom UI on hover, so we disable it here to
|
||||||
|
|
|
@ -191,14 +191,21 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||||
Default is `false`.
|
Default is `false`.
|
||||||
* `type` String (optional) - The type of window, default is normal window. See more about
|
* `type` String (optional) - The type of window, default is normal window. See more about
|
||||||
this below.
|
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
|
* `default` - Results in the standard gray opaque Mac title
|
||||||
bar.
|
bar.
|
||||||
* `hidden` - Results in a hidden title bar and a full size content window, yet
|
* `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 title bar still has the standard window controls ("traffic lights") in
|
||||||
the top left.
|
the top left.
|
||||||
* `hidden-inset` - Results in a hidden title bar with an alternative look
|
* `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.
|
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
|
* `thickFrame` Boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on
|
||||||
Windows, which adds standard window frame. Setting it to `false` will remove
|
Windows, which adds standard window frame. Setting it to `false` will remove
|
||||||
window shadow and window animations. Default is `true`.
|
window shadow and window animations. Default is `true`.
|
||||||
|
|
|
@ -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
|
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
|
hidden and your content extend to the full window size, yet still preserve
|
||||||
the window controls ("traffic lights") for standard window actions.
|
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`
|
#### `hidden`
|
||||||
|
|
||||||
|
@ -38,13 +38,26 @@ let win = new BrowserWindow({titleBarStyle: 'hidden'})
|
||||||
win.show()
|
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.
|
Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const {BrowserWindow} = require('electron')
|
const {BrowserWindow} = require('electron')
|
||||||
let win = new BrowserWindow({titleBarStyle: 'hidden-inset'})
|
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. This
|
||||||
|
option is only applicable for frameless windows.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {BrowserWindow} = require('electron')
|
||||||
|
let win = new BrowserWindow({titleBarStyle: 'customButtonsOnHover', frame: false})
|
||||||
win.show()
|
win.show()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ let window
|
||||||
app.once('ready', () => {
|
app.once('ready', () => {
|
||||||
window = new BrowserWindow({
|
window = new BrowserWindow({
|
||||||
frame: false,
|
frame: false,
|
||||||
titleBarStyle: 'hidden-inset',
|
titleBarStyle: 'hiddenInset',
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
backgroundColor: '#000'
|
backgroundColor: '#000'
|
||||||
|
|
Loading…
Reference in a new issue