diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 73f40824fa..0f0ca4b6cc 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1842,16 +1842,36 @@ will remove the vibrancy effect on the window. Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been deprecated and will be removed in an upcoming version of macOS. -#### `win.setTrafficLightPosition(position)` _macOS_ +#### `win.setWindowButtonPosition(position)` _macOS_ + +* `position` [Point](structures/point.md) | null + +Set a custom position for the traffic light buttons in frameless window. +Passing `null` will reset the position to default. + +#### `win.getWindowButtonPosition()` _macOS_ + +Returns `Point | null` - The custom position for the traffic light buttons in +frameless window, `null` will be returned when there is no custom position. + +#### `win.setTrafficLightPosition(position)` _macOS_ _Deprecated_ * `position` [Point](structures/point.md) Set a custom position for the traffic light buttons in frameless window. +Passing `{ x: 0, y: 0 }` will reset the position to default. -#### `win.getTrafficLightPosition()` _macOS_ +> **Note** +> This function is deprecated. Use [setWindowButtonPosition](#winsetwindowbuttonpositionposition-macos) instead. + +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ Returns `Point` - The custom position for the traffic light buttons in -frameless window. +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. + +> **Note** +> This function is deprecated. Use [getWindowButtonPosition](#wingetwindowbuttonposition-macos) instead. #### `win.setTouchBar(touchBar)` _macOS_ diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index 5449a4b60a..e6898e9eba 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -12,6 +12,46 @@ This document uses the following convention to categorize breaking changes: * **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. * **Removed:** An API or feature was removed, and is no longer supported by Electron. +## Planned Breaking API Changes (24.0) + +### Deprecated: `BrowserWindow.setTrafficLightPosition(position)` + +`BrowserWindow.setTrafficLightPosition(position)` has been deprecated, the +`BrowserWindow.setWindowButtonPosition(position)` API should be used instead +which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to +system default. + +```js +// Removed in Electron 24 +win.setTrafficLightPosition({ x: 10, y: 10 }) +win.setTrafficLightPosition({ x: 0, y: 0 }) + +// Replace with +win.setWindowButtonPosition({ x: 10, y: 10 }) +win.setWindowButtonPosition(null) +``` + +### Deprecated: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been deprecated, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +```js +// Removed in Electron 24 +const pos = win.getTrafficLightPosition() +if (pos.x === 0 && pos.y === 0) { + // No custom position. +} + +// Replace with +const ret = win.getWindowButtonPosition() +if (ret === null) { + // No custom position. +} +``` + ## Planned Breaking API Changes (23.0) ### Removed: Windows 7 / 8 / 8.1 support diff --git a/filenames.gni b/filenames.gni index f3dc677334..bb080c4722 100644 --- a/filenames.gni +++ b/filenames.gni @@ -582,6 +582,7 @@ filenames = { "shell/common/gin_converters/native_window_converter.h", "shell/common/gin_converters/net_converter.cc", "shell/common/gin_converters/net_converter.h", + "shell/common/gin_converters/optional_converter.h", "shell/common/gin_converters/serial_port_info_converter.h", "shell/common/gin_converters/std_converter.h", "shell/common/gin_converters/time_converter.cc", diff --git a/lib/browser/api/base-window.ts b/lib/browser/api/base-window.ts index 28671d7c1d..45a200e125 100644 --- a/lib/browser/api/base-window.ts +++ b/lib/browser/api/base-window.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'events'; import type { BaseWindow as TLWT } from 'electron/main'; +import * as deprecate from '@electron/internal/common/deprecate'; const { BaseWindow } = process._linkedBinding('electron_browser_base_window') as { BaseWindow: typeof TLWT }; Object.setPrototypeOf(BaseWindow.prototype, EventEmitter.prototype); @@ -15,6 +16,25 @@ BaseWindow.prototype._init = function () { } }; +// Deprecation. +const setTrafficLightPositionDeprecated = deprecate.warnOnce('setTrafficLightPosition', 'setWindowButtonPosition'); +// Converting to any as the methods are defined under BrowserWindow in our docs. +(BaseWindow as any).prototype.setTrafficLightPosition = function (pos: Electron.Point) { + setTrafficLightPositionDeprecated(); + if (typeof pos === 'object' && pos.x === 0 && pos.y === 0) { + this.setWindowButtonPosition(null); + } else { + this.setWindowButtonPosition(pos); + } +}; + +const getTrafficLightPositionDeprecated = deprecate.warnOnce('getTrafficLightPosition', 'getWindowButtonPosition'); +(BaseWindow as any).prototype.getTrafficLightPosition = function () { + getTrafficLightPositionDeprecated(); + const pos = this.getWindowButtonPosition(); + return pos === null ? { x: 0, y: 0 } : pos; +}; + // Properties Object.defineProperty(BaseWindow.prototype, 'autoHideMenuBar', { diff --git a/shell/browser/api/electron_api_base_window.cc b/shell/browser/api/electron_api_base_window.cc index 9c0377dafb..fdbe58cf2b 100644 --- a/shell/browser/api/electron_api_base_window.cc +++ b/shell/browser/api/electron_api_base_window.cc @@ -22,6 +22,7 @@ #include "shell/common/gin_converters/gfx_converter.h" #include "shell/common/gin_converters/image_converter.h" #include "shell/common/gin_converters/native_window_converter.h" +#include "shell/common/gin_converters/optional_converter.h" #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/object_template_builder.h" @@ -876,17 +877,12 @@ bool BaseWindow::GetWindowButtonVisibility() const { return window_->GetWindowButtonVisibility(); } -void BaseWindow::SetTrafficLightPosition(const gfx::Point& position) { - // For backward compatibility we treat (0, 0) as resetting to default. - if (position.IsOrigin()) - window_->SetTrafficLightPosition(absl::nullopt); - else - window_->SetTrafficLightPosition(position); +void BaseWindow::SetWindowButtonPosition(absl::optional position) { + window_->SetWindowButtonPosition(std::move(position)); } -gfx::Point BaseWindow::GetTrafficLightPosition() const { - // For backward compatibility we treat default value as (0, 0). - return window_->GetTrafficLightPosition().value_or(gfx::Point()); +absl::optional BaseWindow::GetWindowButtonPosition() const { + return window_->GetWindowButtonPosition(); } #endif @@ -1271,12 +1267,6 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate, .SetMethod("setAutoHideCursor", &BaseWindow::SetAutoHideCursor) #endif .SetMethod("setVibrancy", &BaseWindow::SetVibrancy) -#if BUILDFLAG(IS_MAC) - .SetMethod("setTrafficLightPosition", - &BaseWindow::SetTrafficLightPosition) - .SetMethod("getTrafficLightPosition", - &BaseWindow::GetTrafficLightPosition) -#endif #if BUILDFLAG(IS_MAC) .SetMethod("isHiddenInMissionControl", @@ -1299,6 +1289,10 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate, &BaseWindow::SetWindowButtonVisibility) .SetMethod("_getWindowButtonVisibility", &BaseWindow::GetWindowButtonVisibility) + .SetMethod("setWindowButtonPosition", + &BaseWindow::SetWindowButtonPosition) + .SetMethod("getWindowButtonPosition", + &BaseWindow::GetWindowButtonPosition) .SetProperty("excludedFromShownWindowsMenu", &BaseWindow::IsExcludedFromShownWindowsMenu, &BaseWindow::SetExcludedFromShownWindowsMenu) diff --git a/shell/browser/api/electron_api_base_window.h b/shell/browser/api/electron_api_base_window.h index 01649ede90..28207f1e57 100644 --- a/shell/browser/api/electron_api_base_window.h +++ b/shell/browser/api/electron_api_base_window.h @@ -195,8 +195,8 @@ class BaseWindow : public gin_helper::TrackableObject, std::string GetAlwaysOnTopLevel(); void SetWindowButtonVisibility(bool visible); bool GetWindowButtonVisibility() const; - void SetTrafficLightPosition(const gfx::Point& position); - gfx::Point GetTrafficLightPosition() const; + void SetWindowButtonPosition(absl::optional position); + absl::optional GetWindowButtonPosition() const; #endif #if BUILDFLAG(IS_MAC) diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index 776a6e7eed..23d37dd29d 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -219,8 +219,8 @@ class NativeWindow : public base::SupportsUserData, #if BUILDFLAG(IS_MAC) virtual void SetWindowButtonVisibility(bool visible) = 0; virtual bool GetWindowButtonVisibility() const = 0; - virtual void SetTrafficLightPosition(absl::optional position) = 0; - virtual absl::optional GetTrafficLightPosition() const = 0; + virtual void SetWindowButtonPosition(absl::optional position) = 0; + virtual absl::optional GetWindowButtonPosition() const = 0; virtual void RedrawTrafficLights() = 0; virtual void UpdateFrame() = 0; #endif diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index 5cde63c13c..4431fe1c64 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -129,8 +129,8 @@ class NativeWindowMac : public NativeWindow, void SetVibrancy(const std::string& type) override; void SetWindowButtonVisibility(bool visible) override; bool GetWindowButtonVisibility() const override; - void SetTrafficLightPosition(absl::optional position) override; - absl::optional GetTrafficLightPosition() const override; + void SetWindowButtonPosition(absl::optional position) override; + absl::optional GetWindowButtonPosition() const override; void RedrawTrafficLights() override; void UpdateFrame() override; void SetTouchBar( diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index 26db67be06..3a2bb15b58 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -1474,7 +1474,7 @@ bool NativeWindowMac::GetWindowButtonVisibility() const { ![window_ standardWindowButton:NSWindowCloseButton].hidden; } -void NativeWindowMac::SetTrafficLightPosition( +void NativeWindowMac::SetWindowButtonPosition( absl::optional position) { traffic_light_position_ = std::move(position); if (buttons_proxy_) { @@ -1483,7 +1483,7 @@ void NativeWindowMac::SetTrafficLightPosition( } } -absl::optional NativeWindowMac::GetTrafficLightPosition() const { +absl::optional NativeWindowMac::GetWindowButtonPosition() const { return traffic_light_position_; } diff --git a/shell/common/gin_converters/optional_converter.h b/shell/common/gin_converters/optional_converter.h new file mode 100644 index 0000000000..e40a463c76 --- /dev/null +++ b/shell/common/gin_converters/optional_converter.h @@ -0,0 +1,36 @@ +// Copyright (c) 2023 Microsoft, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_COMMON_GIN_CONVERTERS_OPTIONAL_CONVERTER_H_ +#define ELECTRON_SHELL_COMMON_GIN_CONVERTERS_OPTIONAL_CONVERTER_H_ + +#include + +#include "gin/converter.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace gin { + +template +struct Converter> { + static v8::Local ToV8(v8::Isolate* isolate, + const absl::optional& val) { + if (val) + return Converter::ToV8(isolate, val.value()); + else + return v8::Null(isolate); + } + static bool FromV8(v8::Isolate* isolate, + v8::Local val, + absl::optional* out) { + T converted; + if (Converter::FromV8(isolate, val, &converted)) + out->emplace(std::move(converted)); + return true; + } +}; + +} // namespace gin + +#endif // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_OPTIONAL_CONVERTER_H_ diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index 32e8049f83..5141f076f0 100644 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -2087,7 +2087,52 @@ describe('BrowserWindow module', () => { const pos = { x: 10, y: 10 }; afterEach(closeAllWindows); + describe('BrowserWindow.getWindowButtonPosition(pos)', () => { + it('returns null when there is no custom position', () => { + const w = new BrowserWindow({ show: false }); + expect(w.getWindowButtonPosition()).to.be.null('getWindowButtonPosition'); + }); + + it('gets position property for "hidden" titleBarStyle', () => { + const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); + expect(w.getWindowButtonPosition()).to.deep.equal(pos); + }); + + it('gets position property for "customButtonsOnHover" titleBarStyle', () => { + const w = new BrowserWindow({ show: false, titleBarStyle: 'customButtonsOnHover', trafficLightPosition: pos }); + expect(w.getWindowButtonPosition()).to.deep.equal(pos); + }); + }); + + describe('BrowserWindow.setWindowButtonPosition(pos)', () => { + it('resets the position when null is passed', () => { + const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); + w.setWindowButtonPosition(null); + expect(w.getWindowButtonPosition()).to.be.null('setWindowButtonPosition'); + }); + + it('sets position property for "hidden" titleBarStyle', () => { + const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); + const newPos = { x: 20, y: 20 }; + w.setWindowButtonPosition(newPos); + expect(w.getWindowButtonPosition()).to.deep.equal(newPos); + }); + + it('sets position property for "customButtonsOnHover" titleBarStyle', () => { + const w = new BrowserWindow({ show: false, titleBarStyle: 'customButtonsOnHover', trafficLightPosition: pos }); + const newPos = { x: 20, y: 20 }; + w.setWindowButtonPosition(newPos); + expect(w.getWindowButtonPosition()).to.deep.equal(newPos); + }); + }); + + // The set/getTrafficLightPosition APIs are deprecated. describe('BrowserWindow.getTrafficLightPosition(pos)', () => { + it('returns { x: 0, y: 0 } when there is no custom position', () => { + const w = new BrowserWindow({ show: false }); + expect(w.getTrafficLightPosition()).to.deep.equal({ x: 0, y: 0 }); + }); + it('gets position property for "hidden" titleBarStyle', () => { const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); expect(w.getTrafficLightPosition()).to.deep.equal(pos); @@ -2100,6 +2145,12 @@ describe('BrowserWindow module', () => { }); describe('BrowserWindow.setTrafficLightPosition(pos)', () => { + it('resets the position when { x: 0, y: 0 } is passed', () => { + const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); + w.setTrafficLightPosition({ x: 0, y: 0 }); + expect(w.getTrafficLightPosition()).to.deep.equal({ x: 0, y: 0 }); + }); + it('sets position property for "hidden" titleBarStyle', () => { const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); const newPos = { x: 20, y: 20 };