Skip to content

Commit e01b183

Browse files
authored
feat: make trafficLightPosition work for customButtonOnHover (electron#26789)
1 parent 1e2a200 commit e01b183

File tree

6 files changed

+76
-45
lines changed

6 files changed

+76
-45
lines changed

docs/api/browser-window.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
227227
unless hovered over in the top left of the window. These custom buttons prevent
228228
issues with mouse events that occur with the standard window toolbar buttons.
229229
**Note:** This option is currently experimental.
230-
* `trafficLightPosition` [Point](structures/point.md) (optional) - Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`
230+
* `trafficLightPosition` [Point](structures/point.md) (optional) - Set a
231+
custom position for the traffic light buttons. Can only be used with
232+
`titleBarStyle` set to `hidden` or `customButtonsOnHover`.
231233
* `fullscreenWindowTitle` Boolean (optional) - Shows the title in the
232234
title bar in full screen mode on macOS for all `titleBarStyle` options.
233235
Default is `false`.
@@ -1737,12 +1739,13 @@ deprecated and will be removed in an upcoming version of macOS.
17371739

17381740
* `position` [Point](structures/point.md)
17391741

1740-
Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`.
1742+
Set a custom position for the traffic light buttons. Can only be used with
1743+
`titleBarStyle` set to `hidden` or `customButtonsOnHover`.
17411744

17421745
#### `win.getTrafficLightPosition()` _macOS_
17431746

1744-
Returns `Point` - The current position for the traffic light buttons. Can only be used with `titleBarStyle`
1745-
set to `hidden`.
1747+
Returns `Point` - The current position for the traffic light buttons. Can only
1748+
be used with `titleBarStyle` set to `hidden` or `customButtonsOnHover`.
17461749

17471750
#### `win.setTouchBar(touchBar)` _macOS_
17481751

shell/browser/api/electron_api_base_window.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -842,11 +842,16 @@ void BaseWindow::SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) {
842842

843843
#if defined(OS_MAC)
844844
void BaseWindow::SetTrafficLightPosition(const gfx::Point& position) {
845-
window_->SetTrafficLightPosition(position);
845+
// For backward compatibility we treat (0, 0) as reseting to default.
846+
if (position.IsOrigin())
847+
window_->SetTrafficLightPosition(base::nullopt);
848+
else
849+
window_->SetTrafficLightPosition(position);
846850
}
847851

848852
gfx::Point BaseWindow::GetTrafficLightPosition() const {
849-
return window_->GetTrafficLightPosition();
853+
// For backward compatibility we treat default value as (0, 0).
854+
return window_->GetTrafficLightPosition().value_or(gfx::Point());
850855
}
851856
#endif
852857

shell/browser/native_window.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "base/memory/weak_ptr.h"
1616
#include "base/observer_list.h"
17+
#include "base/optional.h"
1718
#include "base/strings/string16.h"
1819
#include "base/supports_user_data.h"
1920
#include "base/values.h"
@@ -198,8 +199,8 @@ class NativeWindow : public base::SupportsUserData,
198199

199200
// Traffic Light API
200201
#if defined(OS_MAC)
201-
virtual void SetTrafficLightPosition(const gfx::Point& position) = 0;
202-
virtual gfx::Point GetTrafficLightPosition() const = 0;
202+
virtual void SetTrafficLightPosition(base::Optional<gfx::Point> position) = 0;
203+
virtual base::Optional<gfx::Point> GetTrafficLightPosition() const = 0;
203204
virtual void RedrawTrafficLights() = 0;
204205
#endif
205206

shell/browser/native_window_mac.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
159159
// Custom traffic light positioning
160160
void RedrawTrafficLights() override;
161161
void SetExitingFullScreen(bool flag);
162-
void SetTrafficLightPosition(const gfx::Point& position) override;
163-
gfx::Point GetTrafficLightPosition() const override;
162+
void SetTrafficLightPosition(base::Optional<gfx::Point> position) override;
163+
base::Optional<gfx::Point> GetTrafficLightPosition() const override;
164164
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
165165

166166
enum class VisualEffectState {
@@ -220,7 +220,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
220220
bool fullscreen_window_title_ = false;
221221
bool resizable_ = true;
222222
bool exiting_fullscreen_ = false;
223-
gfx::Point traffic_light_position_;
223+
base::Optional<gfx::Point> traffic_light_position_;
224224

225225
NSInteger attention_request_id_ = 0; // identifier from requestUserAttention
226226

shell/browser/native_window_mac.mm

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,18 @@ - (void)viewDidMoveToSuperview {
124124
@interface CustomWindowButtonView : NSView {
125125
@private
126126
BOOL mouse_inside_;
127+
gfx::Point margin_;
127128
}
129+
130+
- (id)initWithMargin:(const base::Optional<gfx::Point>&)margin;
131+
- (void)setMargin:(const base::Optional<gfx::Point>&)margin;
128132
@end
129133

130134
@implementation CustomWindowButtonView
131135

132-
- (id)initWithFrame:(NSRect)frame {
133-
self = [super initWithFrame:frame];
136+
- (id)initWithMargin:(const base::Optional<gfx::Point>&)margin {
137+
self = [super initWithFrame:NSZeroRect];
138+
[self setMargin:margin];
134139

135140
NSButton* close_button =
136141
[NSWindow standardWindowButton:NSWindowCloseButton
@@ -163,18 +168,20 @@ - (id)initWithFrame:(NSRect)frame {
163168
return self;
164169
}
165170

171+
- (void)setMargin:(const base::Optional<gfx::Point>&)margin {
172+
margin_ = margin.value_or(gfx::Point(7, 3));
173+
}
174+
166175
- (void)viewDidMoveToWindow {
167176
if (!self.window) {
168177
return;
169178
}
170179

171180
// Stay in upper left corner.
172-
const CGFloat top_margin = 3;
173-
const CGFloat left_margin = 7;
174181
[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
175-
[self setFrameOrigin:NSMakePoint(left_margin, self.window.frame.size.height -
182+
[self setFrameOrigin:NSMakePoint(margin_.x(), self.window.frame.size.height -
176183
self.frame.size.height -
177-
top_margin)];
184+
margin_.y())];
178185
}
179186

180187
- (BOOL)_mouseInGroup:(NSButton*)button {
@@ -365,7 +372,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
365372
options.Get(options::kZoomToPageWidth, &zoom_to_page_width_);
366373
options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);
367374
options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);
368-
options.Get(options::kTrafficLightPosition, &traffic_light_position_);
375+
options.GetOptional(options::kTrafficLightPosition, &traffic_light_position_);
369376
options.Get(options::kVisualEffectState, &visual_effect_state_);
370377

371378
bool minimizable = true;
@@ -543,9 +550,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
543550
// Ensure maximizable options retain pre-existing state.
544551
SetMaximizable(maximizable_);
545552

546-
if (!traffic_light_position_.x() && !traffic_light_position_.y()) {
553+
// Changing system titlebar is only allowed for "hidden" titleBarStyle.
554+
if (!traffic_light_position_ || title_bar_style_ != TitleBarStyle::kHidden)
547555
return;
548-
}
556+
549557
if (IsFullscreen())
550558
return;
551559

@@ -571,7 +579,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
571579

572580
[titleBarContainerView setHidden:NO];
573581
CGFloat buttonHeight = [close frame].size.height;
574-
CGFloat titleBarFrameHeight = buttonHeight + traffic_light_position_.y();
582+
CGFloat titleBarFrameHeight = buttonHeight + traffic_light_position_->y();
575583
CGRect titleBarRect = titleBarContainerView.frame;
576584
CGFloat titleBarWidth = NSWidth(titleBarRect);
577585
titleBarRect.size.height = titleBarFrameHeight;
@@ -589,10 +597,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
589597
if (isRTL) {
590598
CGFloat buttonWidth = NSWidth(rect);
591599
// origin is always top-left, even in RTL
592-
rect.origin.x = titleBarWidth - traffic_light_position_.x() +
600+
rect.origin.x = titleBarWidth - traffic_light_position_->x() +
593601
(i * space_between) - buttonWidth;
594602
} else {
595-
rect.origin.x = traffic_light_position_.x() + (i * space_between);
603+
rect.origin.x = traffic_light_position_->x() + (i * space_between);
596604
}
597605
rect.origin.y = (titleBarFrameHeight - rect.size.height) / 2;
598606
[view setFrameOrigin:rect.origin];
@@ -1588,12 +1596,18 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
15881596
[effect_view setMaterial:vibrancyType];
15891597
}
15901598

1591-
void NativeWindowMac::SetTrafficLightPosition(const gfx::Point& position) {
1592-
traffic_light_position_ = position;
1593-
RedrawTrafficLights();
1599+
void NativeWindowMac::SetTrafficLightPosition(
1600+
base::Optional<gfx::Point> position) {
1601+
traffic_light_position_ = std::move(position);
1602+
if (title_bar_style_ == TitleBarStyle::kHidden) {
1603+
RedrawTrafficLights();
1604+
} else if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
1605+
[buttons_view_ setMargin:position];
1606+
[buttons_view_ viewDidMoveToWindow];
1607+
}
15941608
}
15951609

1596-
gfx::Point NativeWindowMac::GetTrafficLightPosition() const {
1610+
base::Optional<gfx::Point> NativeWindowMac::GetTrafficLightPosition() const {
15971611
return traffic_light_position_;
15981612
}
15991613

@@ -1695,8 +1709,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
16951709

16961710
// Create a custom window buttons view for kCustomButtonsOnHover.
16971711
if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
1698-
buttons_view_.reset(
1699-
[[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
1712+
buttons_view_.reset([[CustomWindowButtonView alloc]
1713+
initWithMargin:traffic_light_position_]);
17001714

17011715
if (!minimizable)
17021716
[[buttons_view_ viewWithTag:2] removeFromSuperview];

spec-main/api-browser-window-spec.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,28 +1536,36 @@ describe('BrowserWindow module', () => {
15361536
});
15371537
});
15381538

1539-
ifdescribe(process.platform === 'darwin')('BrowserWindow.getTrafficLightPosition(pos)', () => {
1539+
ifdescribe(process.platform === 'darwin')('trafficLightPosition', () => {
1540+
const pos = { x: 10, y: 10 };
15401541
afterEach(closeAllWindows);
15411542

1542-
it('gets the set traffic light position property', () => {
1543-
const pos = { x: 10, y: 10 };
1544-
const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos });
1545-
const currentPosition = w.getTrafficLightPosition();
1543+
describe('BrowserWindow.getTrafficLightPosition(pos)', () => {
1544+
it('gets position property for "hidden" titleBarStyle', () => {
1545+
const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos });
1546+
expect(w.getTrafficLightPosition()).to.deep.equal(pos);
1547+
});
15461548

1547-
expect(currentPosition).to.deep.equal(pos);
1549+
it('gets position property for "customButtonsOnHover" titleBarStyle', () => {
1550+
const w = new BrowserWindow({ show: false, titleBarStyle: 'customButtonsOnHover', trafficLightPosition: pos });
1551+
expect(w.getTrafficLightPosition()).to.deep.equal(pos);
1552+
});
15481553
});
1549-
});
15501554

1551-
ifdescribe(process.platform === 'darwin')('BrowserWindow.setTrafficLightPosition(pos)', () => {
1552-
afterEach(closeAllWindows);
1553-
1554-
it('can set the traffic light position property', () => {
1555-
const pos = { x: 10, y: 10 };
1556-
const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos });
1557-
w.setTrafficLightPosition(pos);
1558-
const currentPosition = w.getTrafficLightPosition();
1555+
describe('BrowserWindow.setTrafficLightPosition(pos)', () => {
1556+
it('sets position property for "hidden" titleBarStyle', () => {
1557+
const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos });
1558+
const newPos = { x: 20, y: 20 };
1559+
w.setTrafficLightPosition(newPos);
1560+
expect(w.getTrafficLightPosition()).to.deep.equal(newPos);
1561+
});
15591562

1560-
expect(currentPosition).to.deep.equal(pos);
1563+
it('sets position property for "customButtonsOnHover" titleBarStyle', () => {
1564+
const w = new BrowserWindow({ show: false, titleBarStyle: 'customButtonsOnHover', trafficLightPosition: pos });
1565+
const newPos = { x: 20, y: 20 };
1566+
w.setTrafficLightPosition(newPos);
1567+
expect(w.getTrafficLightPosition()).to.deep.equal(newPos);
1568+
});
15611569
});
15621570
});
15631571

0 commit comments

Comments
 (0)