diff --git a/atom.gyp b/atom.gyp index f2255e7b0e80..0ff53fc01a23 100644 --- a/atom.gyp +++ b/atom.gyp @@ -135,6 +135,8 @@ 'atom/browser/ui/tray_icon_cocoa.mm', 'atom/browser/ui/tray_icon_observer.h', 'atom/browser/ui/tray_icon_win.cc', + 'atom/browser/ui/views/frameless_view.cc', + 'atom/browser/ui/views/frameless_view.h', 'atom/browser/ui/views/global_menu_bar_x11.cc', 'atom/browser/ui/views/global_menu_bar_x11.h', 'atom/browser/ui/views/linux_frame_view.cc', diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 924d59a89f4b..d5e8ad851420 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -81,6 +81,9 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents, #if defined(USE_X11) // In X11 the window frame is drawn by the application. params.remove_standard_frame = true; +#elif defined(OS_WIN) + if (!has_frame_) + params.remove_standard_frame = true; #endif bool skip_taskbar = false; @@ -370,18 +373,16 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling( gfx::NativeView child, const gfx::Point& location) { // App window should claim mouse events that fall within the draggable region. - if (draggable_region_.get() && + if (draggable_region_ && draggable_region_->contains(location.x(), location.y())) return false; -#if defined(USE_X11) // And the events on border for dragging resizable frameless window. if (!has_frame_ && CanResize()) { - LinuxFrameView* frame = static_cast( + FramelessView* frame = static_cast( window_->non_client_view()->frame_view()); return frame->ResizingBorderHitTest(location) == HTNOWHERE; } -#endif return true; } @@ -394,13 +395,11 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView( views::Widget* widget) { #if defined(USE_X11) LinuxFrameView* frame_view = new LinuxFrameView; +#else defined(OS_WIN) + WinFrameView* frame_view = new WinFrameView; +#endif frame_view->Init(this, widget); return frame_view; -#elif defined(OS_WIN) - return new WinFrameView(widget); -#else - return NULL; -#endif } void NativeWindowViews::HandleKeyboardEvent( diff --git a/atom/browser/ui/views/frameless_view.cc b/atom/browser/ui/views/frameless_view.cc new file mode 100644 index 000000000000..f413899d3866 --- /dev/null +++ b/atom/browser/ui/views/frameless_view.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2014 GitHub, Inc. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/ui/views/frameless_view.h" + +#include "atom/browser/native_window_views.h" +#include "ui/aura/window.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace atom { + +namespace { + +const int kResizeInsideBoundsSize = 5; +const int kResizeAreaCornerSize = 16; +const char kViewClassName[] = "FramelessView"; + +} // namespace + +FramelessView::FramelessView() : window_(NULL), frame_(NULL) { +} + +FramelessView::~FramelessView() { +} + +void FramelessView::Init(NativeWindowViews* window, views::Widget* frame) { + window_ = window; + frame_ = frame; +} + +int FramelessView::ResizingBorderHitTest(const gfx::Point& point) { + // Check the frame first, as we allow a small area overlapping the contents + // to be used for resize handles. + bool can_ever_resize = frame_->widget_delegate() ? + frame_->widget_delegate()->CanResize() : + false; + // Don't allow overlapping resize handles when the window is maximized or + // fullscreen, as it can't be resized in those states. + int resize_border = + frame_->IsMaximized() || frame_->IsFullscreen() ? 0 : + kResizeInsideBoundsSize; + return GetHTComponentForFrame(point, resize_border, resize_border, + kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize); +} + +gfx::Rect FramelessView::GetBoundsForClientView() const { + return bounds(); +} + +gfx::Rect FramelessView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + gfx::Rect window_bounds = client_bounds; + // Enforce minimum size (1, 1) in case that client_bounds is passed with + // empty size. This could occur when the frameless window is being + // initialized. + if (window_bounds.IsEmpty()) { + window_bounds.set_width(1); + window_bounds.set_height(1); + } + return window_bounds; +} + +int FramelessView::NonClientHitTest(const gfx::Point& cursor) { + if (frame_->IsFullscreen()) + return HTCLIENT; + + // Check for possible draggable region in the client area for the frameless + // window. + SkRegion* draggable_region = window_->draggable_region(); + if (draggable_region && draggable_region->contains(cursor.x(), cursor.y())) + return HTCAPTION; + + // Support resizing frameless window by dragging the border. + int frame_component = ResizingBorderHitTest(cursor); + if (frame_component != HTNOWHERE) + return frame_component; + + return HTCLIENT; +} + +void FramelessView::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { +} + +void FramelessView::ResetWindowControls() { +} + +void FramelessView::UpdateWindowIcon() { +} + +void FramelessView::UpdateWindowTitle() { +} + +gfx::Size FramelessView::GetPreferredSize() { + return frame_->non_client_view()->GetWindowBoundsForClientBounds( + gfx::Rect(frame_->client_view()->GetPreferredSize())).size(); +} + +gfx::Size FramelessView::GetMinimumSize() { + return window_->GetMinimumSize(); +} + +gfx::Size FramelessView::GetMaximumSize() { + return window_->GetMaximumSize(); +} + +const char* FramelessView::GetClassName() const { + return kViewClassName; +} + +} // namespace atom diff --git a/atom/browser/ui/views/frameless_view.h b/atom/browser/ui/views/frameless_view.h new file mode 100644 index 000000000000..93b86f73774a --- /dev/null +++ b/atom/browser/ui/views/frameless_view.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014 GitHub, Inc. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_ +#define ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_ + +#include "ui/views/window/non_client_view.h" + +namespace views { +class Widget; +} + +namespace atom { + +class NativeWindowViews; + +class FramelessView : public views::NonClientFrameView { + public: + FramelessView(); + virtual ~FramelessView(); + + virtual void Init(NativeWindowViews* window, views::Widget* frame); + + // Returns whether the |point| is on frameless window's resizing border. + int ResizingBorderHitTest(const gfx::Point& point); + + protected: + // views::NonClientFrameView: + virtual gfx::Rect GetBoundsForClientView() const OVERRIDE; + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const OVERRIDE; + virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE; + virtual void GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) OVERRIDE; + virtual void ResetWindowControls() OVERRIDE; + virtual void UpdateWindowIcon() OVERRIDE; + virtual void UpdateWindowTitle() OVERRIDE; + + // Overridden from View: + virtual gfx::Size GetPreferredSize() OVERRIDE; + virtual gfx::Size GetMinimumSize() OVERRIDE; + virtual gfx::Size GetMaximumSize() OVERRIDE; + virtual const char* GetClassName() const OVERRIDE; + + // Not owned. + NativeWindowViews* window_; + views::Widget* frame_; + + private: + DISALLOW_COPY_AND_ASSIGN(FramelessView); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_ diff --git a/atom/browser/ui/views/linux_frame_view.cc b/atom/browser/ui/views/linux_frame_view.cc index 7832913657ee..b8c9265f1223 100644 --- a/atom/browser/ui/views/linux_frame_view.cc +++ b/atom/browser/ui/views/linux_frame_view.cc @@ -91,8 +91,7 @@ LinuxFrameView::~LinuxFrameView() { } void LinuxFrameView::Init(NativeWindowViews* window, views::Widget* frame) { - window_ = window; - frame_ = frame; + FramelessView::Init(window, frame); close_button_ = new views::ImageButton(this); close_button_->SetAccessibleName( diff --git a/atom/browser/ui/views/linux_frame_view.h b/atom/browser/ui/views/linux_frame_view.h index b1d8d7069f20..85ea975e3c1d 100644 --- a/atom/browser/ui/views/linux_frame_view.h +++ b/atom/browser/ui/views/linux_frame_view.h @@ -5,12 +5,10 @@ #ifndef ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_ #define ATOM_BROWSER_UI_VIEWS_LINUX_FRAME_VIEW_H_ -#include "base/basictypes.h" -#include "base/compiler_specific.h" +#include "atom/browser/ui/views/frameless_view.h" #include "base/memory/scoped_ptr.h" #include "ui/views/controls/button/button.h" #include "ui/views/window/frame_buttons.h" -#include "ui/views/window/non_client_view.h" namespace gfx { class ImageSkia; @@ -19,20 +17,17 @@ class ImageSkia; namespace views { class FrameBackground; class ImageButton; -class Widget; } namespace atom { -class NativeWindowViews; - -class LinuxFrameView : public views::NonClientFrameView, +class LinuxFrameView : public FramelessView public views::ButtonListener { public: LinuxFrameView(); virtual ~LinuxFrameView(); - void Init(NativeWindowViews* window, views::Widget* frame); + void Init(NativeWindowViews* window, views::Widget* frame) OVERRIDE; // Overridden from NonClientFrameView: virtual gfx::Rect GetBoundsForClientView() const OVERRIDE; @@ -123,10 +118,6 @@ class LinuxFrameView : public views::NonClientFrameView, // The layout rect of the title, if visible. gfx::Rect title_bounds_; - // Not owned. - NativeWindowViews* window_; - views::Widget* frame_; - // The icon of this window. May be NULL. views::ImageButton* window_icon_; diff --git a/atom/browser/ui/views/win_frame_view.cc b/atom/browser/ui/views/win_frame_view.cc index 0317ec83c26b..07932de91bd3 100644 --- a/atom/browser/ui/views/win_frame_view.cc +++ b/atom/browser/ui/views/win_frame_view.cc @@ -4,6 +4,7 @@ #include "atom/browser/ui/views/win_frame_view.h" +#include "atom/browser/native_window_views.h" #include "ui/views/widget/widget.h" #include "ui/views/win/hwnd_util.h" @@ -16,18 +17,13 @@ const char kViewClassName[] = "WinFrameView"; } // namespace -WinFrameView::WinFrameView(views::Widget* frame) - : frame_(frame) { +WinFrameView::WinFrameView() { } WinFrameView::~WinFrameView() { } -gfx::Rect WinFrameView::GetBoundsForClientView() const { - return gfx::Rect(0, 0, width(), height()); -} - gfx::Rect WinFrameView::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { gfx::Size size(client_bounds.size()); @@ -36,38 +32,10 @@ gfx::Rect WinFrameView::GetWindowBoundsForClientBounds( } int WinFrameView::NonClientHitTest(const gfx::Point& point) { - return frame_->client_view()->NonClientHitTest(point); -} - -void WinFrameView::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) { - // Nothing to do, we use the default window mask. -} - -void WinFrameView::ResetWindowControls() { - // Nothing to do. -} - -void WinFrameView::UpdateWindowIcon() { - // Nothing to do. -} - -void WinFrameView::UpdateWindowTitle() { - // Nothing to do. -} - -gfx::Size WinFrameView::GetPreferredSize() { - gfx::Size client_preferred_size = frame_->client_view()->GetPreferredSize(); - return frame_->non_client_view()->GetWindowBoundsForClientBounds( - gfx::Rect(client_preferred_size)).size(); -} - -gfx::Size WinFrameView::GetMinimumSize() { - return frame_->client_view()->GetMinimumSize(); -} - -gfx::Size WinFrameView::GetMaximumSize() { - return frame_->client_view()->GetMaximumSize(); + if (window_->has_frame()) + return frame_->client_view()->NonClientHitTest(point); + else + return FramelessView::NonClientHitTest(point); } const char* WinFrameView::GetClassName() const { diff --git a/atom/browser/ui/views/win_frame_view.h b/atom/browser/ui/views/win_frame_view.h index 499b0bbe0321..209a00a1da95 100644 --- a/atom/browser/ui/views/win_frame_view.h +++ b/atom/browser/ui/views/win_frame_view.h @@ -5,42 +5,26 @@ #ifndef ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_ #define ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_ -#include "ui/views/window/non_client_view.h" - -namespace views { -class Widget; -} +#include "atom/browser/ui/views/frameless_view.h" namespace atom { -class WinFrameView : public views::NonClientFrameView { +class WinFrameView : public FramelessView { public: - explicit WinFrameView(views::Widget* widget); + WinFrameView(); virtual ~WinFrameView(); // views::NonClientFrameView: - virtual gfx::Rect GetBoundsForClientView() const OVERRIDE; virtual gfx::Rect GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const OVERRIDE; virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE; - virtual void GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) OVERRIDE; - virtual void ResetWindowControls() OVERRIDE; - virtual void UpdateWindowIcon() OVERRIDE; - virtual void UpdateWindowTitle() OVERRIDE; // views::View: - virtual gfx::Size GetPreferredSize() OVERRIDE; - virtual gfx::Size GetMinimumSize() OVERRIDE; - virtual gfx::Size GetMaximumSize() OVERRIDE; virtual const char* GetClassName() const OVERRIDE; private: void ClientAreaSizeToWindowSize(gfx::Size* size) const; - // Our containing frame. - views::Widget* frame_; - DISALLOW_COPY_AND_ASSIGN(WinFrameView); };