Merge pull request #949 from atom/window-transparency

Add support for window transparency
This commit is contained in:
Cheng Zhao 2015-01-12 14:05:20 -08:00
commit 1926c2cd01
7 changed files with 161 additions and 129 deletions

View file

@ -32,6 +32,7 @@
#include "brightray/browser/inspectable_web_contents_view.h" #include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_dialogs.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/invalidate_type.h" #include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_entry.h"
@ -60,6 +61,10 @@ using content::NavigationEntry;
using content::RenderWidgetHostView; using content::RenderWidgetHostView;
using content::RenderWidgetHost; using content::RenderWidgetHost;
namespace content {
CONTENT_EXPORT extern bool g_use_transparent_window;
}
namespace atom { namespace atom {
namespace { namespace {
@ -88,6 +93,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
const mate::Dictionary& options) const mate::Dictionary& options)
: content::WebContentsObserver(web_contents), : content::WebContentsObserver(web_contents),
has_frame_(true), has_frame_(true),
transparent_(false),
enable_larger_than_screen_(false), enable_larger_than_screen_(false),
is_closed_(false), is_closed_(false),
node_integration_(true), node_integration_(true),
@ -99,9 +105,14 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
printing::PrintViewManagerBasic::CreateForWebContents(web_contents); printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
options.Get(switches::kFrame, &has_frame_); options.Get(switches::kFrame, &has_frame_);
options.Get(switches::kTransparent, &transparent_);
options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_); options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_);
options.Get(switches::kNodeIntegration, &node_integration_); options.Get(switches::kNodeIntegration, &node_integration_);
// Tell the content module to initialize renderer widget with transparent
// mode.
content::g_use_transparent_window = transparent_;
// Read icon before window is created. // Read icon before window is created.
options.Get(switches::kIcon, &icon_); options.Get(switches::kIcon, &icon_);
@ -560,6 +571,18 @@ content::JavaScriptDialogManager* NativeWindow::GetJavaScriptDialogManager() {
return dialog_manager_.get(); return dialog_manager_.get();
} }
void NativeWindow::RenderViewCreated(
content::RenderViewHost* render_view_host) {
if (!transparent_)
return;
content::RenderWidgetHostImpl* impl = content::RenderWidgetHostImpl::FromID(
render_view_host->GetProcess()->GetID(),
render_view_host->GetRoutingID());
if (impl)
impl->SetBackgroundOpaque(false);
}
void NativeWindow::BeforeUnloadFired(content::WebContents* tab, void NativeWindow::BeforeUnloadFired(content::WebContents* tab,
bool proceed, bool proceed,
bool* proceed_to_fire_unload) { bool* proceed_to_fire_unload) {

View file

@ -269,6 +269,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
void RendererResponsive(content::WebContents* source) override; void RendererResponsive(content::WebContents* source) override;
// Implementations of content::WebContentsObserver. // Implementations of content::WebContentsObserver.
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
bool OnMessageReceived(const IPC::Message& message) override; bool OnMessageReceived(const IPC::Message& message) override;
@ -287,6 +288,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
// Whether window has standard frame. // Whether window has standard frame.
bool has_frame_; bool has_frame_;
// Whether window is transparent.
bool transparent_;
// Whether window can be resized larger than screen. // Whether window can be resized larger than screen.
bool enable_larger_than_screen_; bool enable_larger_than_screen_;

View file

@ -26,52 +26,52 @@ class NativeWindowMac : public NativeWindow {
virtual ~NativeWindowMac(); virtual ~NativeWindowMac();
// NativeWindow implementation. // NativeWindow implementation.
virtual void Close() OVERRIDE; void Close() override;
virtual void CloseImmediately() OVERRIDE; void CloseImmediately() override;
virtual void Move(const gfx::Rect& pos) OVERRIDE; void Move(const gfx::Rect& pos) override;
virtual void Focus(bool focus) OVERRIDE; void Focus(bool focus) override;
virtual bool IsFocused() OVERRIDE; bool IsFocused() override;
virtual void Show() OVERRIDE; void Show() override;
virtual void ShowInactive() OVERRIDE; void ShowInactive() override;
virtual void Hide() OVERRIDE; void Hide() override;
virtual bool IsVisible() OVERRIDE; bool IsVisible() override;
virtual void Maximize() OVERRIDE; void Maximize() override;
virtual void Unmaximize() OVERRIDE; void Unmaximize() override;
virtual bool IsMaximized() OVERRIDE; bool IsMaximized() override;
virtual void Minimize() OVERRIDE; void Minimize() override;
virtual void Restore() OVERRIDE; void Restore() override;
virtual bool IsMinimized() OVERRIDE; bool IsMinimized() override;
virtual void SetFullScreen(bool fullscreen) OVERRIDE; void SetFullScreen(bool fullscreen) override;
virtual bool IsFullscreen() OVERRIDE; bool IsFullscreen() override;
virtual void SetSize(const gfx::Size& size) OVERRIDE; void SetSize(const gfx::Size& size) override;
virtual gfx::Size GetSize() OVERRIDE; gfx::Size GetSize() override;
virtual void SetContentSize(const gfx::Size& size) OVERRIDE; void SetContentSize(const gfx::Size& size) override;
virtual gfx::Size GetContentSize() OVERRIDE; gfx::Size GetContentSize() override;
virtual void SetMinimumSize(const gfx::Size& size) OVERRIDE; void SetMinimumSize(const gfx::Size& size) override;
virtual gfx::Size GetMinimumSize() OVERRIDE; gfx::Size GetMinimumSize() override;
virtual void SetMaximumSize(const gfx::Size& size) OVERRIDE; void SetMaximumSize(const gfx::Size& size) override;
virtual gfx::Size GetMaximumSize() OVERRIDE; gfx::Size GetMaximumSize() override;
virtual void SetResizable(bool resizable) OVERRIDE; void SetResizable(bool resizable) override;
virtual bool IsResizable() OVERRIDE; bool IsResizable() override;
virtual void SetAlwaysOnTop(bool top) OVERRIDE; void SetAlwaysOnTop(bool top) override;
virtual bool IsAlwaysOnTop() OVERRIDE; bool IsAlwaysOnTop() override;
virtual void Center() OVERRIDE; void Center() override;
virtual void SetPosition(const gfx::Point& position) OVERRIDE; void SetPosition(const gfx::Point& position) override;
virtual gfx::Point GetPosition() OVERRIDE; gfx::Point GetPosition() override;
virtual void SetTitle(const std::string& title) OVERRIDE; void SetTitle(const std::string& title) override;
virtual std::string GetTitle() OVERRIDE; std::string GetTitle() override;
virtual void FlashFrame(bool flash) OVERRIDE; void FlashFrame(bool flash) override;
virtual void SetSkipTaskbar(bool skip) OVERRIDE; void SetSkipTaskbar(bool skip) override;
virtual void SetKiosk(bool kiosk) OVERRIDE; void SetKiosk(bool kiosk) override;
virtual bool IsKiosk() OVERRIDE; bool IsKiosk() override;
virtual void SetRepresentedFilename(const std::string& filename) OVERRIDE; void SetRepresentedFilename(const std::string& filename) override;
virtual std::string GetRepresentedFilename() OVERRIDE; std::string GetRepresentedFilename() override;
virtual void SetDocumentEdited(bool edited) OVERRIDE; void SetDocumentEdited(bool edited) override;
virtual bool IsDocumentEdited() OVERRIDE; bool IsDocumentEdited() override;
virtual bool HasModalDialog() OVERRIDE; bool HasModalDialog() override;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; gfx::NativeWindow GetNativeWindow() override;
virtual void SetProgressBar(double progress) OVERRIDE; void SetProgressBar(double progress) override;
virtual void ShowDefinitionForSelection() OVERRIDE; void ShowDefinitionForSelection() override;
// Returns true if |point| in local Cocoa coordinate system falls within // Returns true if |point| in local Cocoa coordinate system falls within
// the draggable region. // the draggable region.
@ -83,23 +83,22 @@ class NativeWindowMac : public NativeWindow {
// Clip web view to rounded corner. // Clip web view to rounded corner.
void ClipWebView(); void ClipWebView();
SkRegion* draggable_region() const { return draggable_region_.get(); }
protected: protected:
virtual void UpdateDraggableRegions( void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE; const std::vector<DraggableRegion>& regions) override;
// Implementations of content::WebContentsDelegate. // Implementations of content::WebContentsDelegate.
virtual void HandleKeyboardEvent( void HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE; const content::NativeWebKeyboardEvent&) override;
private: private:
void InstallView(); void InstallView();
void UninstallView(); void UninstallView();
void InstallDraggableRegionViews();
void UpdateDraggableRegionsForCustomDrag( // Install the drag view, which will cover the whole window and decides
const std::vector<DraggableRegion>& regions); // whehter we can drag.
void InstallDraggableRegionView();
base::scoped_nsobject<NSWindow> window_; base::scoped_nsobject<NSWindow> window_;
@ -113,10 +112,6 @@ class NativeWindowMac : public NativeWindow {
// The presentation options before entering kiosk mode. // The presentation options before entering kiosk mode.
NSApplicationPresentationOptions kiosk_options_; NSApplicationPresentationOptions kiosk_options_;
// For system drag, the whole window is draggable and the non-draggable areas
// have to been explicitly excluded.
std::vector<gfx::Rect> system_drag_exclude_areas_;
// For custom drag, the whole window is non-draggable and the draggable region // For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided. // has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag. scoped_ptr<SkRegion> draggable_region_; // used in custom drag.

View file

@ -101,7 +101,7 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
shell_->NotifyWindowBlur(); shell_->NotifyWindowBlur();
} }
- (void)windowDidResize:(NSNotification*)otification { - (void)windowDidResize:(NSNotification*)notification {
if (!shell_->has_frame()) if (!shell_->has_frame())
shell_->ClipWebView(); shell_->ClipWebView();
} }
@ -280,6 +280,29 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
namespace atom { namespace atom {
namespace {
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
SkRegion* DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
SkRegion* sk_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region;
}
} // namespace
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents, NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
const mate::Dictionary& options) const mate::Dictionary& options)
: NativeWindow(web_contents, options), : NativeWindow(web_contents, options),
@ -296,9 +319,7 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
width, width,
height); height);
AtomNSWindow* atomWindow; AtomNSWindow* atomWindow = [[AtomNSWindow alloc]
atomWindow = [[AtomNSWindow alloc]
initWithContentRect:cocoa_bounds initWithContentRect:cocoa_bounds
styleMask:NSTitledWindowMask | NSClosableWindowMask | styleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask |
@ -314,6 +335,13 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
[[AtomNSWindowDelegate alloc] initWithShell:this]; [[AtomNSWindowDelegate alloc] initWithShell:this];
[window_ setDelegate:delegate]; [window_ setDelegate:delegate];
if (transparent_) {
// Make window has transparent background.
[window_ setOpaque:NO];
[window_ setHasShadow:NO];
[window_ setBackgroundColor:[NSColor clearColor]];
}
// We will manage window's lifetime ourselves. // We will manage window's lifetime ourselves.
[window_ setReleasedWhenClosed:NO]; [window_ setReleasedWhenClosed:NO];
@ -542,6 +570,10 @@ gfx::Point NativeWindowMac::GetPosition() {
} }
void NativeWindowMac::SetTitle(const std::string& title) { void NativeWindowMac::SetTitle(const std::string& title) {
// We don't want the title to show in transparent window.
if (transparent_)
return;
[window_ setTitle:base::SysUTF8ToNSString(title)]; [window_ setTitle:base::SysUTF8ToNSString(title)];
} }
@ -659,7 +691,10 @@ void NativeWindowMac::ShowDefinitionForSelection() {
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const { bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region_) if (!draggable_region_)
return false; return false;
NSView* webView = GetWebContents()->GetNativeView(); content::WebContents* web_contents = GetWebContents();
if (!web_contents)
return false;
NSView* webView = web_contents->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]); NSInteger webViewHeight = NSHeight([webView bounds]);
// |draggable_region_| is stored in local platform-indepdent coordiate system // |draggable_region_| is stored in local platform-indepdent coordiate system
// while |point| is in local Cocoa coordinate system. Do the conversion // while |point| is in local Cocoa coordinate system. Do the conversion
@ -672,7 +707,6 @@ void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)]; NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)];
NSPoint current_mouse_location = mouseRect.origin; NSPoint current_mouse_location = mouseRect.origin;
if ([event type] == NSLeftMouseDown) { if ([event type] == NSLeftMouseDown) {
NSPoint frame_origin = [window_ frame].origin; NSPoint frame_origin = [window_ frame].origin;
last_mouse_offset_ = NSMakePoint( last_mouse_offset_ = NSMakePoint(
@ -691,8 +725,7 @@ void NativeWindowMac::UpdateDraggableRegions(
if (has_frame_) if (has_frame_)
return; return;
UpdateDraggableRegionsForCustomDrag(regions); draggable_region_.reset(DraggableRegionsToSkRegion(regions));
InstallDraggableRegionViews();
} }
void NativeWindowMac::HandleKeyboardEvent( void NativeWindowMac::HandleKeyboardEvent(
@ -749,11 +782,16 @@ void NativeWindowMac::InstallView() {
} }
ClipWebView(); ClipWebView();
InstallDraggableRegionView();
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
// Some third-party OS X utilities check the zoom button's enabled state to
// determine whether to show custom UI on hover, so we disable it here to
// prevent them from doing so in a frameless app window.
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
} }
} }
@ -763,70 +801,19 @@ void NativeWindowMac::UninstallView() {
} }
void NativeWindowMac::ClipWebView() { void NativeWindowMac::ClipWebView() {
NSView* view = GetWebContents()->GetNativeView();
view.layer.masksToBounds = YES;
view.layer.cornerRadius = kAtomWindowCornerRadius;
}
void NativeWindowMac::InstallDraggableRegionViews() {
DCHECK(!has_frame_);
// All ControlRegionViews should be added as children of the WebContentsView,
// because WebContentsView will be removed and re-added when entering and
// leaving fullscreen mode.
NSView* webView = GetWebContents()->GetNativeView(); NSView* webView = GetWebContents()->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]); webView.layer.masksToBounds = YES;
webView.layer.cornerRadius = kAtomWindowCornerRadius;
// Remove all ControlRegionViews that are added last time.
// Note that [webView subviews] returns the view's mutable internal array and
// it should be copied to avoid mutating the original array while enumerating
// it.
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
for (NSView* subview in subviews.get())
if ([subview isKindOfClass:[ControlRegionView class]])
[subview removeFromSuperview];
// Create and add ControlRegionView for each region that needs to be excluded
// from the dragging.
for (std::vector<gfx::Rect>::const_iterator iter =
system_drag_exclude_areas_.begin();
iter != system_drag_exclude_areas_.end();
++iter) {
base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithShellWindow:this]);
[controlRegion setFrame:NSMakeRect(iter->x(),
webViewHeight - iter->bottom(),
iter->width(),
iter->height())];
[webView addSubview:controlRegion];
}
} }
void NativeWindowMac::UpdateDraggableRegionsForCustomDrag( void NativeWindowMac::InstallDraggableRegionView() {
const std::vector<DraggableRegion>& regions) { NSView* webView = GetWebContents()->GetNativeView();
// We still need one ControlRegionView to cover the whole window such that base::scoped_nsobject<NSView> controlRegion(
// mouse events could be captured. [[ControlRegionView alloc] initWithShellWindow:this]);
NSView* web_view = GetWebContents()->GetNativeView(); [controlRegion setFrame:NSMakeRect(0, 0,
gfx::Rect window_bounds( NSWidth([webView bounds]),
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds])); NSHeight([webView bounds]))];
system_drag_exclude_areas_.clear(); [webView addSubview:controlRegion];
system_drag_exclude_areas_.push_back(window_bounds);
// Aggregate the draggable areas and non-draggable areas such that hit test
// could be performed easily.
SkRegion* draggable_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
draggable_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
draggable_region_.reset(draggable_region);
} }
// static // static

