Implement generic native window class.

This commit is contained in:
Cheng Zhao 2013-04-12 15:04:46 +08:00
Родитель a915cf2e81
Коммит c27cbaaaf9
8 изменённых файлов: 618 добавлений и 26 удалений

Просмотреть файл

@ -13,6 +13,12 @@
'browser/atom_browser_main_parts.cc', 'browser/atom_browser_main_parts.cc',
'browser/atom_browser_main_parts.h', 'browser/atom_browser_main_parts.h',
'browser/atom_browser_main_parts_mac.mm', 'browser/atom_browser_main_parts_mac.mm',
'browser/native_window.cc',
'browser/native_window.h',
'browser/native_window_mac.h',
'browser/native_window_mac.mm',
'common/options_switches.cc',
'common/options_switches.h',
'renderer/atom_render_view_observer.cc', 'renderer/atom_render_view_observer.cc',
'renderer/atom_render_view_observer.h', 'renderer/atom_render_view_observer.h',
'renderer/atom_renderer_client.cc', 'renderer/atom_renderer_client.cc',

Просмотреть файл

@ -4,8 +4,8 @@
#include "browser/atom_browser_main_parts.h" #include "browser/atom_browser_main_parts.h"
#import <AppKit/AppKit.h> #include "base/values.h"
#include "browser/native_window.h"
#include "brightray/browser/browser_context.h" #include "brightray/browser/browser_context.h"
#include "brightray/browser/default_web_contents_delegate.h" #include "brightray/browser/default_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents.h"
@ -16,32 +16,16 @@ namespace atom {
void AtomBrowserMainParts::PreMainMessageLoopRun() { void AtomBrowserMainParts::PreMainMessageLoopRun() {
brightray::BrowserMainParts::PreMainMessageLoopRun(); brightray::BrowserMainParts::PreMainMessageLoopRun();
auto contentRect = NSMakeRect(0, 0, 800, 600); scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue);
auto styleMask = NSTitledWindowMask | options->SetInteger("width", 800);
NSClosableWindowMask | options->SetInteger("height", 600);
NSMiniaturizableWindowMask | options->SetString("title", "Atom");
NSResizableWindowMask;
auto window = [[NSWindow alloc] initWithContentRect:contentRect
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:YES];
window.title = @"Atom";
// FIXME: We're leaking this object (see #3). // FIXME: Leak object here.
auto contents = brightray::InspectableWebContents::Create(content::WebContents::CreateParams(browser_context())); NativeWindow* window = NativeWindow::Create(browser_context(), options.get());
// FIXME: And this one! window->InitFromOptions(options.get());
contents->GetWebContents()->SetDelegate(
new brightray::DefaultWebContentsDelegate());
auto contentsView = contents->GetView()->GetNativeView();
contentsView.frame = [window.contentView bounds]; window->GetWebContents()->GetController().LoadURL(
contentsView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[window.contentView addSubview:contentsView];
[window makeFirstResponder:contentsView];
[window makeKeyAndOrderFront:nil];
contents->GetWebContents()->GetController().LoadURL(
GURL("http://adam.roben.org/brightray_example/start.html"), GURL("http://adam.roben.org/brightray_example/start.html"),
content::Referrer(), content::Referrer(),
content::PAGE_TRANSITION_AUTO_TOPLEVEL, content::PAGE_TRANSITION_AUTO_TOPLEVEL,

85
browser/native_window.cc Normal file
Просмотреть файл

@ -0,0 +1,85 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/native_window.h"
#include <string>
#include "base/values.h"
#include "brightray/browser/browser_context.h"
#include "brightray/browser/default_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "common/options_switches.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
namespace atom {
NativeWindow::NativeWindow(content::BrowserContext* browser_context,
base::DictionaryValue* options)
: inspectable_web_contents_(brightray::InspectableWebContents::Create(
content::WebContents::CreateParams(browser_context))) {
GetWebContents()->SetDelegate(new brightray::DefaultWebContentsDelegate());
}
NativeWindow::~NativeWindow() {
}
void NativeWindow::InitFromOptions(base::DictionaryValue* options) {
// Setup window from options.
int x, y;
std::string position;
if (options->GetInteger(switches::kX, &x) &&
options->GetInteger(switches::kY, &y)) {
int width, height;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
Move(gfx::Rect(x, y, width, height));
} else if (options->GetString(switches::kPosition, &position)) {
SetPosition(position);
}
int min_height, min_width;
if (options->GetInteger(switches::kMinHeight, &min_height) &&
options->GetInteger(switches::kMinWidth, &min_width)) {
SetMinimumSize(min_width, min_height);
}
int max_height, max_width;
if (options->GetInteger(switches::kMaxHeight, &max_height) &&
options->GetInteger(switches::kMaxWidth, &max_width)) {
SetMaximumSize(max_width, max_height);
}
bool resizable;
if (options->GetBoolean(switches::kResizable, &resizable)) {
SetResizable(resizable);
}
bool top;
if (options->GetBoolean(switches::kAlwaysOnTop, &top) && top) {
SetAlwaysOnTop(true);
}
bool fullscreen;
if (options->GetBoolean(switches::kFullscreen, &fullscreen) && fullscreen) {
SetFullscreen(true);
}
bool kiosk;
if (options->GetBoolean(switches::kKiosk, &kiosk) && kiosk) {
SetKiosk(kiosk);
}
std::string title("Atom Shell");
options->GetString(switches::kTitle, &title);
SetTitle(title);
// Then show it.
bool show = true;
options->GetBoolean(switches::kShow, &show);
if (show)
Show();
}
content::WebContents* NativeWindow::GetWebContents() const {
return inspectable_web_contents_->GetWebContents();
}
} // namespace atom

83
browser/native_window.h Normal file
Просмотреть файл

@ -0,0 +1,83 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_WINDOW_H_
#define ATOM_BROWSER_NATIVE_WINDOW_H_
#include <iosfwd>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
namespace base {
class DictionaryValue;
}
namespace brightray {
class InspectableWebContents;
}
namespace content {
class BrowserContext;
class WebContents;
}
namespace gfx {
class Point;
class Rect;
class Size;
}
namespace atom {
class NativeWindow {
public:
virtual ~NativeWindow();
static NativeWindow* Create(content::BrowserContext* browser_context,
base::DictionaryValue* options);
void InitFromOptions(base::DictionaryValue* options);
virtual void Close() = 0;
virtual void Move(const gfx::Rect& pos) = 0;
virtual void Focus(bool focus) = 0;
virtual void Show() = 0;
virtual void Hide() = 0;
virtual void Maximize() = 0;
virtual void Unmaximize() = 0;
virtual void Minimize() = 0;
virtual void Restore() = 0;
virtual void SetFullscreen(bool fullscreen) = 0;
virtual bool IsFullscreen() = 0;
virtual void SetSize(const gfx::Size& size) = 0;
virtual gfx::Size GetSize() = 0;
virtual void SetMinimumSize(int width, int height) = 0;
virtual void SetMaximumSize(int width, int height) = 0;
virtual void SetResizable(bool resizable) = 0;
virtual void SetAlwaysOnTop(bool top) = 0;
virtual void SetPosition(const std::string& position) = 0;
virtual void SetPosition(const gfx::Point& position) = 0;
virtual gfx::Point GetPosition() = 0;
virtual void SetTitle(const std::string& title) = 0;
virtual void FlashFrame(bool flash) = 0;
virtual void SetKiosk(bool kiosk) = 0;
virtual bool IsKiosk() = 0;
content::WebContents* GetWebContents() const;
protected:
explicit NativeWindow(content::BrowserContext* browser_context,
base::DictionaryValue* options);
private:
scoped_ptr<brightray::InspectableWebContents> inspectable_web_contents_;
DISALLOW_COPY_AND_ASSIGN(NativeWindow);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_H_

Просмотреть файл

@ -0,0 +1,71 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_WINDOW_MAC_H_
#define ATOM_BROWSER_NATIVE_WINDOW_MAC_H_
#import <Cocoa/Cocoa.h>
#include "base/memory/scoped_ptr.h"
#include "browser/native_window.h"
namespace atom {
class NativeWindowMac : public NativeWindow {
public:
explicit NativeWindowMac(content::BrowserContext* browser_context,
base::DictionaryValue* options);
virtual ~NativeWindowMac();
// NativeWindow implementation.
virtual void Close() OVERRIDE;
virtual void Move(const gfx::Rect& pos) OVERRIDE;
virtual void Focus(bool focus) OVERRIDE;
virtual void Show() OVERRIDE;
virtual void Hide() OVERRIDE;
virtual void Maximize() OVERRIDE;
virtual void Unmaximize() OVERRIDE;
virtual void Minimize() OVERRIDE;
virtual void Restore() 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 SetMinimumSize(int width, int height) OVERRIDE;
virtual void SetMaximumSize(int width, int height) OVERRIDE;
virtual void SetResizable(bool resizable) OVERRIDE;
virtual void SetAlwaysOnTop(bool top) OVERRIDE;
virtual void SetPosition(const std::string& position) OVERRIDE;
virtual void SetPosition(const gfx::Point& position) OVERRIDE;
virtual gfx::Point GetPosition() OVERRIDE;
virtual void SetTitle(const std::string& title) OVERRIDE;
virtual void FlashFrame(bool flash) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
void set_is_fullscreen(bool fullscreen) { is_fullscreen_ = fullscreen; }
NSWindow* window() const { return window_; }
protected:
void SetNonLionFullscreen(bool fullscreen);
private:
void InstallView();
void UninstallView();
NSWindow* window_;
bool is_fullscreen_;
bool is_kiosk_;
NSRect restored_bounds_;
NSInteger attention_request_id_; // identifier from requestUserAttention
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_MAC_H_

Просмотреть файл

@ -0,0 +1,289 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/native_window_mac.h"
// FIXME: The foundation_util.h is aborting our compilation, do not
// include it.
#define BASE_MAC_FOUNDATION_UTIL_H_
#include "base/mac/mac_util.h"
#include "base/sys_string_conversions.h"
#include "base/values.h"
#include "common/options_switches.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
namespace atom {
NativeWindowMac::NativeWindowMac(content::BrowserContext* browser_context,
base::DictionaryValue* options)
: NativeWindow(browser_context, options),
is_fullscreen_(false),
is_kiosk_(false),
attention_request_id_(0) {
int width, height;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect cocoa_bounds = NSMakeRect(
(NSWidth(main_screen_rect) - width) / 2,
(NSHeight(main_screen_rect) - height) / 2,
width,
height);
NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask;
window_ = [[NSWindow alloc] initWithContentRect:cocoa_bounds
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:YES];
// Disable fullscreen button when 'fullscreen' is specified to false.
bool fullscreen;
if (!(options->GetBoolean(switches::kFullscreen, &fullscreen) &&
!fullscreen)) {
NSUInteger collectionBehavior = [window() collectionBehavior];
collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
[window() setCollectionBehavior:collectionBehavior];
}
NSView* view = GetWebContents()->GetView()->GetNativeView();
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView();
}
NativeWindowMac::~NativeWindowMac() {
}
void NativeWindowMac::Close() {
[window() performClose:nil];
}
void NativeWindowMac::Move(const gfx::Rect& pos) {
NSRect cocoa_bounds = NSMakeRect(pos.x(), 0,
pos.width(),
pos.height());
// Flip coordinates based on the primary screen.
NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
cocoa_bounds.origin.y =
NSHeight([screen frame]) - pos.height() - pos.y();
[window() setFrame:cocoa_bounds display:YES];
}
void NativeWindowMac::Focus(bool focus) {
if (focus && [window() isVisible])
[window() makeKeyAndOrderFront:nil];
else
[window() orderBack:nil];
}
void NativeWindowMac::Show() {
[window() makeKeyAndOrderFront:nil];
}
void NativeWindowMac::Hide() {
[window() orderOut:nil];
}
void NativeWindowMac::Maximize() {
[window() zoom:nil];
}
void NativeWindowMac::Unmaximize() {
[window() zoom:nil];
}
void NativeWindowMac::Minimize() {
[window() miniaturize:nil];
}
void NativeWindowMac::Restore() {
[window() deminiaturize:nil];
}
void NativeWindowMac::SetFullscreen(bool fullscreen) {
if (fullscreen == is_fullscreen_)
return;
if (base::mac::IsOSLionOrLater()) {
is_fullscreen_ = fullscreen;
[window() toggleFullScreen:nil];
return;
}
DCHECK(base::mac::IsOSSnowLeopard());
SetNonLionFullscreen(fullscreen);
}
bool NativeWindowMac::IsFullscreen() {
return is_fullscreen_;
}
void NativeWindowMac::SetNonLionFullscreen(bool fullscreen) {
if (fullscreen == is_fullscreen_)
return;
is_fullscreen_ = fullscreen;
// Fade to black.
const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
bool did_fade_out = false;
CGDisplayFadeReservationToken token;
if (CGAcquireDisplayFadeReservation(kFadeDurationSeconds, &token) ==
kCGErrorSuccess) {
did_fade_out = true;
CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
}
// Since frameless windows insert the WebContentsView into the NSThemeFrame
// ([[window contentView] superview]), and since that NSThemeFrame is
// destroyed and recreated when we change the styleMask of the window, we
// need to remove the view from the window when we change the style, and
// add it back afterwards.
UninstallView();
if (fullscreen) {
restored_bounds_ = [window() frame];
[window() setStyleMask:NSBorderlessWindowMask];
[window() setFrame:[window()
frameRectForContentRect:[[window() screen] frame]]
display:YES];
base::mac::RequestFullScreen(base::mac::kFullScreenModeAutoHideAll);
} else {
base::mac::ReleaseFullScreen(base::mac::kFullScreenModeAutoHideAll);
NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask;
[window() setStyleMask:style_mask];
[window() setFrame:restored_bounds_ display:YES];
}
InstallView();
// Fade back in.
if (did_fade_out) {
CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, /*synchronous=*/false);
CGReleaseDisplayFadeReservation(token);
}
is_fullscreen_ = fullscreen;
}
void NativeWindowMac::SetSize(const gfx::Size& size) {
NSRect frame = [window_ frame];
frame.origin.y -= size.height() - frame.size.height;
frame.size.width = size.width();
frame.size.height = size.height();
[window() setFrame:frame display:YES];
}
gfx::Size NativeWindowMac::GetSize() {
NSRect frame = [window_ frame];
return gfx::Size(frame.size.width, frame.size.height);
}
void NativeWindowMac::SetMinimumSize(int width, int height) {
NSSize min_size = NSMakeSize(width, height);
NSView* content = [window() contentView];
[window() setContentMinSize:[content convertSize:min_size toView:nil]];
}
void NativeWindowMac::SetMaximumSize(int width, int height) {
NSSize max_size = NSMakeSize(width, height);
NSView* content = [window() contentView];
[window() setContentMaxSize:[content convertSize:max_size toView:nil]];
}
void NativeWindowMac::SetResizable(bool resizable) {
if (resizable) {
[[window() standardWindowButton:NSWindowZoomButton] setEnabled:YES];
[window() setStyleMask:window().styleMask | NSResizableWindowMask];
} else {
[[window() standardWindowButton:NSWindowZoomButton] setEnabled:NO];
[window() setStyleMask:window().styleMask ^ NSResizableWindowMask];
}
}
void NativeWindowMac::SetAlwaysOnTop(bool top) {
[window() setLevel:(top ? NSFloatingWindowLevel : NSNormalWindowLevel)];
}
void NativeWindowMac::SetPosition(const std::string& position) {
if (position == "center")
[window() center];
}
void NativeWindowMac::SetPosition(const gfx::Point& position) {
Move(gfx::Rect(position, GetSize()));
}
gfx::Point NativeWindowMac::GetPosition() {
NSRect frame = [window_ frame];
NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
return gfx::Point(frame.origin.x,
NSHeight([screen frame]) - frame.origin.y - frame.size.height);
}
void NativeWindowMac::SetTitle(const std::string& title) {
[window() setTitle:base::SysUTF8ToNSString(title)];
}
void NativeWindowMac::FlashFrame(bool flash) {
if (flash) {
attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest];
} else {
[NSApp cancelUserAttentionRequest:attention_request_id_];
attention_request_id_ = 0;
}
}
void NativeWindowMac::SetKiosk(bool kiosk) {
if (kiosk) {
NSApplicationPresentationOptions options =
NSApplicationPresentationHideDock +
NSApplicationPresentationHideMenuBar +
NSApplicationPresentationDisableAppleMenu +
NSApplicationPresentationDisableProcessSwitching +
NSApplicationPresentationDisableForceQuit +
NSApplicationPresentationDisableSessionTermination +
NSApplicationPresentationDisableHideApplication;
[NSApp setPresentationOptions:options];
is_kiosk_ = true;
SetNonLionFullscreen(true);
} else {
[NSApp setPresentationOptions:[NSApp currentSystemPresentationOptions]];
is_kiosk_ = false;
SetNonLionFullscreen(false);
}
}
bool NativeWindowMac::IsKiosk() {
return is_kiosk_;
}
void NativeWindowMac::InstallView() {
NSView* view = GetWebContents()->GetView()->GetNativeView();
[view setFrame:[[window() contentView] bounds]];
[[window() contentView] addSubview:view];
}
void NativeWindowMac::UninstallView() {
NSView* view = GetWebContents()->GetView()->GetNativeView();
[view removeFromSuperview];
}
// static
NativeWindow* NativeWindow::Create(content::BrowserContext* browser_context,
base::DictionaryValue* options) {
return new NativeWindowMac(browser_context, options);
}
} // namespace atom

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "common/options_switches.h"
namespace atom {
namespace switches {
const char kTitle[] = "title";
const char kToolbar[] = "toolbar";
const char kIcon[] = "icon";
const char kFrame[] = "frame";
const char kShow[] = "show";
const char kPosition[] = "position";
const char kX[] = "x";
const char kY[] = "y";
const char kWidth[] = "width";
const char kHeight[] = "height";
const char kMinWidth[] = "min_width";
const char kMinHeight[] = "min_height";
const char kMaxWidth[] = "max_width";
const char kMaxHeight[] = "max_height";
const char kResizable[] = "resizable";
const char kAsDesktop[] = "as_desktop";
const char kFullscreen[] = "fullscreen";
// Start with the kiosk mode, see Opera's page for description:
// http://www.opera.com/support/mastering/kiosk/
const char kKiosk[] = "kiosk";
// Make windows stays on the top of all other windows.
const char kAlwaysOnTop[] = "always-on-top";
} // namespace switches
} // namespace atom

36
common/options_switches.h Normal file
Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_OPTIONS_SWITCHES_
#define ATOM_COMMON_OPTIONS_SWITCHES_
namespace atom {
namespace switches {
extern const char kTitle[];
extern const char kToolbar[];
extern const char kIcon[];
extern const char kFrame[];
extern const char kShow[];
extern const char kPosition[];
extern const char kX[];
extern const char kY[];
extern const char kWidth[];
extern const char kHeight[];
extern const char kMinWidth[];
extern const char kMinHeight[];
extern const char kMaxWidth[];
extern const char kMaxHeight[];
extern const char kResizable[];
extern const char kAsDesktop[];
extern const char kFullscreen[];
extern const char kKiosk[];
extern const char kAlwaysOnTop[];
} // namespace switches
} // namespace atom
#endif // ATOM_COMMON_OPTIONS_SWITCHES_