diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 53b1321d9a04..2d240eff3640 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -631,6 +631,14 @@ bool Window::HasShadow() { return window_->HasShadow(); } +void Window::SetOpacity(const double opacity) { + window_->SetOpacity(opacity); +} + +double Window::GetOpacity() { + return window_->GetOpacity(); +} + void Window::FocusOnWebView() { window_->FocusOnWebView(); } @@ -1060,6 +1068,8 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("setBackgroundColor", &Window::SetBackgroundColor) .SetMethod("setHasShadow", &Window::SetHasShadow) .SetMethod("hasShadow", &Window::HasShadow) + .SetMethod("setOpacity", &Window::SetOpacity) + .SetMethod("getOpacity", &Window::GetOpacity) .SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename) .SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename) .SetMethod("setDocumentEdited", &Window::SetDocumentEdited) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index e89e757eefc2..657688f128b0 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -161,6 +161,8 @@ class Window : public mate::TrackableObject, void SetBackgroundColor(const std::string& color_name); void SetHasShadow(bool has_shadow); bool HasShadow(); + void SetOpacity(const double opacity); + double GetOpacity(); void FocusOnWebView(); void BlurWebView(); bool IsWebViewFocused(); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index ebf5dcfafec7..487557cd3118 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -159,6 +159,10 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { if (options.Get(options::kHasShadow, &has_shadow)) { SetHasShadow(has_shadow); } + double opacity; + if (options.Get(options::kOpacity, &opacity)) { + SetOpacity(opacity); + } bool top; if (options.Get(options::kAlwaysOnTop, &top) && top) { SetAlwaysOnTop(true); diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 56ec2a79dd6e..618acef96b0e 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -141,6 +141,8 @@ class NativeWindow : public base::SupportsUserData, virtual void SetBackgroundColor(const std::string& color_name) = 0; virtual void SetHasShadow(bool has_shadow) = 0; virtual bool HasShadow() = 0; + virtual void SetOpacity(const double opacity) = 0; + virtual double GetOpacity() = 0; virtual void SetRepresentedFilename(const std::string& filename); virtual std::string GetRepresentedFilename(); virtual void SetDocumentEdited(bool edited); diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index c8fbb688ce9f..24d9a0aab878 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -83,6 +83,8 @@ class NativeWindowMac : public NativeWindow, void SetBackgroundColor(const std::string& color_name) override; void SetHasShadow(bool has_shadow) override; bool HasShadow() override; + void SetOpacity(const double opacity) override; + double GetOpacity() override; void SetRepresentedFilename(const std::string& filename) override; std::string GetRepresentedFilename() override; void SetDocumentEdited(bool edited) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index ec61629e4f55..252df0ebb205 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1504,6 +1504,14 @@ bool NativeWindowMac::HasShadow() { return [window_ hasShadow]; } +void NativeWindowMac::SetOpacity(const double opacity) { + [window_ setAlphaValue:opacity]; +} + +double NativeWindowMac::GetOpacity() { + return [window_ alphaValue]; +} + void NativeWindowMac::SetRepresentedFilename(const std::string& filename) { [window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)]; } diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index a00943f5549f..444b8fc753a9 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -814,6 +814,24 @@ bool NativeWindowViews::HasShadow() { != wm::ShadowElevation::NONE; } +void NativeWindowViews::SetOpacity(const double opacity) { +#if defined(OS_WIN) + HWND hwnd = GetAcceleratedWidget(); + if (!layered_) { + LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); + ex_style |= WS_EX_LAYERED; + ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); + layered_ = true; + } + ::SetLayeredWindowAttributes(hwnd, 0, opacity * 255, LWA_ALPHA); +#endif + opacity_ = opacity; +} + +double NativeWindowViews::GetOpacity() { + return opacity_; +} + void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) { #if defined(OS_WIN) LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE); @@ -821,6 +839,8 @@ void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) { ex_style |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); else ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED); + if (layered_) + ex_style |= WS_EX_LAYERED; ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style); // Forwarding is always disabled when not ignoring mouse messages. diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 34ba2c8663ee..0f14f35c8f3e 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -104,6 +104,8 @@ class NativeWindowViews : public NativeWindow, void SetBackgroundColor(const std::string& color_name) override; void SetHasShadow(bool has_shadow) override; bool HasShadow() override; + void SetOpacity(const double opacity) override; + double GetOpacity() override; void SetIgnoreMouseEvents(bool ignore, bool forward) override; void SetContentProtection(bool enable) override; void SetFocusable(bool focusable) override; @@ -274,6 +276,7 @@ class NativeWindowViews : public NativeWindow, static HHOOK mouse_hook_; bool forwarding_mouse_messages_ = false; HWND legacy_window_ = NULL; + bool layered_ = false; #endif // Handles unhandled keyboard messages coming back from the renderer process. @@ -293,6 +296,7 @@ class NativeWindowViews : public NativeWindow, bool fullscreenable_; std::string title_; gfx::Size widget_size_; + double opacity_ = 1.0; DISALLOW_COPY_AND_ASSIGN(NativeWindowViews); }; diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 76aa1903f790..78235426efea 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -86,6 +86,9 @@ const char kBackgroundColor[] = "backgroundColor"; // Whether the window should have a shadow. const char kHasShadow[] = "hasShadow"; +// Browser window opacity +const char kOpacity[] = "opacity"; + // Whether the window can be activated. const char kFocusable[] = "focusable"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index fde740cd9190..401feae48a09 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -48,6 +48,7 @@ extern const char kDisableAutoHideCursor[]; extern const char kStandardWindow[]; extern const char kBackgroundColor[]; extern const char kHasShadow[]; +extern const char kOpacity[]; extern const char kFocusable[]; extern const char kWebPreferences[]; extern const char kVibrancyType[]; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index f6500aa80ed2..e2b7c3f048d2 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -205,6 +205,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. `#FFF` (white). * `hasShadow` Boolean (optional) - Whether window should have a shadow. This is only implemented on macOS. Default is `true`. + * `opacity` Number (optional) - Set the initial opacity of the window, between 0.0 (fully + transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS. * `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on some GTK+3 desktop environments. Default is `false`. * `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md). @@ -1206,6 +1208,16 @@ Returns `Boolean` - Whether the window has a shadow. On Windows and Linux always returns `true`. +#### `win.setOpacity(opacity)` _Windows_ _macOS_ + +* `opacity` Number - between 0.0 (fully transparent) and 1.0 (fully opaque) + +Sets the opacity of the window. On Linux does nothing. + +#### `win.getOpacity()` _Windows_ _macOS_ + +Returns `Number` - between 0.0 (fully transparent) and 1.0 (fully opaque) + #### `win.setThumbarButtons(buttons)` _Windows_ * `buttons` [ThumbarButton[]](structures/thumbar-button.md) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index c8ded515031e..5aa2e97afe19 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -807,6 +807,30 @@ describe('BrowserWindow module', function () { }) }) + describe('BrowserWindow.setOpacity(opacity)', function () { + it('make window with initial opacity', function () { + w.destroy() + w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + opacity: 0.5 + }) + assert.equal(w.getOpacity(), 0.5) + }) + + it('allows setting the opacity', function () { + assert.doesNotThrow(function () { + w.setOpacity(0.0) + assert.equal(w.getOpacity(), 0.0) + w.setOpacity(0.5) + assert.equal(w.getOpacity(), 0.5) + w.setOpacity(1.0) + assert.equal(w.getOpacity(), 1.0) + }) + }) + }) + describe('"useContentSize" option', function () { it('make window created with content size when used', function () { w.destroy()