Browse files

[Win] Implement main window with ui/views classes.

  • Loading branch information...
1 parent dcea43f commit 66aac85bafa11acee32d9e6475e52550cdc1e88d @zcbenz zcbenz committed Oct 14, 2012
Showing with 409 additions and 46 deletions.
  1. +354 −45 src/browser/native_window_win.cc
  2. +55 −1 src/browser/native_window_win.h
View
399 src/browser/native_window_win.cc
@@ -20,113 +20,262 @@
#include "content/nw/src/browser/native_window_win.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "base/win/wrapped_window_proc.h"
#include "content/nw/src/shell.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "ui/base/hit_test.h"
#include "ui/base/win/hwnd_util.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/non_client_view.h"
namespace nw {
namespace {
+const int kResizeInsideBoundsSize = 5;
+const int kResizeAreaCornerSize = 16;
-const wchar_t kWindowClass[] = L"NODE_WEBKIT";
+class NativeWindowFrameView : public views::NonClientFrameView {
+ public:
+ static const char kViewClassName[];
+
+ explicit NativeWindowFrameView(NativeWindowWin* window);
+ virtual ~NativeWindowFrameView();
+
+ void Init(views::Widget* frame);
+
+ // views::NonClientFrameView implementation.
+ 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 implementation.
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void Layout() OVERRIDE;
+ virtual std::string GetClassName() const OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetMaximumSize() OVERRIDE;
+
+ private:
+ NativeWindowWin* window_;
+ views::Widget* frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
+};
+
+const char NativeWindowFrameView::kViewClassName[] =
+ "content/nw/src/browser/NativeWindowFrameView";
+
+NativeWindowFrameView::NativeWindowFrameView(NativeWindowWin* window)
+ : window_(window),
+ frame_(NULL) {
+}
+
+NativeWindowFrameView::~NativeWindowFrameView() {
+}
+
+void NativeWindowFrameView::Init(views::Widget* frame) {
+ frame_ = frame;
+}
+
+gfx::Rect NativeWindowFrameView::GetBoundsForClientView() const {
+ return bounds();
+}
+
+gfx::Rect NativeWindowFrameView::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 NativeWindowFrameView::NonClientHitTest(const gfx::Point& point) {
+ if (frame_->IsFullscreen())
+ return HTCLIENT;
+
+ // 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;
+ int frame_component = GetHTComponentForFrame(point,
+ resize_border,
+ resize_border,
+ kResizeAreaCornerSize,
+ kResizeAreaCornerSize,
+ can_ever_resize);
+ if (frame_component != HTNOWHERE)
+ return frame_component;
+
+ // Check for possible draggable region in the client area for the frameless
+ // window.
+ if (window_->draggable_region() &&
+ window_->draggable_region()->contains(point.x(), point.y()))
+ return HTCAPTION;
+
+ int client_component = frame_->client_view()->NonClientHitTest(point);
+ if (client_component != HTNOWHERE)
+ return client_component;
+
+ // Caption is a safe default.
+ return HTCAPTION;
+}
+
+void NativeWindowFrameView::GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) {
+ // We got nothing to say about no window mask.
+}
+
+gfx::Size NativeWindowFrameView::GetPreferredSize() {
+ gfx::Size pref = frame_->client_view()->GetPreferredSize();
+ gfx::Rect bounds(0, 0, pref.width(), pref.height());
+ return frame_->non_client_view()->GetWindowBoundsForClientBounds(
+ bounds).size();
+}
+
+void NativeWindowFrameView::Layout() {
+}
+
+void NativeWindowFrameView::OnPaint(gfx::Canvas* canvas) {
+}
+
+std::string NativeWindowFrameView::GetClassName() const {
+ return kViewClassName;
+}
+
+gfx::Size NativeWindowFrameView::GetMinimumSize() {
+ return frame_->client_view()->GetMinimumSize();
+}
+
+gfx::Size NativeWindowFrameView::GetMaximumSize() {
+ return frame_->client_view()->GetMaximumSize();
+}
} // namespace
NativeWindowWin::NativeWindowWin(content::Shell* shell,
const base::DictionaryValue* manifest)
- : NativeWindow(shell, manifest) {
- window_ = CreateWindow(kWindowClass, L"node-webkit",
- WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
- CW_USEDEFAULT, 0,
- width, height,
- NULL, NULL, instance_handle_, NULL);
- ui::SetWindowUserData(window_, this);
- SetParent(web_contents_->GetView()->GetNativeView(), window_);
+ : NativeWindow(shell, manifest),
+ web_view_(NULL),
+ is_fullscreen_(false),
+ resizable_(true),
+ minimum_size_(0, 0),
+ maximum_size_(INT_MAX, INT_MAX) {
+ window_.reset(new views::Widget);
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+ params.delegate = this;
+ params.ownership = views::Widget::InitParams:WIDGET_OWNS_NATIVE_WIDGET;
+ params.remove_standard_frame = !has_frame();
+ params.use_system_default_icon = true;
+ window_->Init(params);
+
+ int width, height;
+ manifest->GetInteger(switches::kmWidth, &width);
+ manifest->GetInteger(switches::kmHeight, &height);
+
+ gfx::Rect window_bounds =
+ window_->non_client_view()->GetWindowBoundsForClientBounds(
+ gfx::Rect(width, height));
+ window_->SetBounds(window_bounds);
+
+ OnViewWasResized();
}
NativeWindowWin::~NativeWindowWin() {
}
void NativeWindowWin::Close() {
- DestroyWindow(window_);
+ window_->Close();
}
-void NativeWindowWin::Move(const gfx::Rect& pos) {
- SetWindowPos(window_, NULL, pos.x(), pos.y(), pos.width(), pos.height(),
- SWP_NOACTIVATE | SWP_NOZORDER);
+void NativeWindowWin::Move(const gfx::Rect& bounds) {
+ window_->SetBounds(bounds);
}
void NativeWindowWin::Focus(bool focus) {
- if (focus)
- SetFocus(window_);
+ window_->Activate();
}
void NativeWindowWin::Show() {
- ShowWindow(window_, SW_SHOW);
+ window_->Show();
}
void NativeWindowWin::Hide() {
- ShowWindow(window_, SW_HIDE);
+ window_->Hide();
}
void NativeWindowWin::Maximize() {
- ShowWindow(window_, SW_MAXIMIZE);
+ window_->Maximize();
}
void NativeWindowWin::Unmaximize() {
- ShowWindow(window_, SW_RESTORE);
+ window_->Restore();
}
void NativeWindowWin::Minimize() {
- ShowWindow(window_, SW_MINIMIZE);
+ window_->Minimize();
}
void NativeWindowWin::Restore() {
- ShowWindow(window_, SW_RESTORE);
+ window_->Restore();
}
void NativeWindowWin::SetFullscreen(bool fullscreen) {
+ is_fullscreen_ = fullscreen;
+ window_->SetFullscreen(fullscreen);
+ // TODO(jeremya) we need to call RenderViewHost::ExitFullscreen() if we
+ // ever drop the window out of fullscreen in response to something that
+ // wasn't the app calling webkitCancelFullScreen().
}
void NativeWindowWin::SetMinimumSize(int width, int height) {
- min_width_ = width;
- min_height_ = height;
+ minimum_size_.set_width(width);
+ minimum_size_.set_height(width);
}
void NativeWindowWin::SetMaximumSize(int width, int height) {
- max_width_ = width;
- max_height_ = height;
+ maximum_size_.set_width(width);
+ maximum_size_.set_height(width);
}
void NativeWindowWin::SetResizable(bool resizable) {
+ resizable_ = resizable;
}
void NativeWindowWin::SetPosition(const std::string& position) {
- RECT rc;
- GetWindowRect(window_, &rc);
- OffsetRect(&rc, -rc.left, -rc.top);
- int width = rc.right;
- int height = rc.bottom;
-
- int x, y;
- if (position == "center") {
- x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
- y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
- } else if (position == "mouse") {
- POINT point;
- GetCursorPos(&point);
- x = point.x - width / 2;
- y = point.y - height / 2;
- }
- MoveWindow(window_, x, y, width, height, FALSE);
+ if (position == "center")
+ window_->CenterWindow(window_->GetWindowBoundsInScreen());
}
void NativeWindowWin::FlashFrame(bool flash) {
+ window_->FlashFrame(flash);
}
void NativeWindowWin::SetTitle(const std::string& title) {
- string16 title_utf16 = UTF8ToUTF16(title);
- ::SetWindowText(window_, title_utf16.c_str());
+ title_ = title;
+ window_->UpdateWindowTitle();
}
void NativeWindowWin::AddToolbar() {
@@ -142,14 +291,174 @@ void NativeWindowWin::SetToolbarUrlEntry(const std::string& url) {
void NativeWindowWin::SetToolbarIsLoading(bool loading) {
}
+views::View* NativeWindowWin::GetContentsView() {
+ return this;
+}
+
+views::ClientView* NativeWindowWin::CreateClientView() {
+ // TODO
+ // Create a new clientview that handles CanClose.
+ return new ClientView(widget, GetContentsView());
+}
+
+views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
+ views::Widget* widget) {
+ NativeWindowFrameView* frame_view = new NativeWindowFrameView(this);
+ frame_view->Init(window_);
+ return frame_view;
+}
+
+bool NativeWindowWin::CanResize() const {
+ return resizable_;
+}
+
+bool NativeWindowWin::CanMaximize() const {
+ return true;
+}
+
+views::Widget* NativeWindowWin::GetWidget() {
+ return window_;
+}
+
+const views::Widget* NativeWindowWin::GetWidget() const {
+ return window_;
+}
+
+string16 NativeWindowWin::GetWindowTitle() const {
+ return UTF8ToUTF16(title_);
+}
+
+void NativeWindowWin::DeleteDelegate() {
+ delete shell();
+}
+
+bool NativeWindowWin::ShouldShowWindowTitle() const {
+ return has_frame();
+}
+
+gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
+ // TODO return icon from manifest here.
+ return gfx::ImageSkia();
+}
+
+gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
+ // TODO return icon from manifest here.
+ return gfx::ImageSkia();
+}
+
+views::View* NativeWindowWin::GetInitiallyFocusedView() {
+ return web_view_;
+}
+
void NativeWindowWin::UpdateDraggableRegions(
const std::vector<extensions::DraggableRegion>& regions) {
- LOG(ERROR) << "UpdateDraggableRegions";
+ // Draggable region is not supported for non-frameless window.
+ if (has_frame())
+ return;
+
+ SkRegion* draggable_region = new SkRegion;
+
+ // By default, the whole window is non-draggable. We need to explicitly
+ // include those draggable regions.
+ for (std::vector<extensions::DraggableRegion>::const_iterator iter =
+ regions.begin();
+ iter != regions.end(); ++iter) {
+ const extensions::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);
+ OnViewWasResized();
}
void NativeWindowWin::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
// no-op
}
+
+void NativeWindowWin::Layout() {
+ DCHECK(web_view_);
+ web_view_->SetBounds(0, 0, width(), height());
+ OnViewWasResized();
+}
+
+void NativeWindowWin::ViewHierarchyChanged(
+ bool is_add, views::View *parent, views::View *child) {
+ if (is_add && child == this) {
+ web_view_ = new views::WebView(NULL);
+ AddChildView(web_view_);
+ web_view_->SetWebContents(web_contents());
+ }
+}
+
+gfx::Size NativeWindowWin::GetMinimumSize() {
+ return minimum_size_;
+}
+
+gfx::Size NativeWindowWin::GetMaximumSize() {
+ return maximum_size_;
+}
+
+void NativeWindowWin::OnFocus() {
+ web_view_->RequestFocus();
+}
+
+void NativeWindowWin::SaveWindowPlacement(const gfx::Rect& bounds,
+ ui::WindowShowState show_state) {
+ // views::WidgetDelegate::SaveWindowPlacement(bounds, show_state);
+}
+void NativeWindowWin::OnViewWasResized() {
+ // Set the window shape of the RWHV.
+ DCHECK(window_);
+ DCHECK(web_view_);
+ gfx::Size sz = web_view_->size();
+ int height = sz.height(), width = sz.width();
+ int radius = 1;
+ gfx::Path path;
+ if (window_->IsMaximized() || window_->IsFullscreen()) {
+ // Don't round the corners when the window is maximized or fullscreen.
+ path.addRect(0, 0, width, height);
+ } else {
+ if (frameless_) {
+ path.moveTo(0, radius);
+ path.lineTo(radius, 0);
+ path.lineTo(width - radius, 0);
+ path.lineTo(width, radius);
+ } else {
+ // Don't round the top corners in chrome-style frame mode.
+ path.moveTo(0, 0);
+ path.lineTo(width, 0);
+ }
+ path.lineTo(width, height - radius - 1);
+ path.lineTo(width - radius - 1, height);
+ path.lineTo(radius + 1, height);
+ path.lineTo(0, height - radius - 1);
+ path.close();
+ }
+ SetWindowRgn(web_contents()->GetNativeView(), path.CreateNativeRegion(), 1);
+
+ SkRegion* rgn = new SkRegion;
+ if (!window_->IsFullscreen()) {
+ if (draggable_region())
+ rgn->op(*draggable_region(), SkRegion::kUnion_Op);
+ if (!window_->IsMaximized()) {
+ if (frameless_)
+ rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
+ rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
+ rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
+ SkRegion::kUnion_Op);
+ rgn->op(0, height - kResizeInsideBoundsSize, width, height,
+ SkRegion::kUnion_Op);
+ }
+ }
+ if (web_contents()->GetRenderViewHost()->GetView())
+ web_contents()->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
+}
+
} // namespace nw
View
56 src/browser/native_window_win.h
@@ -23,14 +23,26 @@
#include "content/nw/src/browser/native_window.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+class WebView;
+}
+
namespace nw {
-class NativeWindowWin : public NativeWindow {
+class NativeWindowWin : public NativeWindow,
+ public views::WidgetDelegateView {
public:
explicit NativeWindowWin(content::Shell* shell,
const base::DictionaryValue* manifest);
virtual ~NativeWindowWin();
+ SkRegion* draggable_region() { return draggable_region_.get(); }
+
// NativeWindow implementation.
virtual void Close() OVERRIDE;
virtual void Move(const gfx::Rect& pos) OVERRIDE;
@@ -53,6 +65,22 @@ class NativeWindowWin : public NativeWindow {
virtual void SetToolbarUrlEntry(const std::string& url) OVERRIDE;
virtual void SetToolbarIsLoading(bool loading) OVERRIDE;
+ // WidgetDelegate implementation.
+ virtual views::View* GetContentsView() OVERRIDE;
+ virtual views::ClientView* CreateClientView() OVERRIDE;
+ virtual views::NonClientFrameView* CreateNonClientFrameView(
+ views::Widget* widget) OVERRIDE;
+ virtual bool CanResize() const OVERRIDE;
+ virtual bool CanMaximize() const OVERRIDE;
+ virtual views::Widget* GetWidget() OVERRIDE;
+ virtual const views::Widget* GetWidget() const OVERRIDE;
+ virtual string16 GetWindowTitle() const OVERRIDE;
+ virtual void DeleteDelegate() OVERRIDE;
+ virtual views::View* GetInitiallyFocusedView() OVERRIDE;
+ virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
+ virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
+ virtual bool ShouldShowWindowTitle() const OVERRIDE;
+
protected:
// NativeWindow implementation.
virtual void AddToolbar() OVERRIDE;
@@ -61,7 +89,33 @@ class NativeWindowWin : public NativeWindow {
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
+ // views::View implementation.
+ virtual void Layout() OVERRIDE;
+ virtual void ViewHierarchyChanged(
+ bool is_add, views::View *parent, views::View *child) OVERRIDE;
+ virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetMaximumSize() OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+
+ // views::WidgetDelegate implementation.
+ virtual void SaveWindowPlacement(const gfx::Rect& bounds,
+ ui::WindowShowState show_state) OVERRIDE;
+
private:
+ friend class NativeWindowFrameView;
+
+ void OnViewWasResized();
+
+ views::WebView* web_view_;
+ scoped_ptr<views::Widget> window_;
+ bool is_fullscreen_;
+
+ scoped_ptr<SkRegion> draggable_region_;
+
+ bool resizable_;
+ std::string title_;
+ gfx::Size minimum_size_;
+ gfx::Size maximum_size_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowWin);
};

0 comments on commit 66aac85

Please sign in to comment.