diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 5248f6bda816b..f0261f274539e 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -32,6 +32,7 @@ #include "brightray/browser/inspectable_web_contents_view.h" #include "chrome/browser/printing/print_view_manager_basic.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/invalidate_type.h" #include "content/public/browser/navigation_entry.h" @@ -60,6 +61,10 @@ using content::NavigationEntry; using content::RenderWidgetHostView; using content::RenderWidgetHost; +namespace content { +CONTENT_EXPORT extern bool g_use_transparent_window; +} + namespace atom { namespace { @@ -88,6 +93,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents, const mate::Dictionary& options) : content::WebContentsObserver(web_contents), has_frame_(true), + transparent_(false), enable_larger_than_screen_(false), is_closed_(false), node_integration_(true), @@ -99,9 +105,14 @@ NativeWindow::NativeWindow(content::WebContents* web_contents, printing::PrintViewManagerBasic::CreateForWebContents(web_contents); options.Get(switches::kFrame, &has_frame_); + options.Get(switches::kTransparent, &transparent_); options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_); 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. options.Get(switches::kIcon, &icon_); @@ -560,6 +571,18 @@ content::JavaScriptDialogManager* NativeWindow::GetJavaScriptDialogManager() { 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, bool proceed, bool* proceed_to_fire_unload) { diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 06f7163862b56..0f3a8deb7be11 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -269,6 +269,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, void RendererResponsive(content::WebContents* source) override; // Implementations of content::WebContentsObserver. + void RenderViewCreated(content::RenderViewHost* render_view_host) override; void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; bool OnMessageReceived(const IPC::Message& message) override; @@ -287,6 +288,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, // Whether window has standard frame. bool has_frame_; + // Whether window is transparent. + bool transparent_; + // Whether window can be resized larger than screen. bool enable_larger_than_screen_; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 8567cccebf767..bbeb7a650c025 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -26,52 +26,52 @@ class NativeWindowMac : public NativeWindow { virtual ~NativeWindowMac(); // NativeWindow implementation. - virtual void Close() OVERRIDE; - virtual void CloseImmediately() OVERRIDE; - virtual void Move(const gfx::Rect& pos) OVERRIDE; - virtual void Focus(bool focus) OVERRIDE; - virtual bool IsFocused() OVERRIDE; - virtual void Show() OVERRIDE; - virtual void ShowInactive() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual bool IsVisible() OVERRIDE; - virtual void Maximize() OVERRIDE; - virtual void Unmaximize() OVERRIDE; - virtual bool IsMaximized() OVERRIDE; - virtual void Minimize() OVERRIDE; - virtual void Restore() OVERRIDE; - virtual bool IsMinimized() OVERRIDE; - virtual void SetFullScreen(bool fullscreen) OVERRIDE; - virtual bool IsFullscreen() OVERRIDE; - virtual void SetSize(const gfx::Size& size) OVERRIDE; - virtual gfx::Size GetSize() OVERRIDE; - virtual void SetContentSize(const gfx::Size& size) OVERRIDE; - virtual gfx::Size GetContentSize() OVERRIDE; - virtual void SetMinimumSize(const gfx::Size& size) OVERRIDE; - virtual gfx::Size GetMinimumSize() OVERRIDE; - virtual void SetMaximumSize(const gfx::Size& size) OVERRIDE; - virtual gfx::Size GetMaximumSize() OVERRIDE; - virtual void SetResizable(bool resizable) OVERRIDE; - virtual bool IsResizable() OVERRIDE; - virtual void SetAlwaysOnTop(bool top) OVERRIDE; - virtual bool IsAlwaysOnTop() OVERRIDE; - virtual void Center() OVERRIDE; - virtual void SetPosition(const gfx::Point& position) OVERRIDE; - virtual gfx::Point GetPosition() OVERRIDE; - virtual void SetTitle(const std::string& title) OVERRIDE; - virtual std::string GetTitle() OVERRIDE; - virtual void FlashFrame(bool flash) OVERRIDE; - virtual void SetSkipTaskbar(bool skip) OVERRIDE; - virtual void SetKiosk(bool kiosk) OVERRIDE; - virtual bool IsKiosk() OVERRIDE; - virtual void SetRepresentedFilename(const std::string& filename) OVERRIDE; - virtual std::string GetRepresentedFilename() OVERRIDE; - virtual void SetDocumentEdited(bool edited) OVERRIDE; - virtual bool IsDocumentEdited() OVERRIDE; - virtual bool HasModalDialog() OVERRIDE; - virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; - virtual void SetProgressBar(double progress) OVERRIDE; - virtual void ShowDefinitionForSelection() OVERRIDE; + void Close() override; + void CloseImmediately() override; + void Move(const gfx::Rect& pos) override; + void Focus(bool focus) override; + bool IsFocused() override; + void Show() override; + void ShowInactive() override; + void Hide() override; + bool IsVisible() override; + void Maximize() override; + void Unmaximize() override; + bool IsMaximized() override; + void Minimize() override; + void Restore() override; + bool IsMinimized() override; + void SetFullScreen(bool fullscreen) override; + bool IsFullscreen() override; + void SetSize(const gfx::Size& size) override; + gfx::Size GetSize() override; + void SetContentSize(const gfx::Size& size) override; + gfx::Size GetContentSize() override; + void SetMinimumSize(const gfx::Size& size) override; + gfx::Size GetMinimumSize() override; + void SetMaximumSize(const gfx::Size& size) override; + gfx::Size GetMaximumSize() override; + void SetResizable(bool resizable) override; + bool IsResizable() override; + void SetAlwaysOnTop(bool top) override; + bool IsAlwaysOnTop() override; + void Center() override; + void SetPosition(const gfx::Point& position) override; + gfx::Point GetPosition() override; + void SetTitle(const std::string& title) override; + std::string GetTitle() override; + void FlashFrame(bool flash) override; + void SetSkipTaskbar(bool skip) override; + void SetKiosk(bool kiosk) override; + bool IsKiosk() override; + void SetRepresentedFilename(const std::string& filename) override; + std::string GetRepresentedFilename() override; + void SetDocumentEdited(bool edited) override; + bool IsDocumentEdited() override; + bool HasModalDialog() override; + gfx::NativeWindow GetNativeWindow() override; + void SetProgressBar(double progress) override; + void ShowDefinitionForSelection() override; // Returns true if |point| in local Cocoa coordinate system falls within // the draggable region. @@ -83,23 +83,22 @@ class NativeWindowMac : public NativeWindow { // Clip web view to rounded corner. void ClipWebView(); - SkRegion* draggable_region() const { return draggable_region_.get(); } - protected: - virtual void UpdateDraggableRegions( - const std::vector& regions) OVERRIDE; + void UpdateDraggableRegions( + const std::vector& regions) override; // Implementations of content::WebContentsDelegate. - virtual void HandleKeyboardEvent( + void HandleKeyboardEvent( content::WebContents*, - const content::NativeWebKeyboardEvent&) OVERRIDE; + const content::NativeWebKeyboardEvent&) override; private: void InstallView(); void UninstallView(); - void InstallDraggableRegionViews(); - void UpdateDraggableRegionsForCustomDrag( - const std::vector& regions); + + // Install the drag view, which will cover the whole window and decides + // whehter we can drag. + void InstallDraggableRegionView(); base::scoped_nsobject window_; @@ -113,10 +112,6 @@ class NativeWindowMac : public NativeWindow { // The presentation options before entering kiosk mode. NSApplicationPresentationOptions kiosk_options_; - // For system drag, the whole window is draggable and the non-draggable areas - // have to been explicitly excluded. - std::vector system_drag_exclude_areas_; - // For custom drag, the whole window is non-draggable and the draggable region // has to been explicitly provided. scoped_ptr draggable_region_; // used in custom drag. diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 0f5b39ee5b332..f9c77597bd293 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -101,7 +101,7 @@ - (void)windowDidResignMain:(NSNotification*)notification { shell_->NotifyWindowBlur(); } -- (void)windowDidResize:(NSNotification*)otification { +- (void)windowDidResize:(NSNotification*)notification { if (!shell_->has_frame()) shell_->ClipWebView(); } @@ -280,6 +280,29 @@ - (void)drawRect:(NSRect)dirtyRect { 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& regions) { + SkRegion* sk_region = new SkRegion; + for (std::vector::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, const mate::Dictionary& options) : NativeWindow(web_contents, options), @@ -296,9 +319,7 @@ - (void)drawRect:(NSRect)dirtyRect { width, height); - AtomNSWindow* atomWindow; - - atomWindow = [[AtomNSWindow alloc] + AtomNSWindow* atomWindow = [[AtomNSWindow alloc] initWithContentRect:cocoa_bounds styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask | @@ -314,6 +335,13 @@ - (void)drawRect:(NSRect)dirtyRect { [[AtomNSWindowDelegate alloc] initWithShell:this]; [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. [window_ setReleasedWhenClosed:NO]; @@ -542,6 +570,10 @@ - (void)drawRect:(NSRect)dirtyRect { } 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)]; } @@ -659,7 +691,10 @@ - (void)drawRect:(NSRect)dirtyRect { bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const { if (!draggable_region_) 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]); // |draggable_region_| is stored in local platform-indepdent coordiate system // while |point| is in local Cocoa coordinate system. Do the conversion @@ -672,7 +707,6 @@ - (void)drawRect:(NSRect)dirtyRect { NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)]; NSPoint current_mouse_location = mouseRect.origin; - if ([event type] == NSLeftMouseDown) { NSPoint frame_origin = [window_ frame].origin; last_mouse_offset_ = NSMakePoint( @@ -691,8 +725,7 @@ - (void)drawRect:(NSRect)dirtyRect { if (has_frame_) return; - UpdateDraggableRegionsForCustomDrag(regions); - InstallDraggableRegionViews(); + draggable_region_.reset(DraggableRegionsToSkRegion(regions)); } void NativeWindowMac::HandleKeyboardEvent( @@ -749,11 +782,16 @@ - (void)drawRect:(NSRect)dirtyRect { } ClipWebView(); + InstallDraggableRegionView(); [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowMiniaturizeButton] 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)drawRect:(NSRect)dirtyRect { } 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(); - NSInteger webViewHeight = NSHeight([webView bounds]); - - // 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 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::const_iterator iter = - system_drag_exclude_areas_.begin(); - iter != system_drag_exclude_areas_.end(); - ++iter) { - base::scoped_nsobject controlRegion( - [[ControlRegionView alloc] initWithShellWindow:this]); - [controlRegion setFrame:NSMakeRect(iter->x(), - webViewHeight - iter->bottom(), - iter->width(), - iter->height())]; - [webView addSubview:controlRegion]; - } + webView.layer.masksToBounds = YES; + webView.layer.cornerRadius = kAtomWindowCornerRadius; } -void NativeWindowMac::UpdateDraggableRegionsForCustomDrag( - const std::vector& regions) { - // We still need one ControlRegionView to cover the whole window such that - // mouse events could be captured. - NSView* web_view = GetWebContents()->GetNativeView(); - gfx::Rect window_bounds( - 0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds])); - system_drag_exclude_areas_.clear(); - 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::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); +void NativeWindowMac::InstallDraggableRegionView() { + NSView* webView = GetWebContents()->GetNativeView(); + base::scoped_nsobject controlRegion( + [[ControlRegionView alloc] initWithShellWindow:this]); + [controlRegion setFrame:NSMakeRect(0, 0, + NSWidth([webView bounds]), + NSHeight([webView bounds]))]; + [webView addSubview:controlRegion]; } // static diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 52184e8620e98..9178b43eac64b 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -28,6 +28,7 @@ #include "ui/views/window/client_view.h" #include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/widget.h" +#include "ui/wm/core/shadow_types.h" #if defined(USE_X11) #include "atom/browser/browser.h" @@ -183,6 +184,9 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents, params.type = views::Widget::InitParams::TYPE_WINDOW; params.remove_standard_frame = !has_frame_; + if (transparent_) + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + #if defined(USE_X11) std::string name = Browser::Get()->GetName(); // Set WM_WINDOW_ROLE. @@ -237,8 +241,18 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents, // frameless. DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | 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); } + + 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 // 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(); } + // 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_->CenterWindow(bounds.size()); Layout(); diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index ea8baa848dc40..76cfad3319a6b 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -69,6 +69,9 @@ const char kGuestInstanceID[] = "guest-instance-id"; // Script that will be loaded by guest WebContents before other scripts. const char kPreloadScript[] = "preload"; +// Whether the window should be transparent. +const char kTransparent[] = "transparent"; + // Web runtime features. const char kExperimentalFeatures[] = "experimental-features"; const char kExperimentalCanvasFeatures[] = "experimental-canvas-features"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index f3b83f372e20c..a2cfb574dfcc1 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -39,6 +39,7 @@ extern const char kDirectWrite[]; extern const char kEnablePlugins[]; extern const char kGuestInstanceID[]; extern const char kPreloadScript[]; +extern const char kTransparent[]; extern const char kExperimentalFeatures[]; extern const char kExperimentalCanvasFeatures[];