View file

@ -28,6 +28,7 @@
#include "ui/views/window/client_view.h" #include "ui/views/window/client_view.h"
#include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/wm/core/shadow_types.h"
#if defined(USE_X11) #if defined(USE_X11)
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
@ -183,6 +184,9 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
params.type = views::Widget::InitParams::TYPE_WINDOW; params.type = views::Widget::InitParams::TYPE_WINDOW;
params.remove_standard_frame = !has_frame_; params.remove_standard_frame = !has_frame_;
if (transparent_)
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
#if defined(USE_X11) #if defined(USE_X11)
std::string name = Browser::Get()->GetName(); std::string name = Browser::Get()->GetName();
// Set WM_WINDOW_ROLE. // Set WM_WINDOW_ROLE.
@ -237,8 +241,18 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
// frameless. // frameless.
DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
WS_CAPTION; WS_CAPTION;
// We should not show a frame for transparent window.
if (transparent_)
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style); ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
} }
if (transparent_) {
// Transparent window on Windows has to have WS_EX_COMPOSITED style.
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
ex_style |= WS_EX_COMPOSITED;
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
}
#endif #endif
// TODO(zcbenz): This was used to force using native frame on Windows 2003, we // TODO(zcbenz): This was used to force using native frame on Windows 2003, we
@ -248,6 +262,11 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
window_->FrameTypeChanged(); window_->FrameTypeChanged();
} }
// The given window is most likely not rectangular since it uses
// transparency and has no standard frame, don't show a shadow for it.
if (transparent_ && !has_frame_)
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
window_->UpdateWindowIcon(); window_->UpdateWindowIcon();
window_->CenterWindow(bounds.size()); window_->CenterWindow(bounds.size());
Layout(); Layout();

View file

@ -69,6 +69,9 @@ const char kGuestInstanceID[] = "guest-instance-id";
// Script that will be loaded by guest WebContents before other scripts. // Script that will be loaded by guest WebContents before other scripts.
const char kPreloadScript[] = "preload"; const char kPreloadScript[] = "preload";
// Whether the window should be transparent.
const char kTransparent[] = "transparent";
// Web runtime features. // Web runtime features.
const char kExperimentalFeatures[] = "experimental-features"; const char kExperimentalFeatures[] = "experimental-features";
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features"; const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";

View file

@ -39,6 +39,7 @@ extern const char kDirectWrite[];
extern const char kEnablePlugins[]; extern const char kEnablePlugins[];
extern const char kGuestInstanceID[]; extern const char kGuestInstanceID[];
extern const char kPreloadScript[]; extern const char kPreloadScript[];
extern const char kTransparent[];
extern const char kExperimentalFeatures[]; extern const char kExperimentalFeatures[];
extern const char kExperimentalCanvasFeatures[]; extern const char kExperimentalCanvasFeatures[];