feat: add BrowserWindow.set/getWindowButtonPosition APIs (#37094)

This commit is contained in:
Cheng Zhao 2023-02-17 19:06:32 +09:00 коммит произвёл GitHub
Родитель 0a5e634736
Коммит 0de1012280
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 188 добавлений и 26 удалений

Просмотреть файл

@ -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 Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been
deprecated and will be removed in an upcoming version of macOS. 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) * `position` [Point](structures/point.md)
Set a custom position for the traffic light buttons in frameless window. 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 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_ #### `win.setTouchBar(touchBar)` _macOS_

Просмотреть файл

@ -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. * **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. * **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) ## Planned Breaking API Changes (23.0)
### Removed: Windows 7 / 8 / 8.1 support ### Removed: Windows 7 / 8 / 8.1 support

Просмотреть файл

@ -582,6 +582,7 @@ filenames = {
"shell/common/gin_converters/native_window_converter.h", "shell/common/gin_converters/native_window_converter.h",
"shell/common/gin_converters/net_converter.cc", "shell/common/gin_converters/net_converter.cc",
"shell/common/gin_converters/net_converter.h", "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/serial_port_info_converter.h",
"shell/common/gin_converters/std_converter.h", "shell/common/gin_converters/std_converter.h",
"shell/common/gin_converters/time_converter.cc", "shell/common/gin_converters/time_converter.cc",

Просмотреть файл

@ -1,5 +1,6 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import type { BaseWindow as TLWT } from 'electron/main'; 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 }; const { BaseWindow } = process._linkedBinding('electron_browser_base_window') as { BaseWindow: typeof TLWT };
Object.setPrototypeOf(BaseWindow.prototype, EventEmitter.prototype); 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 // Properties
Object.defineProperty(BaseWindow.prototype, 'autoHideMenuBar', { Object.defineProperty(BaseWindow.prototype, 'autoHideMenuBar', {

Просмотреть файл

@ -22,6 +22,7 @@
#include "shell/common/gin_converters/gfx_converter.h" #include "shell/common/gin_converters/gfx_converter.h"
#include "shell/common/gin_converters/image_converter.h" #include "shell/common/gin_converters/image_converter.h"
#include "shell/common/gin_converters/native_window_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_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/gin_helper/object_template_builder.h"
@ -876,17 +877,12 @@ bool BaseWindow::GetWindowButtonVisibility() const {
return window_->GetWindowButtonVisibility(); return window_->GetWindowButtonVisibility();
} }
void BaseWindow::SetTrafficLightPosition(const gfx::Point& position) { void BaseWindow::SetWindowButtonPosition(absl::optional<gfx::Point> position) {
// For backward compatibility we treat (0, 0) as resetting to default. window_->SetWindowButtonPosition(std::move(position));
if (position.IsOrigin())
window_->SetTrafficLightPosition(absl::nullopt);
else
window_->SetTrafficLightPosition(position);
} }
gfx::Point BaseWindow::GetTrafficLightPosition() const { absl::optional<gfx::Point> BaseWindow::GetWindowButtonPosition() const {
// For backward compatibility we treat default value as (0, 0). return window_->GetWindowButtonPosition();
return window_->GetTrafficLightPosition().value_or(gfx::Point());
} }
#endif #endif
@ -1271,12 +1267,6 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setAutoHideCursor", &BaseWindow::SetAutoHideCursor) .SetMethod("setAutoHideCursor", &BaseWindow::SetAutoHideCursor)
#endif #endif
.SetMethod("setVibrancy", &BaseWindow::SetVibrancy) .SetMethod("setVibrancy", &BaseWindow::SetVibrancy)
#if BUILDFLAG(IS_MAC)
.SetMethod("setTrafficLightPosition",
&BaseWindow::SetTrafficLightPosition)
.SetMethod("getTrafficLightPosition",
&BaseWindow::GetTrafficLightPosition)
#endif
#if BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC)
.SetMethod("isHiddenInMissionControl", .SetMethod("isHiddenInMissionControl",
@ -1299,6 +1289,10 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
&BaseWindow::SetWindowButtonVisibility) &BaseWindow::SetWindowButtonVisibility)
.SetMethod("_getWindowButtonVisibility", .SetMethod("_getWindowButtonVisibility",
&BaseWindow::GetWindowButtonVisibility) &BaseWindow::GetWindowButtonVisibility)
.SetMethod("setWindowButtonPosition",
&BaseWindow::SetWindowButtonPosition)
.SetMethod("getWindowButtonPosition",
&BaseWindow::GetWindowButtonPosition)
.SetProperty("excludedFromShownWindowsMenu", .SetProperty("excludedFromShownWindowsMenu",
&BaseWindow::IsExcludedFromShownWindowsMenu, &BaseWindow::IsExcludedFromShownWindowsMenu,
&BaseWindow::SetExcludedFromShownWindowsMenu) &BaseWindow::SetExcludedFromShownWindowsMenu)

Просмотреть файл

@ -195,8 +195,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
std::string GetAlwaysOnTopLevel(); std::string GetAlwaysOnTopLevel();
void SetWindowButtonVisibility(bool visible); void SetWindowButtonVisibility(bool visible);
bool GetWindowButtonVisibility() const; bool GetWindowButtonVisibility() const;
void SetTrafficLightPosition(const gfx::Point& position); void SetWindowButtonPosition(absl::optional<gfx::Point> position);
gfx::Point GetTrafficLightPosition() const; absl::optional<gfx::Point> GetWindowButtonPosition() const;
#endif #endif
#if BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC)

Просмотреть файл

@ -219,8 +219,8 @@ class NativeWindow : public base::SupportsUserData,
#if BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC)
virtual void SetWindowButtonVisibility(bool visible) = 0; virtual void SetWindowButtonVisibility(bool visible) = 0;
virtual bool GetWindowButtonVisibility() const = 0; virtual bool GetWindowButtonVisibility() const = 0;
virtual void SetTrafficLightPosition(absl::optional<gfx::Point> position) = 0; virtual void SetWindowButtonPosition(absl::optional<gfx::Point> position) = 0;
virtual absl::optional<gfx::Point> GetTrafficLightPosition() const = 0; virtual absl::optional<gfx::Point> GetWindowButtonPosition() const = 0;
virtual void RedrawTrafficLights() = 0; virtual void RedrawTrafficLights() = 0;
virtual void UpdateFrame() = 0; virtual void UpdateFrame() = 0;
#endif #endif

Просмотреть файл

@ -129,8 +129,8 @@ class NativeWindowMac : public NativeWindow,
void SetVibrancy(const std::string& type) override; void SetVibrancy(const std::string& type) override;
void SetWindowButtonVisibility(bool visible) override; void SetWindowButtonVisibility(bool visible) override;
bool GetWindowButtonVisibility() const override; bool GetWindowButtonVisibility() const override;
void SetTrafficLightPosition(absl::optional<gfx::Point> position) override; void SetWindowButtonPosition(absl::optional<gfx::Point> position) override;
absl::optional<gfx::Point> GetTrafficLightPosition() const override; absl::optional<gfx::Point> GetWindowButtonPosition() const override;
void RedrawTrafficLights() override; void RedrawTrafficLights() override;
void UpdateFrame() override; void UpdateFrame() override;
void SetTouchBar( void SetTouchBar(

Просмотреть файл

@ -1474,7 +1474,7 @@ bool NativeWindowMac::GetWindowButtonVisibility() const {
![window_ standardWindowButton:NSWindowCloseButton].hidden; ![window_ standardWindowButton:NSWindowCloseButton].hidden;
} }
void NativeWindowMac::SetTrafficLightPosition( void NativeWindowMac::SetWindowButtonPosition(
absl::optional<gfx::Point> position) { absl::optional<gfx::Point> position) {
traffic_light_position_ = std::move(position); traffic_light_position_ = std::move(position);
if (buttons_proxy_) { if (buttons_proxy_) {
@ -1483,7 +1483,7 @@ void NativeWindowMac::SetTrafficLightPosition(
} }
} }
absl::optional<gfx::Point> NativeWindowMac::GetTrafficLightPosition() const { absl::optional<gfx::Point> NativeWindowMac::GetWindowButtonPosition() const {
return traffic_light_position_; return traffic_light_position_;
} }

Просмотреть файл

@ -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 <utility>
#include "gin/converter.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace gin {
template <typename T>
struct Converter<absl::optional<T>> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const absl::optional<T>& val) {
if (val)
return Converter<T>::ToV8(isolate, val.value());
else
return v8::Null(isolate);
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
absl::optional<T>* out) {
T converted;
if (Converter<T>::FromV8(isolate, val, &converted))
out->emplace(std::move(converted));
return true;
}
};
} // namespace gin
#endif // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_OPTIONAL_CONVERTER_H_

Просмотреть файл

@ -2087,7 +2087,52 @@ describe('BrowserWindow module', () => {
const pos = { x: 10, y: 10 }; const pos = { x: 10, y: 10 };
afterEach(closeAllWindows); 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)', () => { 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', () => { it('gets position property for "hidden" titleBarStyle', () => {
const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos });
expect(w.getTrafficLightPosition()).to.deep.equal(pos); expect(w.getTrafficLightPosition()).to.deep.equal(pos);
@ -2100,6 +2145,12 @@ describe('BrowserWindow module', () => {
}); });
describe('BrowserWindow.setTrafficLightPosition(pos)', () => { 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', () => { it('sets position property for "hidden" titleBarStyle', () => {
const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos }); const w = new BrowserWindow({ show: false, titleBarStyle: 'hidden', trafficLightPosition: pos });
const newPos = { x: 20, y: 20 }; const newPos = { x: 20, y: 20 };