feat: Add BrowserWindow option to hide window in Mission Control (macOS) (#36092)
* feat: Add BrowserWindow option to ignore Mission Control (macOS) * There are many circumstances when app developers may want to hide their windows from mission control. E.g., full screen overlays, small helper windows, dialogs, etc. * This PR adds the functionality, docs, and tests. * chore:Rename variables * Update shell/browser/native_window_mac.h Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com> Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com> Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
This commit is contained in:
parent
8b430c9d26
commit
15540975ff
9 changed files with 77 additions and 1 deletions
|
@ -192,6 +192,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||
macOS. Default is `false`.
|
||||
* `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar.
|
||||
Default is `false`.
|
||||
* `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control.
|
||||
* `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`.
|
||||
* `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `<title>` is defined in the HTML file loaded by `loadURL()`, this property will be ignored.
|
||||
* `icon` ([NativeImage](native-image.md) | string) (optional) - The window icon. On Windows it is
|
||||
|
@ -1255,6 +1256,16 @@ Returns `boolean` - Whether the window can be manually closed by user.
|
|||
|
||||
On Linux always returns `true`.
|
||||
|
||||
#### `win.setHiddenInMissionControl(hidden)` _macOS_
|
||||
|
||||
* `hidden` boolean
|
||||
|
||||
Sets whether the window will be hidden when the user toggles into mission control.
|
||||
|
||||
#### `win.isHiddenInMissionControl()` _macOS_
|
||||
|
||||
Returns `boolean` - Whether the window will be hidden when the user toggles into mission control.
|
||||
|
||||
#### `win.setAlwaysOnTop(flag[, level][, relativeLevel])`
|
||||
|
||||
* `flag` boolean
|
||||
|
|
|
@ -881,6 +881,16 @@ gfx::Point BaseWindow::GetTrafficLightPosition() const {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
bool BaseWindow::IsHiddenInMissionControl() {
|
||||
return window_->IsHiddenInMissionControl();
|
||||
}
|
||||
|
||||
void BaseWindow::SetHiddenInMissionControl(bool hidden) {
|
||||
window_->SetHiddenInMissionControl(hidden);
|
||||
}
|
||||
#endif
|
||||
|
||||
void BaseWindow::SetTouchBar(
|
||||
std::vector<gin_helper::PersistentDictionary> items) {
|
||||
window_->SetTouchBar(std::move(items));
|
||||
|
@ -1256,6 +1266,14 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("getTrafficLightPosition",
|
||||
&BaseWindow::GetTrafficLightPosition)
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
.SetMethod("isHiddenInMissionControl",
|
||||
&BaseWindow::IsHiddenInMissionControl)
|
||||
.SetMethod("setHiddenInMissionControl",
|
||||
&BaseWindow::SetHiddenInMissionControl)
|
||||
#endif
|
||||
|
||||
.SetMethod("_setTouchBarItems", &BaseWindow::SetTouchBar)
|
||||
.SetMethod("_refreshTouchBarItem", &BaseWindow::RefreshTouchBarItem)
|
||||
.SetMethod("_setEscapeTouchBarItem", &BaseWindow::SetEscapeTouchBarItem)
|
||||
|
|
|
@ -198,6 +198,11 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
|||
gfx::Point GetTrafficLightPosition() const;
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
bool IsHiddenInMissionControl();
|
||||
void SetHiddenInMissionControl(bool hidden);
|
||||
#endif
|
||||
|
||||
void SetTouchBar(std::vector<gin_helper::PersistentDictionary> items);
|
||||
void RefreshTouchBarItem(const std::string& item_id);
|
||||
void SetEscapeTouchBarItem(gin_helper::PersistentDictionary item);
|
||||
|
|
|
@ -227,6 +227,12 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void UpdateFrame() = 0;
|
||||
#endif
|
||||
|
||||
// whether windows should be ignored by mission control
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
virtual bool IsHiddenInMissionControl() = 0;
|
||||
virtual void SetHiddenInMissionControl(bool hidden) = 0;
|
||||
#endif
|
||||
|
||||
// Touchbar API
|
||||
virtual void SetTouchBar(std::vector<gin_helper::PersistentDictionary> items);
|
||||
virtual void RefreshTouchBarItem(const std::string& item_id);
|
||||
|
|
|
@ -103,6 +103,8 @@ class NativeWindowMac : public NativeWindow,
|
|||
void SetDocumentEdited(bool edited) override;
|
||||
bool IsDocumentEdited() override;
|
||||
void SetIgnoreMouseEvents(bool ignore, bool forward) override;
|
||||
bool IsHiddenInMissionControl() override;
|
||||
void SetHiddenInMissionControl(bool hidden) override;
|
||||
void SetContentProtection(bool enable) override;
|
||||
void SetFocusable(bool focusable) override;
|
||||
bool IsFocusable() override;
|
||||
|
|
|
@ -209,6 +209,9 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
|||
std::string windowType;
|
||||
options.Get(options::kType, &windowType);
|
||||
|
||||
bool hiddenInMissionControl = false;
|
||||
options.Get(options::kHiddenInMissionControl, &hiddenInMissionControl);
|
||||
|
||||
bool useStandardWindow = true;
|
||||
// eventually deprecate separate "standardWindow" option in favor of
|
||||
// standard / textured window types
|
||||
|
@ -347,6 +350,8 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
|||
options.Get(options::kDisableAutoHideCursor, &disableAutoHideCursor);
|
||||
[window_ setDisableAutoHideCursor:disableAutoHideCursor];
|
||||
|
||||
SetHiddenInMissionControl(hiddenInMissionControl);
|
||||
|
||||
// Set maximizable state last to ensure zoom button does not get reset
|
||||
// by calls to other APIs.
|
||||
SetMaximizable(maximizable);
|
||||
|
@ -1085,9 +1090,17 @@ bool NativeWindowMac::IsDocumentEdited() {
|
|||
return [window_ isDocumentEdited];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsHiddenInMissionControl() {
|
||||
NSUInteger collectionBehavior = [window_ collectionBehavior];
|
||||
return collectionBehavior & NSWindowCollectionBehaviorTransient;
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetHiddenInMissionControl(bool hidden) {
|
||||
SetCollectionBehavior(hidden, NSWindowCollectionBehaviorTransient);
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetIgnoreMouseEvents(bool ignore, bool forward) {
|
||||
[window_ setIgnoresMouseEvents:ignore];
|
||||
|
||||
if (!ignore) {
|
||||
SetForwardMouseMessages(NO);
|
||||
} else {
|
||||
|
|
|
@ -39,6 +39,8 @@ const char kOverlaySymbolColor[] = "symbolColor";
|
|||
// The custom height for Window Controls Overlay.
|
||||
const char kOverlayHeight[] = "height";
|
||||
|
||||
// whether to keep the window out of mission control
|
||||
const char kHiddenInMissionControl[] = "hiddenInMissionControl";
|
||||
// Whether the window should show in taskbar.
|
||||
const char kSkipTaskbar[] = "skipTaskbar";
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ extern const char kMinimizable[];
|
|||
extern const char kMaximizable[];
|
||||
extern const char kFullScreenable[];
|
||||
extern const char kClosable[];
|
||||
extern const char kHiddenInMissionControl[];
|
||||
extern const char kFullscreen[];
|
||||
extern const char kSkipTaskbar[];
|
||||
extern const char kKiosk[];
|
||||
|
|
|
@ -4784,6 +4784,24 @@ describe('BrowserWindow module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('isHiddenInMissionControl state', () => {
|
||||
it('with functions', () => {
|
||||
it('can be set with ignoreMissionControl constructor option', () => {
|
||||
const w = new BrowserWindow({ show: false, hiddenInMissionControl: true });
|
||||
expect(w.isHiddenInMissionControl()).to.be.true('isHiddenInMissionControl');
|
||||
});
|
||||
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.isHiddenInMissionControl()).to.be.false('isHiddenInMissionControl');
|
||||
w.setHiddenInMissionControl(true);
|
||||
expect(w.isHiddenInMissionControl()).to.be.true('isHiddenInMissionControl');
|
||||
w.setHiddenInMissionControl(false);
|
||||
expect(w.isHiddenInMissionControl()).to.be.false('isHiddenInMissionControl');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// fullscreen events are dispatched eagerly and twiddling things too fast can confuse poor Electron
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('kiosk state', () => {
|
||||
|
|
Loading…
Reference in a new issue