Skip to content

Commit 68b86a9

Browse files
committed
Merge pull request nwjs#2463 from jtg-gg/transparency
nwjs#132 support for screen Transparency on WIN/OSX/Linux
2 parents 34bde97 + c740fd6 commit 68b86a9

13 files changed

+165
-2
lines changed

src/api/window/window.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ void Window::Call(const std::string& method,
268268
std::string label;
269269
if (arguments.GetString(0, &label))
270270
shell_->window()->SetBadgeLabel(label);
271+
} else if (method == "SetTransparent") {
272+
bool transparent;
273+
if (arguments.GetBoolean(0, &transparent))
274+
shell_->window()->SetTransparent(transparent);
271275
} else if (method == "SetProgressBar") {
272276
double progress;
273277
if (arguments.GetDouble(0, &progress))
@@ -315,6 +319,9 @@ void Window::CallSync(const std::string& method,
315319
gfx::Point position = shell_->window()->GetPosition();
316320
result->AppendInteger(position.x());
317321
result->AppendInteger(position.y());
322+
} else if (method == "IsTransparent") {
323+
bool transparent = shell_->window()->IsTransparent();
324+
result->AppendBoolean(transparent);
318325
} else if (method == "IsDevToolsOpen") {
319326
result->AppendBoolean(shell_->devToolsOpen());
320327
} else if (method == "ShowDevTools") {

src/api/window_bindings.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ Window.prototype.__defineGetter__('isFullscreen', function() {
249249
var result = CallObjectMethodSync(this, 'IsFullscreen', []);
250250
return Boolean(result[0]);
251251
});
252+
253+
Window.prototype.__defineGetter__('isTransparent', function() {
254+
var result = CallObjectMethodSync(this, 'IsTransparent', []);
255+
return Boolean(result[0]);
256+
});
252257

253258
Window.prototype.__defineSetter__('isKioskMode', function(flag) {
254259
if (flag)
@@ -425,6 +430,10 @@ Window.prototype.setProgressBar = function(progress) {
425430
throw new String('progress must be a number');
426431
CallObjectMethod(this, 'SetProgressBar', [ progress ]);
427432
}
433+
434+
Window.prototype.setTransparent = function(transparent) {
435+
CallObjectMethod(this, 'SetTransparent', [ transparent ]);
436+
}
428437

429438
Window.prototype.setPosition = function(position) {
430439
if (position != 'center' && position != 'mouse')

src/browser/native_window.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "base/memory/weak_ptr.h"
2424
#include "base/values.h"
25+
#include "base/command_line.h"
2526
#include "content/nw/src/browser/capture_page_helper.h"
2627
#include "content/nw/src/common/shell_switches.h"
2728
#include "content/nw/src/nw_package.h"
@@ -38,6 +39,9 @@
3839
#include "content/nw/src/browser/native_window_aura.h"
3940
#endif
4041

42+
namespace content {
43+
extern bool g_support_transparency;
44+
}
4145

4246
namespace nw {
4347

@@ -69,9 +73,13 @@ NativeWindow* NativeWindow::Create(const base::WeakPtr<content::Shell>& shell,
6973
NativeWindow::NativeWindow(const base::WeakPtr<content::Shell>& shell,
7074
base::DictionaryValue* manifest)
7175
: shell_(shell),
76+
transparent_(false),
7277
has_frame_(true),
7378
capture_page_helper_(NULL) {
7479
manifest->GetBoolean(switches::kmFrame, &has_frame_);
80+
content::g_support_transparency = !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kmDisableTransparency);
81+
if (content::g_support_transparency)
82+
manifest->GetBoolean(switches::kmTransparent, &transparent_);
7583

7684
LoadAppIconFromPackage(manifest);
7785
}

src/browser/native_window.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class NativeWindow {
8888
virtual void Restore() = 0;
8989
virtual void SetFullscreen(bool fullscreen) = 0;
9090
virtual bool IsFullscreen() = 0;
91+
virtual void SetTransparent(bool transparent) = 0;
9192
virtual void SetSize(const gfx::Size& size) = 0;
9293
virtual gfx::Size GetSize() = 0;
9394
virtual void SetMinimumSize(int width, int height) = 0;
@@ -140,6 +141,7 @@ class NativeWindow {
140141
bool has_frame() const { return has_frame_; }
141142
const gfx::Image& app_icon() const { return app_icon_; }
142143
void CapturePage(const std::string& image_format);
144+
bool IsTransparent() { return transparent_; }
143145

144146
protected:
145147
void OnNativeWindowDestory() {
@@ -151,6 +153,8 @@ class NativeWindow {
151153

152154
// Weak reference to parent.
153155
base::WeakPtr<content::Shell> shell_;
156+
157+
bool transparent_;
154158

155159
bool has_frame_;
156160

src/browser/native_window_aura.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222

2323
#if defined(OS_WIN)
2424
#include <shobjidl.h>
25+
#include <dwmapi.h>
2526
#endif
2627

2728
#include "base/strings/utf_string_conversions.h"
2829
#include "base/values.h"
30+
#include "base/command_line.h"
2931

3032
#if defined(OS_WIN)
3133
#include "base/win/scoped_comptr.h"
@@ -44,6 +46,7 @@
4446
#include "content/public/browser/render_view_host.h"
4547
#include "content/public/browser/render_widget_host_view.h"
4648
#include "content/public/browser/web_contents.h"
49+
#include "content/public/common/content_switches.h"
4750
#include "extensions/common/draggable_region.h"
4851
#include "third_party/skia/include/core/SkPaint.h"
4952
#include "ui/base/hit_test.h"
@@ -58,9 +61,11 @@
5861
#include "ui/gfx/font_list.h"
5962
#include "ui/gfx/platform_font.h"
6063
#include "ui/gfx/image/image_skia_operations.h"
64+
#include "ui/views/background.h"
6165
#include "ui/views/controls/webview/webview.h"
6266
#include "ui/views/layout/box_layout.h"
6367
#include "ui/views/views_delegate.h"
68+
#include "ui/views/views_switches.h"
6469
#include "ui/views/widget/widget.h"
6570
#include "ui/views/window/native_frame_view.h"
6671
#include "ui/views/widget/native_widget_private.h"
@@ -77,6 +82,9 @@
7782
#include "ash/accelerators/accelerator_table.h"
7883
#endif
7984

85+
namespace content {
86+
extern bool g_support_transparency;
87+
}
8088

8189

8290
namespace nw {
@@ -291,6 +299,8 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr<content::Shell>& shell,
291299
params.delegate = this;
292300
params.remove_standard_frame = !has_frame();
293301
params.use_system_default_icon = true;
302+
if (content::g_support_transparency && transparent_)
303+
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
294304
if (is_fullscreen_)
295305
params.show_state = ui::SHOW_STATE_FULLSCREEN;
296306
#if defined(OS_WIN)
@@ -400,6 +410,87 @@ bool NativeWindowAura::IsFullscreen() {
400410
return is_fullscreen_;
401411
}
402412

413+
void NativeWindowAura::SetTransparent(bool transparent) {
414+
if (!content::g_support_transparency)
415+
return;
416+
#if defined(OS_WIN)
417+
// Check for Windows Vista or higher, transparency isn't supported in
418+
// anything lower.
419+
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
420+
NOTREACHED() << "The operating system does not support transparency.";
421+
transparent_ = false;
422+
return;
423+
}
424+
425+
// Check to see if composition is disabled, if so we have to throw an
426+
// error, there's no graceful recovery, yet. TODO: Graceful recovery.
427+
BOOL enabled = FALSE;
428+
HRESULT result = ::DwmIsCompositionEnabled(&enabled);
429+
if (!enabled || !SUCCEEDED(result)) {
430+
NOTREACHED() << "Windows DWM composition is not enabled, transparency is not supported.";
431+
transparent_ = false;
432+
return;
433+
}
434+
435+
HWND hWnd = views::HWNDForWidget(window_);
436+
437+
const int marginVal = transparent ? -1 : 0;
438+
MARGINS mgMarInset = { marginVal, marginVal, marginVal, marginVal };
439+
if (DwmExtendFrameIntoClientArea(hWnd, &mgMarInset) != S_OK) {
440+
NOTREACHED() << "Windows DWM extending to client area failed, transparency is not supported.";
441+
transparent_ = false;
442+
return;
443+
}
444+
445+
// this is needed, or transparency will fail if it defined on startup
446+
bool change_window_style = false;
447+
448+
if (!has_frame_) {
449+
const LONG lastStyle = GetWindowLong(hWnd, GWL_STYLE);
450+
const LONG style = WS_CAPTION;
451+
const LONG newStyle = transparent ? lastStyle | style : lastStyle & ~style;
452+
SetWindowLong(hWnd, GWL_STYLE, newStyle);
453+
change_window_style |= lastStyle != newStyle;
454+
}
455+
456+
const LONG lastExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
457+
const LONG exStyle = WS_EX_COMPOSITED;
458+
const LONG newExStyle = transparent ? lastExStyle | exStyle : lastExStyle & ~exStyle;
459+
SetWindowLong(hWnd, GWL_EXSTYLE, newExStyle);
460+
change_window_style |= lastExStyle != newExStyle;
461+
462+
if (change_window_style) {
463+
window_->FrameTypeChanged();
464+
}
465+
#elif defined(USE_X11) && !defined(OS_CHROMEOS)
466+
467+
static char cachedRes = -1;
468+
if ( cachedRes<0 ) {
469+
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
470+
cachedRes = !command_line.HasSwitch(switches::kDisableGpu) ||
471+
!command_line.HasSwitch(views::switches::kEnableTransparentVisuals);
472+
}
473+
474+
if (cachedRes && transparent) {
475+
LOG(INFO) << "if transparency does not work, try with --enable-transparent-visuals --disable-gpu";
476+
}
477+
478+
#endif
479+
480+
if (toolbar_) {
481+
toolbar_->set_background(transparent ? views::Background::CreateSolidBackground(SK_ColorTRANSPARENT) :
482+
views::Background::CreateStandardPanelBackground());
483+
toolbar_->SchedulePaint();
484+
}
485+
486+
content::RenderWidgetHostView* rwhv = shell_->web_contents()->GetRenderWidgetHostView();
487+
if (rwhv) {
488+
rwhv->SetBackgroundOpaque(!transparent);
489+
}
490+
491+
transparent_ = transparent;
492+
}
493+
403494
void NativeWindowAura::SetSize(const gfx::Size& size) {
404495
window_->SetSize(size);
405496
}

src/browser/native_window_aura.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class NativeWindowAura : public NativeWindow,
7878
virtual void Restore() OVERRIDE;
7979
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
8080
virtual bool IsFullscreen() OVERRIDE;
81+
virtual void SetTransparent(bool transparent) OVERRIDE;
8182
virtual void SetSize(const gfx::Size& size) OVERRIDE;
8283
virtual gfx::Size GetSize() OVERRIDE;
8384
virtual void SetMinimumSize(int width, int height) OVERRIDE;

src/browser/native_window_gtk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class NativeWindowGtk : public NativeWindow {
4848
virtual void Restore() OVERRIDE;
4949
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
5050
virtual bool IsFullscreen() OVERRIDE;
51+
virtual void SetTransparent(bool transparent) OVERRIDE;
5152
virtual void SetSize(const gfx::Size& size) OVERRIDE;
5253
virtual gfx::Size GetSize() OVERRIDE;
5354
virtual void SetMinimumSize(int width, int height) OVERRIDE;

src/browser/native_window_mac.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class NativeWindowCocoa : public NativeWindow {
5252
virtual void Restore() OVERRIDE;
5353
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
5454
virtual bool IsFullscreen() OVERRIDE;
55+
virtual void SetTransparent(bool transparent) OVERRIDE;
5556
virtual void SetSize(const gfx::Size& size) OVERRIDE;
5657
virtual gfx::Size GetSize() OVERRIDE;
5758
virtual void SetMinimumSize(int width, int height) OVERRIDE;
@@ -111,6 +112,9 @@ class NativeWindowCocoa : public NativeWindow {
111112

112113
// Delegate to the toolbar.
113114
base::scoped_nsobject<ShellToolbarDelegate> toolbar_delegate_;
115+
116+
// Data for transparency
117+
NSColor *opaque_color_;
114118

115119
bool is_fullscreen_;
116120
bool is_kiosk_;

src/browser/native_window_mac.mm

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@
3535
#include "content/nw/src/nw_package.h"
3636
#include "content/nw/src/nw_shell.h"
3737
#include "content/public/browser/native_web_keyboard_event.h"
38-
#include "content/public/browser/render_widget_host_view.h"
38+
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
3939
#include "content/public/browser/web_contents.h"
4040
#include "extensions/common/draggable_region.h"
4141
#include "third_party/skia/include/core/SkRegion.h"
4242
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
4343

44+
namespace content {
45+
extern bool g_support_transparency;
46+
}
47+
4448
@interface NSWindow (NSPrivateApis)
4549
- (void)setBottomCornerRounded:(BOOL)rounded;
4650
@end
@@ -282,7 +286,11 @@ - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view {
282286
[[NSBezierPath bezierPathWithRoundedRect:[view bounds]
283287
xRadius:cornerRadius
284288
yRadius:cornerRadius] addClip];
285-
[[NSColor whiteColor] set];
289+
if ([self isOpaque] || !content::g_support_transparency)
290+
[[NSColor whiteColor] set];
291+
else
292+
[[NSColor clearColor] set];
293+
286294
NSRectFill(rect);
287295
}
288296

@@ -385,10 +393,13 @@ - (void)drawRect:(NSRect)dirtyRect {
385393
defer:NO];
386394
}
387395
window_ = shell_window;
396+
opaque_color_ = [window() backgroundColor];
388397
[shell_window setShell:shell];
389398
[[window() contentView] setWantsLayer:YES];
390399
[window() setDelegate:[[NativeWindowDelegate alloc] initWithShell:shell]];
391400

401+
SetTransparent(transparent_);
402+
392403
// Disable fullscreen button when 'fullscreen' is specified to false.
393404
bool fullscreen;
394405
if (!(manifest->GetBoolean(switches::kmFullscreen, &fullscreen) &&
@@ -539,6 +550,27 @@ - (void)drawRect:(NSRect)dirtyRect {
539550
return is_fullscreen_;
540551
}
541552

553+
void NativeWindowCocoa::SetTransparent(bool transparent) {
554+
555+
if (!content::g_support_transparency) return;
556+
if (!transparent_ && transparent) {
557+
opaque_color_ = [window() backgroundColor];
558+
}
559+
560+
[window() setHasShadow:transparent ? NO : YES];
561+
[window() setOpaque:transparent ? NO : YES];
562+
[window() setBackgroundColor:transparent ? [NSColor clearColor] : opaque_color_];
563+
564+
content::RenderWidgetHostViewMac* rwhv = static_cast<content::RenderWidgetHostViewMac*>(shell_->web_contents()->GetRenderWidgetHostView());
565+
566+
if (rwhv) {
567+
rwhv->SetBackgroundOpaque(!transparent);
568+
[rwhv->background_layer_ setBackgroundColor:CGColorGetConstantColor(transparent ? kCGColorClear : kCGColorWhite)];
569+
}
570+
571+
transparent_ = transparent;
572+
573+
}
542574
void NativeWindowCocoa::SetNonLionFullscreen(bool fullscreen) {
543575
if (fullscreen == is_fullscreen_)
544576
return;

src/common/shell_switches.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ const char kmResizable[] = "resizable";
7272
const char kmAsDesktop[] = "as_desktop";
7373
const char kmFullscreen[] = "fullscreen";
7474
const char kmInitialFocus[] = "focus";
75+
const char kmTransparent[] = "transparent";
76+
const char kmDisableTransparency[] = "disable_transparency";
7577

7678
// Make windows icon hide show or hide in taskbar.
7779
const char kmShowInTaskbar[] = "show_in_taskbar";

0 commit comments

Comments
 (0)