Move all sources under atom/.

This commit is contained in:
Cheng Zhao 2014-03-16 08:30:26 +08:00
parent 26ddbbb0ee
commit 516d46444d
217 changed files with 519 additions and 519 deletions

View file

@ -0,0 +1,211 @@
// 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 "atom/browser/api/atom_api_app.h"
#include "base/values.h"
#include "base/command_line.h"
#include "atom/browser/browser.h"
#include "atom/common/v8/native_type_conversions.h"
#include "atom/common/v8/node_common.h"
namespace atom {
namespace api {
App::App(v8::Handle<v8::Object> wrapper)
: EventEmitter(wrapper) {
Browser::Get()->AddObserver(this);
}
App::~App() {
Browser::Get()->RemoveObserver(this);
}
void App::OnWillQuit(bool* prevent_default) {
*prevent_default = Emit("will-quit");
}
void App::OnWindowAllClosed() {
Emit("window-all-closed");
}
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
base::ListValue args;
args.AppendString(file_path);
*prevent_default = Emit("open-file", &args);
}
void App::OnOpenURL(const std::string& url) {
base::ListValue args;
args.AppendString(url);
Emit("open-url", &args);
}
void App::OnActivateWithNoOpenWindows() {
Emit("activate-with-no-open-windows");
}
void App::OnWillFinishLaunching() {
Emit("will-finish-launching");
}
void App::OnFinishLaunching() {
Emit("ready");
}
// static
void App::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new App(args.This());
}
// static
void App::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->Quit();
}
// static
void App::Exit(const v8::FunctionCallbackInfo<v8::Value>& args) {
exit(args[0]->IntegerValue());
}
// static
void App::Terminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->Terminate();
}
// static
void App::Focus(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->Focus();
}
// static
void App::GetVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(ToV8Value(Browser::Get()->GetVersion()));
}
// static
void App::SetVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string version;
if (!FromV8Arguments(args, &version))
return node::ThrowError("Bad argument");
Browser::Get()->SetVersion(version);
}
// static
void App::GetName(const v8::FunctionCallbackInfo<v8::Value>& args) {
return args.GetReturnValue().Set(ToV8Value(Browser::Get()->GetName()));
}
// static
void App::SetName(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string name;
if (!FromV8Arguments(args, &name))
return node::ThrowError("Bad argument");
Browser::Get()->SetName(name);
}
// static
void App::AppendSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string switch_string;
if (!FromV8Arguments(args, &switch_string))
return node::ThrowError("Bad argument");
if (args.Length() == 1) {
CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
} else {
std::string value = FromV8Value(args[1]);
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switch_string, value);
}
}
// static
void App::AppendArgument(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string value;
if (!FromV8Arguments(args, &value))
return node::ThrowError("Bad argument");
CommandLine::ForCurrentProcess()->AppendArg(value);
}
#if defined(OS_MACOSX)
// static
void App::DockBounce(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string type;
if (!FromV8Arguments(args, &type))
return node::ThrowError("Bad argument");
int request_id = -1;
if (type == "critical")
request_id = Browser::Get()->DockBounce(Browser::BOUNCE_CRITICAL);
else if (type == "informational")
request_id = Browser::Get()->DockBounce(Browser::BOUNCE_INFORMATIONAL);
else
return node::ThrowTypeError("Invalid bounce type");
args.GetReturnValue().Set(request_id);
}
// static
void App::DockCancelBounce(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->DockCancelBounce(FromV8Value(args[0]));
}
// static
void App::DockSetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->DockSetBadgeText(FromV8Value(args[0]));
}
// static
void App::DockGetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string text(Browser::Get()->DockGetBadgeText());
args.GetReturnValue().Set(ToV8Value(text));
}
#endif // defined(OS_MACOSX)
// static
void App::Initialize(v8::Handle<v8::Object> target) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("Application"));
NODE_SET_PROTOTYPE_METHOD(t, "quit", Quit);
NODE_SET_PROTOTYPE_METHOD(t, "exit", Exit);
NODE_SET_PROTOTYPE_METHOD(t, "terminate", Terminate);
NODE_SET_PROTOTYPE_METHOD(t, "focus", Focus);
NODE_SET_PROTOTYPE_METHOD(t, "getVersion", GetVersion);
NODE_SET_PROTOTYPE_METHOD(t, "setVersion", SetVersion);
NODE_SET_PROTOTYPE_METHOD(t, "getName", GetName);
NODE_SET_PROTOTYPE_METHOD(t, "setName", SetName);
target->Set(v8::String::NewSymbol("Application"), t->GetFunction());
NODE_SET_METHOD(target, "appendSwitch", AppendSwitch);
NODE_SET_METHOD(target, "appendArgument", AppendArgument);
#if defined(OS_MACOSX)
NODE_SET_METHOD(target, "dockBounce", DockBounce);
NODE_SET_METHOD(target, "dockCancelBounce", DockCancelBounce);
NODE_SET_METHOD(target, "dockSetBadgeText", DockSetBadgeText);
NODE_SET_METHOD(target, "dockGetBadgeText", DockGetBadgeText);
#endif // defined(OS_MACOSX)
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_app, atom::api::App::Initialize)

View file

@ -0,0 +1,64 @@
// 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_API_ATOM_API_APP_H_
#define ATOM_BROWSER_API_ATOM_API_APP_H_
#include "base/compiler_specific.h"
#include "atom/browser/browser_observer.h"
#include "atom/common/api/atom_api_event_emitter.h"
namespace atom {
namespace api {
class App : public EventEmitter,
public BrowserObserver {
public:
virtual ~App();
static void Initialize(v8::Handle<v8::Object> target);
protected:
explicit App(v8::Handle<v8::Object> wrapper);
// BrowserObserver implementations:
virtual void OnWillQuit(bool* prevent_default) OVERRIDE;
virtual void OnWindowAllClosed() OVERRIDE;
virtual void OnOpenFile(bool* prevent_default,
const std::string& file_path) OVERRIDE;
virtual void OnOpenURL(const std::string& url) OVERRIDE;
virtual void OnActivateWithNoOpenWindows() OVERRIDE;
virtual void OnWillFinishLaunching() OVERRIDE;
virtual void OnFinishLaunching() OVERRIDE;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Exit(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Terminate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetVersion(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetVersion(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetName(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetName(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AppendSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AppendArgument(const v8::FunctionCallbackInfo<v8::Value>& args);
#if defined(OS_MACOSX)
static void DockBounce(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DockCancelBounce(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DockSetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DockGetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args);
#endif // defined(OS_MACOSX)
DISALLOW_COPY_AND_ASSIGN(App);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_APP_H_

View file

@ -0,0 +1,106 @@
// 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 "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h"
#include "base/values.h"
#include "atom/browser/auto_updater.h"
#include "atom/common/v8/native_type_conversions.h"
#include "atom/common/v8/node_common.h"
namespace atom {
namespace api {
AutoUpdater::AutoUpdater(v8::Handle<v8::Object> wrapper)
: EventEmitter(wrapper) {
auto_updater::AutoUpdater::SetDelegate(this);
}
AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(NULL);
}
void AutoUpdater::OnError(const std::string& error) {
base::ListValue args;
args.AppendString(error);
Emit("error", &args);
}
void AutoUpdater::OnCheckingForUpdate() {
Emit("checking-for-update");
}
void AutoUpdater::OnUpdateAvailable() {
Emit("update-available");
}
void AutoUpdater::OnUpdateNotAvailable() {
Emit("update-not-available");
}
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {
quit_and_install_ = quit_and_install;
base::ListValue args;
args.AppendString(release_notes);
args.AppendString(release_name);
args.AppendDouble(release_date.ToJsTime());
args.AppendString(update_url);
Emit("update-downloaded-raw", &args);
}
// static
void AutoUpdater::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new AutoUpdater(args.This());
}
// static
void AutoUpdater::SetFeedURL(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::SetFeedURL(FromV8Value(args[0]));
}
// static
void AutoUpdater::CheckForUpdates(
const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::CheckForUpdates();
}
// static
void AutoUpdater::QuitAndInstall(
const v8::FunctionCallbackInfo<v8::Value>& args) {
AutoUpdater* self = AutoUpdater::Unwrap<AutoUpdater>(args.This());
if (!self->quit_and_install_.is_null())
self->quit_and_install_.Run();
}
// static
void AutoUpdater::Initialize(v8::Handle<v8::Object> target) {
v8::Local<v8::FunctionTemplate> t(
v8::FunctionTemplate::New(AutoUpdater::New));
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("AutoUpdater"));
NODE_SET_PROTOTYPE_METHOD(t, "setFeedUrl", SetFeedURL);
NODE_SET_PROTOTYPE_METHOD(t, "checkForUpdates", CheckForUpdates);
NODE_SET_PROTOTYPE_METHOD(t, "quitAndInstall", QuitAndInstall);
target->Set(v8::String::NewSymbol("AutoUpdater"), t->GetFunction());
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_auto_updater, atom::api::AutoUpdater::Initialize)

View file

@ -0,0 +1,57 @@
// 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_API_ATOM_API_AUTO_UPDATER_H_
#define ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "atom/browser/auto_updater_delegate.h"
#include "atom/common/api/atom_api_event_emitter.h"
namespace atom {
namespace api {
class AutoUpdater : public EventEmitter,
public auto_updater::AutoUpdaterDelegate {
public:
virtual ~AutoUpdater();
static void Initialize(v8::Handle<v8::Object> target);
protected:
explicit AutoUpdater(v8::Handle<v8::Object> wrapper);
// AutoUpdaterDelegate implementations.
virtual void OnError(const std::string& error) OVERRIDE;
virtual void OnCheckingForUpdate() OVERRIDE;
virtual void OnUpdateAvailable() OVERRIDE;
virtual void OnUpdateNotAvailable() OVERRIDE;
virtual void OnUpdateDownloaded(
const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) OVERRIDE;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetFeedURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CheckForUpdates(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ContinueUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void QuitAndInstall(const v8::FunctionCallbackInfo<v8::Value>& args);
base::Closure quit_and_install_;
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_

View file

@ -0,0 +1,48 @@
// 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 "atom/browser/api/atom_api_browser_ipc.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/v8/node_common.h"
#include "atom/common/v8/native_type_conversions.h"
#include "content/public/browser/render_view_host.h"
using content::RenderViewHost;
namespace atom {
namespace api {
// static
void BrowserIPC::Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
string16 channel;
int process_id, routing_id;
scoped_ptr<base::Value> arguments;
if (!FromV8Arguments(args, &channel, &process_id, &routing_id, &arguments))
return node::ThrowTypeError("Bad argument");
DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST));
RenderViewHost* render_view_host(RenderViewHost::FromID(
process_id, routing_id));
if (!render_view_host)
return node::ThrowError("Invalid render view host");
args.GetReturnValue().Set(render_view_host->Send(new AtomViewMsg_Message(
routing_id,
channel,
*static_cast<base::ListValue*>(arguments.get()))));
}
// static
void BrowserIPC::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_METHOD(target, "send", Send);
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_ipc, atom::api::BrowserIPC::Initialize)

View file

@ -0,0 +1,29 @@
// 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_API_ATOM_API_BROWSER_IPC_H_
#define ATOM_BROWSER_API_ATOM_API_BROWSER_IPC_H_
#include "base/basictypes.h"
#include "v8/include/v8.h"
namespace atom {
namespace api {
class BrowserIPC {
public:
static void Initialize(v8::Handle<v8::Object> target);
private:
static void Send(const v8::FunctionCallbackInfo<v8::Value>& args);
DISALLOW_IMPLICIT_CONSTRUCTORS(BrowserIPC);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_BROWSER_IPC_H_

View file

@ -0,0 +1,141 @@
// 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 "atom/browser/api/atom_api_dialog.h"
#include "base/bind.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
#include "atom/browser/ui/message_box.h"
#include "atom/common/v8/node_common.h"
#include "atom/common/v8/native_type_conversions.h"
namespace atom {
namespace api {
namespace {
template<typename T>
void CallV8Function(const RefCountedV8Function& callback, T arg) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> value = ToV8Value(arg);
callback->NewHandle(node_isolate)->Call(
v8::Context::GetCurrent()->Global(), 1, &value);
}
template<typename T>
void CallV8Function2(const RefCountedV8Function& callback, bool result, T arg) {
if (result)
return CallV8Function<T>(callback, arg);
else
return CallV8Function<void*>(callback, NULL);
}
void Initialize(v8::Handle<v8::Object> target) {
NODE_SET_METHOD(target, "showMessageBox", ShowMessageBox);
NODE_SET_METHOD(target, "showOpenDialog", ShowOpenDialog);
NODE_SET_METHOD(target, "showSaveDialog", ShowSaveDialog);
}
} // namespace
void ShowMessageBox(const v8::FunctionCallbackInfo<v8::Value>& args) {
int type;
std::vector<std::string> buttons;
std::string title, message, detail;
if (!FromV8Arguments(args, &type, &buttons, &title, &message, &detail))
return node::ThrowTypeError("Bad argument");
NativeWindow* native_window = FromV8Value(args[5]);
if (!args[6]->IsFunction()) {
int chosen = atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail);
args.GetReturnValue().Set(chosen);
} else {
RefCountedV8Function callback = FromV8Value(args[6]);
atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail,
base::Bind(&CallV8Function<int>, callback));
}
}
void ShowOpenDialog(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string title;
base::FilePath default_path;
int properties;
if (!FromV8Arguments(args, &title, &default_path, &properties))
return node::ThrowTypeError("Bad argument");
NativeWindow* native_window = FromV8Value(args[3]);
if (!args[4]->IsFunction()) {
std::vector<base::FilePath> paths;
if (!file_dialog::ShowOpenDialog(native_window,
title,
default_path,
properties,
&paths))
return;
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
for (size_t i = 0; i < paths.size(); ++i)
result->Set(i, ToV8Value(paths[i]));
args.GetReturnValue().Set(result);
} else {
RefCountedV8Function callback = FromV8Value(args[4]);
file_dialog::ShowOpenDialog(
native_window,
title,
default_path,
properties,
base::Bind(&CallV8Function2<const std::vector<base::FilePath>&>,
callback));
}
}
void ShowSaveDialog(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string title;
base::FilePath default_path;
if (!FromV8Arguments(args, &title, &default_path))
return node::ThrowTypeError("Bad argument");
NativeWindow* native_window = FromV8Value(args[2]);
if (!args[3]->IsFunction()) {
base::FilePath path;
if (file_dialog::ShowSaveDialog(native_window,
title,
default_path,
&path))
args.GetReturnValue().Set(ToV8Value(path));
} else {
RefCountedV8Function callback = FromV8Value(args[3]);
file_dialog::ShowSaveDialog(
native_window,
title,
default_path,
base::Bind(&CallV8Function2<const base::FilePath&>, callback));
}
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_dialog, atom::api::Initialize)

View file

@ -0,0 +1,22 @@
// 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_API_ATOM_API_DIALOG_H_
#define ATOM_BROWSER_API_ATOM_API_DIALOG_H_
#include "v8/include/v8.h"
namespace atom {
namespace api {
void ShowMessageBox(const v8::FunctionCallbackInfo<v8::Value>& args);
void ShowOpenDialog(const v8::FunctionCallbackInfo<v8::Value>& args);
void ShowSaveDialog(const v8::FunctionCallbackInfo<v8::Value>& args);
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_DIALOG_H_

View file

@ -0,0 +1,100 @@
// 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 "atom/browser/api/atom_api_event.h"
#include "atom/browser/native_window.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/v8/node_common.h"
#include "atom/common/v8/native_type_conversions.h"
namespace atom {
namespace api {
ScopedPersistent<v8::Function> Event::constructor_template_;
Event::Event()
: sender_(NULL),
message_(NULL),
prevent_default_(false) {
}
Event::~Event() {
if (sender_ != NULL)
sender_->RemoveObserver(this);
}
// static
v8::Handle<v8::Object> Event::CreateV8Object() {
if (constructor_template_.IsEmpty()) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("Event"));
NODE_SET_PROTOTYPE_METHOD(t, "preventDefault", PreventDefault);
NODE_SET_PROTOTYPE_METHOD(t, "sendReply", SendReply);
NODE_SET_PROTOTYPE_METHOD(t, "destroy", Destroy);
constructor_template_.reset(t->GetFunction());
}
v8::Handle<v8::Function> t = constructor_template_.NewHandle(node_isolate);
return t->NewInstance(0, NULL);
}
void Event::SetSenderAndMessage(NativeWindow* sender, IPC::Message* message) {
DCHECK(!sender_);
DCHECK(!message_);
sender_ = sender;
message_ = message;
sender_->AddObserver(this);
}
void Event::OnWindowClosed() {
sender_ = NULL;
message_ = NULL;
}
// static
void Event::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
Event* event = new Event;
event->Wrap(args.This());
}
// static
void Event::PreventDefault(const v8::FunctionCallbackInfo<v8::Value>& args) {
Event* event = Unwrap<Event>(args.This());
if (event == NULL)
return node::ThrowError("Event is already destroyed");
event->prevent_default_ = true;
}
// static
void Event::SendReply(const v8::FunctionCallbackInfo<v8::Value>& args) {
Event* event = Unwrap<Event>(args.This());
if (event == NULL)
return node::ThrowError("Event is already destroyed");
if (event->message_ == NULL || event->sender_ == NULL)
return node::ThrowError("Can only send reply to synchronous events");
string16 json = FromV8Value(args[0]);
AtomViewHostMsg_Message_Sync::WriteReplyParams(event->message_, json);
event->sender_->Send(event->message_);
delete event;
}
// static
void Event::Destroy(const v8::FunctionCallbackInfo<v8::Value>& args) {
delete Unwrap<Event>(args.This());
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,67 @@
// 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_ATOM_API_EVENT_H_
#define ATOM_BROWSER_ATOM_API_EVENT_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
#include "atom/browser/native_window_observer.h"
#include "atom/common/v8/scoped_persistent.h"
#include "vendor/node/src/node_object_wrap.h"
namespace IPC {
class Message;
}
namespace atom {
class NativeWindow;
namespace api {
class Event : public node::ObjectWrap,
public NativeWindowObserver {
public:
virtual ~Event();
// Create a V8 Event object.
static v8::Handle<v8::Object> CreateV8Object();
// Pass the sender and message to be replied.
void SetSenderAndMessage(NativeWindow* sender, IPC::Message* message);
// Whether event.preventDefault() is called.
bool prevent_default() const { return prevent_default_; }
protected:
Event();
// NativeWindowObserver implementations:
virtual void OnWindowClosed() OVERRIDE;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PreventDefault(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SendReply(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);
static ScopedPersistent<v8::Function> constructor_template_;
// Replyer for the synchronous messages.
NativeWindow* sender_;
IPC::Message* message_;
bool prevent_default_;
DISALLOW_COPY_AND_ASSIGN(Event);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_ATOM_API_EVENT_H_

View file

@ -0,0 +1,360 @@
// 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 "atom/browser/api/atom_api_menu.h"
#include "atom/browser/ui/accelerator_util.h"
#include "atom/common/v8/node_common.h"
#include "atom/common/v8/native_type_conversions.h"
#define UNWRAP_MEMNU_AND_CHECK \
Menu* self = ObjectWrap::Unwrap<Menu>(args.This()); \
if (self == NULL) \
return node::ThrowError("Menu is already destroyed")
namespace atom {
namespace api {
namespace {
// Call method of delegate object.
v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
v8::Handle<v8::Object> menu,
const char* method,
int command_id) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> delegate = menu->Get(v8::String::New("delegate"));
if (!delegate->IsObject())
return default_value;
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(
delegate->ToObject()->Get(v8::String::New(method)));
if (!function->IsFunction())
return default_value;
v8::Handle<v8::Value> argv = v8::Integer::New(command_id);
return handle_scope.Close(
function->Call(v8::Context::GetCurrent()->Global(), 1, &argv));
}
} // namespace
Menu::Menu(v8::Handle<v8::Object> wrapper)
: EventEmitter(wrapper),
model_(new ui::SimpleMenuModel(this)) {
}
Menu::~Menu() {
}
bool Menu::IsCommandIdChecked(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::False(),
const_cast<Menu*>(this)->handle(),
"isCommandIdChecked",
command_id)->BooleanValue();
}
bool Menu::IsCommandIdEnabled(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::True(),
const_cast<Menu*>(this)->handle(),
"isCommandIdEnabled",
command_id)->BooleanValue();
}
bool Menu::IsCommandIdVisible(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::True(),
const_cast<Menu*>(this)->handle(),
"isCommandIdVisible",
command_id)->BooleanValue();
}
bool Menu::GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> shortcut = CallDelegate(v8::Undefined(),
handle(),
"getAcceleratorForCommandId",
command_id);
if (shortcut->IsString()) {
std::string shortcut_str = FromV8Value(shortcut);
return accelerator_util::StringToAccelerator(shortcut_str, accelerator);
}
return false;
}
bool Menu::IsItemForCommandIdDynamic(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::False(),
const_cast<Menu*>(this)->handle(),
"isItemForCommandIdDynamic",
command_id)->BooleanValue();
}
string16 Menu::GetLabelForCommandId(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return FromV8Value(CallDelegate(v8::False(),
const_cast<Menu*>(this)->handle(),
"getLabelForCommandId",
command_id));
}
string16 Menu::GetSublabelForCommandId(int command_id) const {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
return FromV8Value(CallDelegate(v8::False(),
const_cast<Menu*>(this)->handle(),
"getSubLabelForCommandId",
command_id));
}
void Menu::ExecuteCommand(int command_id, int event_flags) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
CallDelegate(v8::False(), handle(), "executeCommand", command_id);
}
// static
void Menu::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
Menu::Create(args.This());
}
// static
void Menu::InsertItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument");
if (index < 0)
self->model_->AddItem(command_id, label);
else
self->model_->InsertItemAt(index, command_id, label);
}
// static
void Menu::InsertCheckItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument");
if (index < 0)
self->model_->AddCheckItem(command_id, label);
else
self->model_->InsertCheckItemAt(index, command_id, label);
}
// static
void Menu::InsertRadioItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index, command_id, group_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label, &group_id))
return node::ThrowTypeError("Bad argument");
if (index < 0)
self->model_->AddRadioItem(command_id, label, group_id);
else
self->model_->InsertRadioItemAt(index, command_id, label, group_id);
}
// static
void Menu::InsertSeparator(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index;
if (!FromV8Arguments(args, &index))
return node::ThrowTypeError("Bad argument");
if (index < 0)
self->model_->AddSeparator(ui::NORMAL_SEPARATOR);
else
self->model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR);
}
// static
void Menu::InsertSubMenu(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument");
Menu* submenu = ObjectWrap::Unwrap<Menu>(args[3]->ToObject());
if (!submenu)
return node::ThrowTypeError("The submenu is already destroyed");
if (index < 0)
self->model_->AddSubMenu(command_id, label, submenu->model_.get());
else
self->model_->InsertSubMenuAt(
index, command_id, label, submenu->model_.get());
}
// static
void Menu::SetIcon(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index;
base::FilePath path;
if (!FromV8Arguments(args, &index, &path))
return node::ThrowTypeError("Bad argument");
// FIXME use webkit_glue's image decoder here.
}
// static
void Menu::SetSublabel(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index;
string16 label;
if (!FromV8Arguments(args, &index, &label))
return node::ThrowTypeError("Bad argument");
self->model_->SetSublabel(index, label);
}
// static
void Menu::Clear(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
self->model_->Clear();
}
// static
void Menu::GetIndexOfCommandId(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->GetIndexOfCommandId(index));
}
// static
void Menu::GetItemCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
args.GetReturnValue().Set(self->model_->GetItemCount());
}
// static
void Menu::GetCommandIdAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->GetCommandIdAt(index));
}
// static
void Menu::GetLabelAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(ToV8Value(self->model_->GetLabelAt(index)));
}
// static
void Menu::GetSublabelAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(ToV8Value(self->model_->GetSublabelAt(index)));
}
// static
void Menu::IsItemCheckedAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->IsItemCheckedAt(index));
}
// static
void Menu::IsEnabledAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->IsEnabledAt(index));
}
// static
void Menu::IsVisibleAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->IsVisibleAt(index));
}
// static
void Menu::Popup(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
atom::NativeWindow* window;
if (!FromV8Arguments(args, &window))
return node::ThrowTypeError("Bad argument");
self->Popup(window);
}
// static
void Menu::Initialize(v8::Handle<v8::Object> target) {
v8::Local<v8::FunctionTemplate> t(v8::FunctionTemplate::New(Menu::New));
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("Menu"));
NODE_SET_PROTOTYPE_METHOD(t, "insertItem", InsertItem);
NODE_SET_PROTOTYPE_METHOD(t, "insertCheckItem", InsertCheckItem);
NODE_SET_PROTOTYPE_METHOD(t, "insertRadioItem", InsertRadioItem);
NODE_SET_PROTOTYPE_METHOD(t, "insertSeparator", InsertSeparator);
NODE_SET_PROTOTYPE_METHOD(t, "insertSubMenu", InsertSubMenu);
NODE_SET_PROTOTYPE_METHOD(t, "setIcon", SetIcon);
NODE_SET_PROTOTYPE_METHOD(t, "setSublabel", SetSublabel);
NODE_SET_PROTOTYPE_METHOD(t, "clear", Clear);
NODE_SET_PROTOTYPE_METHOD(t, "getIndexOfCommandId", GetIndexOfCommandId);
NODE_SET_PROTOTYPE_METHOD(t, "getItemCount", GetItemCount);
NODE_SET_PROTOTYPE_METHOD(t, "getCommandIdAt", GetCommandIdAt);
NODE_SET_PROTOTYPE_METHOD(t, "getLabelAt", GetLabelAt);
NODE_SET_PROTOTYPE_METHOD(t, "getSublabelAt", GetSublabelAt);
NODE_SET_PROTOTYPE_METHOD(t, "isItemCheckedAt", IsItemCheckedAt);
NODE_SET_PROTOTYPE_METHOD(t, "isEnabledAt", IsEnabledAt);
NODE_SET_PROTOTYPE_METHOD(t, "isVisibleAt", IsVisibleAt);
NODE_SET_PROTOTYPE_METHOD(t, "popup", Popup);
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
NODE_SET_PROTOTYPE_METHOD(t, "attachToWindow", AttachToWindow);
#endif
target->Set(v8::String::NewSymbol("Menu"), t->GetFunction());
#if defined(OS_MACOSX)
NODE_SET_METHOD(target, "setApplicationMenu", SetApplicationMenu);
NODE_SET_METHOD(
target, "sendActionToFirstResponder", SendActionToFirstResponder);
#endif
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_menu, atom::api::Menu::Initialize)

View file

@ -0,0 +1,88 @@
// 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_API_ATOM_API_MENU_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_H_
#include "base/memory/scoped_ptr.h"
#include "atom/common/api/atom_api_event_emitter.h"
#include "ui/base/models/simple_menu_model.h"
namespace atom {
class NativeWindow;
namespace api {
class Menu : public EventEmitter,
public ui::SimpleMenuModel::Delegate {
public:
virtual ~Menu();
static Menu* Create(v8::Handle<v8::Object> wrapper);
static void Initialize(v8::Handle<v8::Object> target);
protected:
explicit Menu(v8::Handle<v8::Object> wrapper);
// ui::SimpleMenuModel::Delegate implementations:
virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
virtual bool IsCommandIdVisible(int command_id) const OVERRIDE;
virtual bool GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* accelerator) OVERRIDE;
virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
virtual string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
virtual void Popup(NativeWindow* window) = 0;
scoped_ptr<ui::SimpleMenuModel> model_;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertItem(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertCheckItem(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertRadioItem(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertSeparator(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertSubMenu(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetIcon(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetSublabel(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Clear(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetIndexOfCommandId(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetItemCount(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetCommandIdAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetLabelAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetSublabelAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsItemCheckedAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsEnabledAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsVisibleAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Popup(const v8::FunctionCallbackInfo<v8::Value>& args);
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
static void AttachToWindow(const v8::FunctionCallbackInfo<v8::Value>& args);
#elif defined(OS_MACOSX)
static void SetApplicationMenu(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void SendActionToFirstResponder(
const v8::FunctionCallbackInfo<v8::Value>& args);
#endif
DISALLOW_COPY_AND_ASSIGN(Menu);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_H_

View file

@ -0,0 +1,64 @@
// Copyright (c) 2014 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 "atom/browser/api/atom_api_menu_gtk.h"
#include "atom/browser/native_window_gtk.h"
#include "atom/common/v8/native_type_conversions.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
#include "atom/common/v8/node_common.h"
namespace atom {
namespace api {
MenuGtk::MenuGtk(v8::Handle<v8::Object> wrapper)
: Menu(wrapper) {
}
MenuGtk::~MenuGtk() {
}
void MenuGtk::Popup(NativeWindow* native_window) {
uint32_t triggering_event_time;
gfx::Point point;
GdkEventButton* event = native_window->GetWebContents()->
GetRenderWidgetHostView()->GetLastMouseDown();
if (event) {
triggering_event_time = event->time;
point = gfx::Point(event->x_root, event->y_root);
} else {
triggering_event_time = GDK_CURRENT_TIME;
point = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
}
menu_gtk_.reset(new ::MenuGtk(this, model_.get()));
menu_gtk_->PopupAsContext(point, triggering_event_time);
}
// static
void Menu::AttachToWindow(const v8::FunctionCallbackInfo<v8::Value>& args) {
Menu* self = ObjectWrap::Unwrap<Menu>(args.This());
if (self == NULL)
return node::ThrowError("Menu is already destroyed");
NativeWindow* native_window;
if (!FromV8Arguments(args, &native_window))
return node::ThrowTypeError("Bad argument");
static_cast<NativeWindowGtk*>(native_window)->SetMenu(self->model_.get());
}
// static
Menu* Menu::Create(v8::Handle<v8::Object> wrapper) {
return new MenuGtk(wrapper);
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,34 @@
// Copyright (c) 2014 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_API_ATOM_API_MENU_GTK_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_GTK_H_
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/ui/gtk/menu_gtk.h"
namespace atom {
namespace api {
class MenuGtk : public Menu,
public ::MenuGtk::Delegate {
public:
explicit MenuGtk(v8::Handle<v8::Object> wrapper);
virtual ~MenuGtk();
protected:
virtual void Popup(NativeWindow* window) OVERRIDE;
private:
scoped_ptr<::MenuGtk> menu_gtk_;
DISALLOW_COPY_AND_ASSIGN(MenuGtk);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_GTK_H_

View file

@ -0,0 +1,39 @@
// 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_API_ATOM_API_MENU_MAC_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_
#include "atom/browser/api/atom_api_menu.h"
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
namespace atom {
namespace api {
class MenuMac : public Menu {
public:
explicit MenuMac(v8::Handle<v8::Object> wrapper);
virtual ~MenuMac();
protected:
virtual void Popup(NativeWindow* window) OVERRIDE;
base::scoped_nsobject<AtomMenuController> menu_controller_;
private:
friend class Menu;
// Fake sending an action from the application menu.
static void SendActionToFirstResponder(const std::string& action);
DISALLOW_COPY_AND_ASSIGN(MenuMac);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_

View file

@ -0,0 +1,109 @@
// 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.
#import "atom/browser/api/atom_api_menu_mac.h"
#include "base/mac/scoped_sending_event.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "atom/browser/native_window.h"
#include "atom/common/v8/node_common.h"
#include "atom/common/v8/native_type_conversions.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
namespace atom {
namespace api {
MenuMac::MenuMac(v8::Handle<v8::Object> wrapper)
: Menu(wrapper) {
}
MenuMac::~MenuMac() {
}
void MenuMac::Popup(NativeWindow* native_window) {
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:model_.get()]);
NSWindow* window = native_window->GetNativeWindow();
content::WebContents* web_contents = native_window->GetWebContents();
// Fake out a context menu event.
NSEvent* currentEvent = [NSApp currentEvent];
NSPoint position = [window mouseLocationOutsideOfEventStream];
NSTimeInterval eventTime = [currentEvent timestamp];
NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
location:position
modifierFlags:NSRightMouseDownMask
timestamp:eventTime
windowNumber:[window windowNumber]
context:nil
eventNumber:0
clickCount:1
pressure:1.0];
{
// Make sure events can be pumped while the menu is up.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
// One of the events that could be pumped is |window.close()|.
// User-initiated event-tracking loops protect against this by
// setting flags in -[CrApplication sendEvent:], but since
// web-content menus are initiated by IPC message the setup has to
// be done manually.
base::mac::ScopedSendingEvent sendingEventScoper;
// Show the menu.
[NSMenu popUpContextMenu:[menu_controller menu]
withEvent:clickEvent
forView:web_contents->GetView()->GetContentNativeView()];
}
}
// static
void MenuMac::SendActionToFirstResponder(const std::string& action) {
SEL selector = NSSelectorFromString(base::SysUTF8ToNSString(action));
[[NSApplication sharedApplication] sendAction:selector
to:nil
from:[NSApp mainMenu]];
}
// static
void Menu::SetApplicationMenu(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!args[0]->IsObject())
return node::ThrowTypeError("Bad argument");
MenuMac* menu = ObjectWrap::Unwrap<MenuMac>(args[0]->ToObject());
if (!menu)
return node::ThrowError("Menu is destroyed");
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:menu->model_.get()]);
[NSApp setMainMenu:[menu_controller menu]];
// Ensure the menu_controller_ is destroyed after main menu is set.
menu_controller.swap(menu->menu_controller_);
}
// static
void Menu::SendActionToFirstResponder(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string action;
if (!FromV8Arguments(args, &action))
return node::ThrowTypeError("Bad argument");
MenuMac::SendActionToFirstResponder(action);
}
// static
Menu* Menu::Create(v8::Handle<v8::Object> wrapper) {
return new MenuMac(wrapper);
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,52 @@
// 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 "atom/browser/api/atom_api_menu_win.h"
#include "atom/browser/native_window_win.h"
#include "atom/browser/ui/win/menu_2.h"
#include "atom/common/v8/native_type_conversions.h"
#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
#include "atom/common/v8/node_common.h"
namespace atom {
namespace api {
MenuWin::MenuWin(v8::Handle<v8::Object> wrapper)
: Menu(wrapper) {
}
MenuWin::~MenuWin() {
}
void MenuWin::Popup(NativeWindow* native_window) {
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
menu_.reset(new atom::Menu2(model_.get()));
menu_->RunContextMenuAt(cursor);
}
// static
void Menu::AttachToWindow(const v8::FunctionCallbackInfo<v8::Value>& args) {
Menu* self = ObjectWrap::Unwrap<Menu>(args.This());
if (self == NULL)
return node::ThrowError("Menu is already destroyed");
NativeWindow* native_window;
if (!FromV8Arguments(args, &native_window))
return node::ThrowTypeError("Bad argument");
static_cast<NativeWindowWin*>(native_window)->SetMenu(self->model_.get());
}
// static
Menu* Menu::Create(v8::Handle<v8::Object> wrapper) {
return new MenuWin(wrapper);
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,34 @@
// 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_API_ATOM_API_MENU_WIN_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_
#include "atom/browser/api/atom_api_menu.h"
namespace atom {
class Menu2;
namespace api {
class MenuWin : public Menu {
public:
explicit MenuWin(v8::Handle<v8::Object> wrapper);
virtual ~MenuWin();
protected:
virtual void Popup(NativeWindow* window) OVERRIDE;
private:
scoped_ptr<atom::Menu2> menu_;
DISALLOW_COPY_AND_ASSIGN(MenuWin);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_WIN_H_

View file

@ -0,0 +1,67 @@
// 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 "atom/browser/api/atom_api_power_monitor.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "atom/common/v8/node_common.h"
namespace atom {
namespace api {
PowerMonitor::PowerMonitor(v8::Handle<v8::Object> wrapper)
: EventEmitter(wrapper) {
base::PowerMonitor::Get()->AddObserver(this);
}
PowerMonitor::~PowerMonitor() {
base::PowerMonitor::Get()->RemoveObserver(this);
}
void PowerMonitor::OnPowerStateChange(bool on_battery_power) {
if (on_battery_power)
Emit("on-battery");
else
Emit("on-ac");
}
void PowerMonitor::OnSuspend() {
Emit("suspend");
}
void PowerMonitor::OnResume() {
Emit("resume");
}
// static
void PowerMonitor::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new PowerMonitor(args.This());
}
// static
void PowerMonitor::Initialize(v8::Handle<v8::Object> target) {
#if defined(OS_MACOSX)
base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
#endif
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(
PowerMonitor::New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("PowerMonitor"));
target->Set(v8::String::NewSymbol("PowerMonitor"), t->GetFunction());
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_power_monitor, atom::api::PowerMonitor::Initialize)

View file

@ -0,0 +1,40 @@
// 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_API_ATOM_API_POWER_MONITOR_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#include "base/compiler_specific.h"
#include "base/power_monitor/power_observer.h"
#include "atom/common/api/atom_api_event_emitter.h"
namespace atom {
namespace api {
class PowerMonitor : public EventEmitter,
public base::PowerObserver {
public:
virtual ~PowerMonitor();
static void Initialize(v8::Handle<v8::Object> target);
protected:
explicit PowerMonitor(v8::Handle<v8::Object> wrapper);
virtual void OnPowerStateChange(bool on_battery_power) OVERRIDE;
virtual void OnSuspend() OVERRIDE;
virtual void OnResume() OVERRIDE;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_

View file

@ -0,0 +1,386 @@
// 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 "atom/browser/api/atom_api_protocol.h"
#include "base/stl_util.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/net/atom_url_request_context_getter.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/common/v8/native_type_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h"
#include "atom/common/v8/node_common.h"
namespace atom {
namespace api {
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
namespace {
// The protocol module object.
ScopedPersistent<v8::Object> g_protocol_object;
// Registered protocol handlers.
typedef std::map<std::string, RefCountedV8Function> HandlersMap;
static HandlersMap g_handlers;
static const char* kEarlyUseProtocolError = "This method can only be used"
"after the application has finished launching.";
// Emit an event for the protocol module.
void EmitEventInUI(const std::string& event, const std::string& parameter) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> argv[] = {
ToV8Value(event),
ToV8Value(parameter),
};
node::MakeCallback(g_protocol_object.NewHandle(node_isolate),
"emit", 2, argv);
}
// Convert the URLRequest object to V8 object.
v8::Handle<v8::Object> ConvertURLRequestToV8Object(
const net::URLRequest* request) {
v8::Local<v8::Object> obj = v8::Object::New();
obj->Set(ToV8Value("method"), ToV8Value(request->method()));
obj->Set(ToV8Value("url"), ToV8Value(request->url().spec()));
obj->Set(ToV8Value("referrer"), ToV8Value(request->referrer()));
return obj;
}
// Get the job factory.
AtomURLRequestJobFactory* GetRequestJobFactory() {
return AtomBrowserContext::Get()->url_request_context_getter()->job_factory();
}
class CustomProtocolRequestJob : public AdapterRequestJob {
public:
CustomProtocolRequestJob(ProtocolHandler* protocol_handler,
net::URLRequest* request,
net::NetworkDelegate* network_delegate)
: AdapterRequestJob(protocol_handler, request, network_delegate) {
}
// AdapterRequestJob:
virtual void GetJobTypeInUI() OVERRIDE {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
// Call the JS handler.
v8::Handle<v8::Value> argv[] = {
ConvertURLRequestToV8Object(request()),
};
RefCountedV8Function callback = g_handlers[request()->url().scheme()];
v8::Handle<v8::Value> result = callback->NewHandle(node_isolate)->Call(
v8::Context::GetCurrent()->Global(), 1, argv);
// Determine the type of the job we are going to create.
if (result->IsString()) {
std::string data = FromV8Value(result);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
GetWeakPtr(),
"text/plain",
"UTF-8",
data));
return;
} else if (result->IsObject()) {
v8::Handle<v8::Object> obj = result->ToObject();
std::string name = FromV8Value(obj->GetConstructorName());
if (name == "RequestStringJob") {
std::string mime_type = FromV8Value(obj->Get(
v8::String::New("mimeType")));
std::string charset = FromV8Value(obj->Get(v8::String::New("charset")));
std::string data = FromV8Value(obj->Get(v8::String::New("data")));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
GetWeakPtr(),
mime_type,
charset,
data));
return;
} else if (name == "RequestFileJob") {
base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
GetWeakPtr(),
path));
return;
}
}
// Try the default protocol handler if we have.
if (default_protocol_handler()) {
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
GetWeakPtr()));
return;
}
// Fallback to the not implemented error.
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
GetWeakPtr(),
net::ERR_NOT_IMPLEMENTED));
}
};
// Always return the same CustomProtocolRequestJob for all requests, because
// the content API needs the ProtocolHandler to return a job immediately, and
// getting the real job from the JS requires asynchronous calls, so we have
// to create an adapter job first.
// Users can also pass an extra ProtocolHandler as the fallback one when
// registered handler doesn't want to deal with the request.
class CustomProtocolHandler : public ProtocolHandler {
public:
explicit CustomProtocolHandler(ProtocolHandler* protocol_handler = NULL)
: protocol_handler_(protocol_handler) {
}
virtual net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const OVERRIDE {
return new CustomProtocolRequestJob(protocol_handler_.get(),
request,
network_delegate);
}
ProtocolHandler* ReleaseDefaultProtocolHandler() {
return protocol_handler_.release();
}
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
private:
scoped_ptr<ProtocolHandler> protocol_handler_;
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
};
} // namespace
// static
void Protocol::RegisterProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
RefCountedV8Function callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (g_handlers.find(scheme) != g_handlers.end() ||
GetRequestJobFactory()->IsHandledProtocol(scheme))
return node::ThrowError("The scheme is already registered");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Store the handler in a map.
g_handlers[scheme] = callback;
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&RegisterProtocolInIO, scheme));
}
// static
void Protocol::UnregisterProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Erase the handler from map.
HandlersMap::iterator it(g_handlers.find(scheme));
if (it == g_handlers.end())
return node::ThrowError("The scheme has not been registered");
g_handlers.erase(it);
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&UnregisterProtocolInIO, scheme));
}
// static
void Protocol::IsHandledProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
args.GetReturnValue().Set(GetRequestJobFactory()->IsHandledProtocol(scheme));
}
// static
void Protocol::InterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
RefCountedV8Function callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (!GetRequestJobFactory()->HasProtocolHandler(scheme))
return node::ThrowError("Cannot intercept procotol");
if (ContainsKey(g_handlers, scheme))
return node::ThrowError("Cannot intercept custom procotols");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Store the handler in a map.
g_handlers[scheme] = callback;
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&InterceptProtocolInIO, scheme));
}
// static
void Protocol::UninterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Erase the handler from map.
HandlersMap::iterator it(g_handlers.find(scheme));
if (it == g_handlers.end())
return node::ThrowError("The scheme has not been registered");
g_handlers.erase(it);
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&UninterceptProtocolInIO,
scheme));
}
// static
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
job_factory->SetProtocolHandler(scheme, new CustomProtocolHandler);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"registered",
scheme));
}
// static
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
job_factory->SetProtocolHandler(scheme, NULL);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"unregistered",
scheme));
}
// static
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
ProtocolHandler* original_handler = job_factory->GetProtocolHandler(scheme);
if (original_handler == NULL) {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"error",
"There is no protocol handler to intercpet"));
return;
}
job_factory->ReplaceProtocol(scheme,
new CustomProtocolHandler(original_handler));
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"intercepted",
scheme));
}
// static
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
// Check if the protocol handler is intercepted.
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
job_factory->GetProtocolHandler(scheme));
if (handler->original_handler() == NULL) {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"error",
"The protocol is not intercpeted"));
return;
}
// Reset the protocol handler to the orignal one and delete current
// protocol handler.
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
delete job_factory->ReplaceProtocol(scheme, original_handler);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"unintercepted",
scheme));
}
// static
void Protocol::Initialize(v8::Handle<v8::Object> target) {
// Remember the protocol object, used for emitting event later.
g_protocol_object.reset(target);
// Make sure the job factory has been created.
AtomBrowserContext::Get()->url_request_context_getter()->
GetURLRequestContext();
NODE_SET_METHOD(target, "registerProtocol", RegisterProtocol);
NODE_SET_METHOD(target, "unregisterProtocol", UnregisterProtocol);
NODE_SET_METHOD(target, "isHandledProtocol", IsHandledProtocol);
NODE_SET_METHOD(target, "interceptProtocol", InterceptProtocol);
NODE_SET_METHOD(target, "uninterceptProtocol", UninterceptProtocol);
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)

View file

@ -0,0 +1,47 @@
// 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_API_ATOM_API_PROTOCOL_H_
#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
#include <string>
#include <map>
#include "base/basictypes.h"
#include "v8/include/v8.h"
namespace atom {
namespace api {
class Protocol {
public:
static void Initialize(v8::Handle<v8::Object> target);
private:
static void RegisterProtocol(const v8::FunctionCallbackInfo<v8::Value>& args);
static void UnregisterProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsHandledProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void InterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void UninterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void RegisterProtocolInIO(const std::string& scheme);
static void UnregisterProtocolInIO(const std::string& scheme);
static void InterceptProtocolInIO(const std::string& scheme);
static void UninterceptProtocolInIO(const std::string& scheme);
DISALLOW_IMPLICIT_CONSTRUCTORS(Protocol);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_

View file

@ -0,0 +1,706 @@
// 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 "atom/browser/api/atom_api_window.h"
#include "base/bind.h"
#include "base/process/kill.h"
#include "atom/browser/native_window.h"
#include "atom/common/v8/native_type_conversions.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/render_process_host.h"
#include "ui/gfx/point.h"
#include "ui/gfx/size.h"
#include "atom/common/v8/node_common.h"
#include "vendor/node/src/node_buffer.h"
using content::NavigationController;
using node::ObjectWrap;
#define UNWRAP_WINDOW_AND_CHECK \
Window* self = ObjectWrap::Unwrap<Window>(args.This()); \
if (self == NULL) \
return node::ThrowError("Window is already destroyed")
namespace atom {
namespace api {
Window::Window(v8::Handle<v8::Object> wrapper, base::DictionaryValue* options)
: EventEmitter(wrapper),
window_(NativeWindow::Create(options)) {
window_->InitFromOptions(options);
window_->AddObserver(this);
}
Window::~Window() {
Emit("destroyed");
window_->RemoveObserver(this);
}
void Window::OnPageTitleUpdated(bool* prevent_default,
const std::string& title) {
base::ListValue args;
args.AppendString(title);
*prevent_default = Emit("page-title-updated", &args);
}
void Window::OnLoadingStateChanged(bool is_loading) {
base::ListValue args;
args.AppendBoolean(is_loading);
Emit("loading-state-changed", &args);
}
void Window::WillCloseWindow(bool* prevent_default) {
*prevent_default = Emit("close");
}
void Window::OnWindowClosed() {
Emit("closed");
// Free memory when native window is closed, the delete is delayed so other
// observers would not get a invalid pointer of NativeWindow.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
void Window::OnWindowBlur() {
Emit("blur");
}
void Window::OnRendererUnresponsive() {
Emit("unresponsive");
}
void Window::OnRendererResponsive() {
Emit("responsive");
}
void Window::OnRenderViewDeleted(int process_id, int routing_id) {
base::ListValue args;
args.AppendInteger(process_id);
args.AppendInteger(routing_id);
Emit("render-view-deleted", &args);
}
void Window::OnRendererCrashed() {
Emit("crashed");
}
void Window::OnCapturePageDone(const RefCountedV8Function& callback,
const std::vector<unsigned char>& data) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::Value> buffer = node::Buffer::New(
reinterpret_cast<const char*>(data.data()),
data.size());
callback->NewHandle(node_isolate)->Call(
v8::Context::GetCurrent()->Global(), 1, &buffer);
}
// static
void Window::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
scoped_ptr<base::Value> options;
if (!FromV8Arguments(args, &options))
return node::ThrowTypeError("Bad argument");
if (!options || !options->IsType(base::Value::TYPE_DICTIONARY))
return node::ThrowTypeError("Options must be dictionary");
new Window(args.This(), static_cast<base::DictionaryValue*>(options.get()));
// Give js code a chance to do initialization.
node::MakeCallback(args.This(), "_init", 0, NULL);
}
// static
void Window::Destroy(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
base::ProcessHandle handle = self->window_->GetRenderProcessHandle();
delete self;
// Make sure the renderer process is terminated, it could happen that the
// renderer process became a zombie.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(base::IgnoreResult(base::KillProcess), handle, 0, false),
base::TimeDelta::FromMilliseconds(5000));
}
// static
void Window::Close(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Close();
}
// static
void Window::Focus(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Focus(args[0]->IsBoolean() ? args[0]->BooleanValue(): true);
}
// static
void Window::IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsFocused());
}
// static
void Window::Show(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Show();
}
// static
void Window::Hide(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Hide();
}
// static
void Window::IsVisible(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return args.GetReturnValue().Set(self->window_->IsVisible());
}
// static
void Window::Maximize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Maximize();
}
// static
void Window::Unmaximize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Unmaximize();
}
// static
void Window::Minimize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Minimize();
}
// static
void Window::Restore(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Restore();
}
// static
void Window::SetFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
bool fs;
if (!FromV8Arguments(args, &fs))
return node::ThrowTypeError("Bad argument");
self->window_->SetFullscreen(fs);
}
// static
void Window::IsFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsFullscreen());
}
// static
void Window::SetSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetSize(gfx::Size(width, height));
}
// static
void Window::GetSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Size size = self->window_->GetSize();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, ToV8Value(size.width()));
ret->Set(1, ToV8Value(size.height()));
args.GetReturnValue().Set(ret);
}
// static
void Window::SetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetMinimumSize(gfx::Size(width, height));
}
// static
void Window::GetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Size size = self->window_->GetMinimumSize();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, ToV8Value(size.width()));
ret->Set(1, ToV8Value(size.height()));
args.GetReturnValue().Set(ret);
}
// static
void Window::SetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetMaximumSize(gfx::Size(width, height));
}
// static
void Window::GetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Size size = self->window_->GetMaximumSize();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, ToV8Value(size.width()));
ret->Set(1, ToV8Value(size.height()));
args.GetReturnValue().Set(ret);
}
// static
void Window::SetResizable(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
bool resizable;
if (!FromV8Arguments(args, &resizable))
return node::ThrowTypeError("Bad argument");
self->window_->SetResizable(resizable);
}
// static
void Window::IsResizable(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsResizable());
}
// static
void Window::SetAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
bool top;
if (!FromV8Arguments(args, &top))
return node::ThrowTypeError("Bad argument");
self->window_->SetAlwaysOnTop(top);
}
// static
void Window::IsAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsAlwaysOnTop());
}
// static
void Window::Center(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Center();
}
// static
void Window::SetPosition(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int x, y;
if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument");
self->window_->SetPosition(gfx::Point(x, y));
}
// static
void Window::GetPosition(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Point pos = self->window_->GetPosition();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, ToV8Value(pos.x()));
ret->Set(1, ToV8Value(pos.y()));
args.GetReturnValue().Set(ret);
}
// static
void Window::SetTitle(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
std::string title;
if (!FromV8Arguments(args, &title))
return node::ThrowTypeError("Bad argument");
self->window_->SetTitle(title);
}
// static
void Window::GetTitle(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(ToV8Value(self->window_->GetTitle()));
}
// static
void Window::FlashFrame(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->FlashFrame(
args[0]->IsBoolean() ? args[0]->BooleanValue(): true);
}
// static
void Window::SetKiosk(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
bool kiosk;
if (!FromV8Arguments(args, &kiosk))
return node::ThrowTypeError("Bad argument");
self->window_->SetKiosk(kiosk);
}
// static
void Window::IsKiosk(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsKiosk());
}
// static
void Window::OpenDevTools(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->OpenDevTools();
}
// static
void Window::CloseDevTools(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->CloseDevTools();
}
// static
void Window::IsDevToolsOpened(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsDevToolsOpened());
}
// static
void Window::InspectElement(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int x, y;
if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument");
self->window_->InspectElement(x, y);
}
// static
void Window::DebugDevTools(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (self->window_->IsDevToolsOpened())
NativeWindow::Debug(self->window_->GetDevToolsWebContents());
}
// static
void Window::FocusOnWebView(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->FocusOnWebView();
}
// static
void Window::BlurWebView(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->BlurWebView();
}
// static
void Window::IsWebViewFocused(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->IsWebViewFocused());
}
// static
void Window::CapturePage(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Rect rect;
RefCountedV8Function callback;
if (!FromV8Arguments(args, &rect, &callback) &&
!FromV8Arguments(args, &callback))
return node::ThrowTypeError("Bad argument");
self->window_->CapturePage(rect, base::Bind(&Window::OnCapturePageDone,
base::Unretained(self),
callback));
}
// static
void Window::GetPageTitle(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(ToV8Value(
self->window_->GetWebContents()->GetTitle()));
}
// static
void Window::IsLoading(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->GetWebContents()->IsLoading());
}
// static
void Window::IsWaitingForResponse(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(
self->window_->GetWebContents()->IsWaitingForResponse());
}
// static
void Window::Stop(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->GetWebContents()->Stop();
}
// static
void Window::GetRoutingID(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->GetWebContents()->GetRoutingID());
}
// static
void Window::GetProcessID(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(
self->window_->GetWebContents()->GetRenderProcessHost()->GetID());
}
// static
void Window::IsCrashed(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
args.GetReturnValue().Set(self->window_->GetWebContents()->IsCrashed());
}
// static
void Window::LoadURL(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
GURL url;
if (!FromV8Arguments(args, &url))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
content::NavigationController::LoadURLParams params(url);
params.transition_type = content::PAGE_TRANSITION_TYPED;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
controller.LoadURLWithParams(params);
}
// static
void Window::GetURL(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
GURL url;
if (controller.GetActiveEntry())
url = controller.GetActiveEntry()->GetVirtualURL();
args.GetReturnValue().Set(ToV8Value(url));
}
// static
void Window::CanGoBack(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
args.GetReturnValue().Set(controller.CanGoBack());
}
// static
void Window::CanGoForward(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
args.GetReturnValue().Set(controller.CanGoForward());
}
// static
void Window::CanGoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int offset;
if (!FromV8Arguments(args, &offset))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
args.GetReturnValue().Set(controller.CanGoToOffset(offset));
}
// static
void Window::GoBack(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoBack();
}
// static
void Window::GoForward(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoForward();
}
// static
void Window::GoToIndex(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int index;
if (!FromV8Arguments(args, &index))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoToIndex(index);
}
// static
void Window::GoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int offset;
if (!FromV8Arguments(args, &offset))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoToOffset(offset);
}
// static
void Window::Reload(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.Reload(args[0]->IsBoolean() ? args[0]->BooleanValue(): false);
}
// static
void Window::ReloadIgnoringCache(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.ReloadIgnoringCache(
args[0]->IsBoolean() ? args[0]->BooleanValue(): false);
}
// static
void Window::Initialize(v8::Handle<v8::Object> target) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(Window::New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("BrowserWindow"));
NODE_SET_PROTOTYPE_METHOD(t, "destroy", Destroy);
NODE_SET_PROTOTYPE_METHOD(t, "close", Close);
NODE_SET_PROTOTYPE_METHOD(t, "focus", Focus);
NODE_SET_PROTOTYPE_METHOD(t, "isFocused", IsFocused);
NODE_SET_PROTOTYPE_METHOD(t, "show", Show);
NODE_SET_PROTOTYPE_METHOD(t, "hide", Hide);
NODE_SET_PROTOTYPE_METHOD(t, "isVisible", IsVisible);
NODE_SET_PROTOTYPE_METHOD(t, "maximize", Maximize);
NODE_SET_PROTOTYPE_METHOD(t, "unmaximize", Unmaximize);
NODE_SET_PROTOTYPE_METHOD(t, "minimize", Minimize);
NODE_SET_PROTOTYPE_METHOD(t, "restore", Restore);
NODE_SET_PROTOTYPE_METHOD(t, "setFullScreen", SetFullscreen);
NODE_SET_PROTOTYPE_METHOD(t, "isFullScreen", IsFullscreen);
NODE_SET_PROTOTYPE_METHOD(t, "setSize", SetSize);
NODE_SET_PROTOTYPE_METHOD(t, "getSize", GetSize);
NODE_SET_PROTOTYPE_METHOD(t, "setMinimumSize", SetMinimumSize);
NODE_SET_PROTOTYPE_METHOD(t, "getMinimumSize", GetMinimumSize);
NODE_SET_PROTOTYPE_METHOD(t, "setMaximumSize", SetMaximumSize);
NODE_SET_PROTOTYPE_METHOD(t, "getMaximumSize", GetMaximumSize);
NODE_SET_PROTOTYPE_METHOD(t, "setResizable", SetResizable);
NODE_SET_PROTOTYPE_METHOD(t, "isResizable", IsResizable);
NODE_SET_PROTOTYPE_METHOD(t, "setAlwaysOnTop", SetAlwaysOnTop);
NODE_SET_PROTOTYPE_METHOD(t, "isAlwaysOnTop", IsAlwaysOnTop);
NODE_SET_PROTOTYPE_METHOD(t, "center", Center);
NODE_SET_PROTOTYPE_METHOD(t, "setPosition", SetPosition);
NODE_SET_PROTOTYPE_METHOD(t, "getPosition", GetPosition);
NODE_SET_PROTOTYPE_METHOD(t, "setTitle", SetTitle);
NODE_SET_PROTOTYPE_METHOD(t, "getTitle", GetTitle);
NODE_SET_PROTOTYPE_METHOD(t, "flashFrame", FlashFrame);
NODE_SET_PROTOTYPE_METHOD(t, "setKiosk", SetKiosk);
NODE_SET_PROTOTYPE_METHOD(t, "isKiosk", IsKiosk);
NODE_SET_PROTOTYPE_METHOD(t, "openDevTools", OpenDevTools);
NODE_SET_PROTOTYPE_METHOD(t, "closeDevTools", CloseDevTools);
NODE_SET_PROTOTYPE_METHOD(t, "isDevToolsOpened", IsDevToolsOpened);
NODE_SET_PROTOTYPE_METHOD(t, "inspectElement", InspectElement);
NODE_SET_PROTOTYPE_METHOD(t, "debugDevTools", DebugDevTools);
NODE_SET_PROTOTYPE_METHOD(t, "focusOnWebView", FocusOnWebView);
NODE_SET_PROTOTYPE_METHOD(t, "blurWebView", BlurWebView);
NODE_SET_PROTOTYPE_METHOD(t, "isWebViewFocused", IsWebViewFocused);
NODE_SET_PROTOTYPE_METHOD(t, "capturePage", CapturePage);
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);
NODE_SET_PROTOTYPE_METHOD(t, "isWaitingForResponse", IsWaitingForResponse);
NODE_SET_PROTOTYPE_METHOD(t, "stop", Stop);
NODE_SET_PROTOTYPE_METHOD(t, "getRoutingId", GetRoutingID);
NODE_SET_PROTOTYPE_METHOD(t, "getProcessId", GetProcessID);
NODE_SET_PROTOTYPE_METHOD(t, "isCrashed", IsCrashed);
NODE_SET_PROTOTYPE_METHOD(t, "loadUrl", LoadURL);
NODE_SET_PROTOTYPE_METHOD(t, "getUrl", GetURL);
NODE_SET_PROTOTYPE_METHOD(t, "canGoBack", CanGoBack);
NODE_SET_PROTOTYPE_METHOD(t, "canGoForward", CanGoForward);
NODE_SET_PROTOTYPE_METHOD(t, "canGoToOffset", CanGoToOffset);
NODE_SET_PROTOTYPE_METHOD(t, "goBack", GoBack);
NODE_SET_PROTOTYPE_METHOD(t, "goForward", GoForward);
NODE_SET_PROTOTYPE_METHOD(t, "goToIndex", GoToIndex);
NODE_SET_PROTOTYPE_METHOD(t, "goToOffset", GoToOffset);
NODE_SET_PROTOTYPE_METHOD(t, "reload", Reload);
NODE_SET_PROTOTYPE_METHOD(t, "reloadIgnoringCache", ReloadIgnoringCache);
target->Set(v8::String::NewSymbol("BrowserWindow"), t->GetFunction());
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_window, atom::api::Window::Initialize)

View file

@ -0,0 +1,132 @@
// 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_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "atom/browser/native_window_observer.h"
#include "atom/common/api/atom_api_event_emitter.h"
#include "atom/common/v8/scoped_persistent.h"
namespace base {
class DictionaryValue;
}
namespace atom {
class NativeWindow;
namespace api {
class Window : public EventEmitter,
public NativeWindowObserver {
public:
virtual ~Window();
static void Initialize(v8::Handle<v8::Object> target);
NativeWindow* window() { return window_.get(); }
protected:
explicit Window(v8::Handle<v8::Object> wrapper,
base::DictionaryValue* options);
// Implementations of NativeWindowObserver.
virtual void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) OVERRIDE;
virtual void OnLoadingStateChanged(bool is_loading) OVERRIDE;
virtual void WillCloseWindow(bool* prevent_default) OVERRIDE;
virtual void OnWindowClosed() OVERRIDE;
virtual void OnWindowBlur() OVERRIDE;
virtual void OnRendererUnresponsive() OVERRIDE;
virtual void OnRendererResponsive() OVERRIDE;
virtual void OnRenderViewDeleted(int process_id, int routing_id) OVERRIDE;
virtual void OnRendererCrashed() OVERRIDE;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);
// APIs for NativeWindow.
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Show(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Hide(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsVisible(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Maximize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Unmaximize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Minimize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Restore(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetResizable(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsResizable(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Center(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetPosition(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPosition(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetTitle(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetTitle(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FlashFrame(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetKiosk(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsKiosk(const v8::FunctionCallbackInfo<v8::Value>& args);
static void OpenDevTools(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CloseDevTools(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsDevToolsOpened(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InspectElement(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DebugDevTools(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FocusOnWebView(const v8::FunctionCallbackInfo<v8::Value>& args);
static void BlurWebView(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsWebViewFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CapturePage(const v8::FunctionCallbackInfo<v8::Value>& args);
// APIs for WebContents.
static void GetPageTitle(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsLoading(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsWaitingForResponse(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetRoutingID(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetProcessID(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsCrashed(const v8::FunctionCallbackInfo<v8::Value>& args);
// APIs for NavigationController.
static void LoadURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CanGoBack(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CanGoForward(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CanGoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoBack(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoForward(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoToIndex(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Reload(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ReloadIgnoringCache(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Called when capturePage is done.
void OnCapturePageDone(const RefCountedV8Function& callback,
const std::vector<unsigned char>& data);
scoped_ptr<NativeWindow> window_;
DISALLOW_COPY_AND_ASSIGN(Window);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_WINDOW_H_

View file

@ -0,0 +1,94 @@
// 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 "atom/browser/api/atom_browser_bindings.h"
#include <vector>
#include "base/logging.h"
#include "atom/browser/api/atom_api_event.h"
#include "atom/common/v8/native_type_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "atom/common/v8/node_common.h"
namespace atom {
AtomBrowserBindings::AtomBrowserBindings() {
}
AtomBrowserBindings::~AtomBrowserBindings() {
}
void AtomBrowserBindings::OnRendererMessage(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// process.emit(channel, 'message', process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(ToV8Value(channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
void AtomBrowserBindings::OnRendererMessageSync(
int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args,
NativeWindow* sender,
IPC::Message* message) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// Create the event object.
v8::Handle<v8::Object> event = api::Event::CreateV8Object();
api::Event::Unwrap<api::Event>(event)->SetSenderAndMessage(sender, message);
// process.emit(channel, 'sync-message', event, process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(ToV8Value(channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(event);
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
} // namespace atom

View file

@ -0,0 +1,49 @@
// 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_API_ATOM_BROWSER_BINDINGS_
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#include "base/strings/string16.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/v8/scoped_persistent.h"
namespace base {
class ListValue;
}
namespace IPC {
class Message;
}
namespace atom {
class NativeWindow;
class AtomBrowserBindings : public AtomBindings {
public:
AtomBrowserBindings();
virtual ~AtomBrowserBindings();
// Called when received a message from renderer.
void OnRendererMessage(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args,
NativeWindow* sender,
IPC::Message* message);
private:
DISALLOW_COPY_AND_ASSIGN(AtomBrowserBindings);
};
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_BINDINGS_

View file

@ -0,0 +1,34 @@
EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'app'
Application = bindings.Application
Application::__proto__ = EventEmitter.prototype
app = new Application
app.getHomeDir = ->
process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']
app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu
app.getApplicationMenu = ->
require('menu').getApplicationMenu()
app.commandLine =
appendSwitch: bindings.appendSwitch,
appendArgument: bindings.appendArgument
if process.platform is 'darwin'
app.dock =
bounce: (type='informational') -> bindings.dockBounce type
cancelBounce: bindings.dockCancelBounce
setBadge: bindings.dockSetBadgeText
getBadge: bindings.dockGetBadgeText
# Support old event name.
app.once 'ready', -> app.emit 'finish-launching'
# Only one App object pemitted.
module.exports = app

View file

@ -0,0 +1,6 @@
module.exports =
browserMainParts:
preMainMessageLoopRun: ->
setImmediate ->
module.exports.browserMainParts.preMainMessageLoopRun()

View file

@ -0,0 +1,25 @@
AutoUpdater = process.atomBinding('auto_updater').AutoUpdater
EventEmitter = require('events').EventEmitter
AutoUpdater::__proto__ = EventEmitter.prototype
autoUpdater = new AutoUpdater
autoUpdater.on 'update-downloaded-raw', (args...) ->
args[3] = new Date(args[3]) # releaseDate
@emit 'update-downloaded', args..., => @quitAndInstall()
autoUpdater.quitAndInstall = ->
# If we don't have any window then quitAndInstall immediately.
BrowserWindow = require 'browser-window'
windows = BrowserWindow.getAllWindows()
if windows.length is 0
AutoUpdater::quitAndInstall.call this
return
# Do the restart after all windows have been closed.
app = require 'app'
app.removeAllListeners 'window-all-closed'
app.once 'window-all-closed', AutoUpdater::quitAndInstall.bind(this)
win.close() for win in windows
module.exports = autoUpdater

View file

@ -0,0 +1,58 @@
EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map'
app = require 'app'
BrowserWindow = process.atomBinding('window').BrowserWindow
BrowserWindow::__proto__ = EventEmitter.prototype
# Store all created windows in the weak map.
BrowserWindow.windows = new IDWeakMap
BrowserWindow::_init = ->
# Simulate the application menu on platforms other than OS X.
if process.platform isnt 'darwin'
menu = app.getApplicationMenu()
@setMenu menu if menu?
# Remember the window.
id = BrowserWindow.windows.add this
# Remove the window from weak map immediately when it's destroyed, since we
# could be iterating windows before GC happended.
@once 'destroyed', ->
BrowserWindow.windows.remove id if BrowserWindow.windows.has id
# Tell the rpc server that a render view has been deleted and we need to
# release all objects owned by it.
@on 'render-view-deleted', (event, processId, routingId) ->
process.emit 'ATOM_BROWSER_RELEASE_RENDER_VIEW', processId, routingId
BrowserWindow::toggleDevTools = ->
if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
BrowserWindow::restart = ->
@loadUrl(@getUrl())
BrowserWindow::setMenu = (menu) ->
if process.platform is 'darwin'
throw new Error('BrowserWindow.setMenu is not available on OS X')
throw new TypeError('Invalid menu') unless menu?.constructor?.name is 'Menu'
@menu = menu # Keep a reference of menu in case of GC.
@menu.attachToWindow this
BrowserWindow.getAllWindows = ->
windows = BrowserWindow.windows
windows.get key for key in windows.keys()
BrowserWindow.getFocusedWindow = ->
windows = BrowserWindow.getAllWindows()
return window for window in windows when window.isFocused()
BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) ->
windows = BrowserWindow.getAllWindows()
return window for window in windows when window.getProcessId() == processId and
window.getRoutingId() == routingId
module.exports = BrowserWindow

View file

@ -0,0 +1,78 @@
binding = process.atomBinding 'dialog'
v8Util = process.atomBinding 'v8_util'
BrowserWindow = require 'browser-window'
fileDialogProperties =
openFile: 1, openDirectory: 2, multiSelections: 4, createDirectory: 8
messageBoxTypes = ['none', 'info', 'warning']
module.exports =
showOpenDialog: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options ?= title: 'Open', properties: ['openFile']
options.properties ?= ['openFile']
throw new TypeError('Properties need to be array') unless Array.isArray options.properties
properties = 0
for prop, value of fileDialogProperties
properties |= value if prop in options.properties
options.title ?= ''
options.defaultPath ?= ''
binding.showOpenDialog String(options.title),
String(options.defaultPath),
properties,
window,
callback
showSaveDialog: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options ?= title: 'Save'
options.title ?= ''
options.defaultPath ?= ''
binding.showSaveDialog String(options.title),
String(options.defaultPath),
window,
callback
showMessageBox: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options ?= type: 'none'
options.type ?= 'none'
options.type = messageBoxTypes.indexOf options.type
throw new TypeError('Invalid message box type') unless options.type > -1
throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons
options.title ?= ''
options.message ?= ''
options.detail ?= ''
binding.showMessageBox options.type,
options.buttons,
String(options.title),
String(options.message),
String(options.detail),
window,
callback
# Mark standard asynchronous functions.
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports

View file

@ -0,0 +1,32 @@
EventEmitter = require('events').EventEmitter
send = process.atomBinding('ipc').send
sendWrap = (channel, processId, routingId, args...) ->
BrowserWindow = require 'browser-window'
if processId?.constructor is BrowserWindow
window = processId
args = [routingId, args...]
processId = window.getProcessId()
routingId = window.getRoutingId()
send channel, processId, routingId, [args...]
class Ipc extends EventEmitter
constructor: ->
process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
@emit(args...)
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
set = (value) -> event.sendReply JSON.stringify(value)
Object.defineProperty event, 'returnValue', {set}
Object.defineProperty event, 'result', {set}
@emit(channel, event, args...)
send: (processId, routingId, args...) ->
@sendChannel(processId, routingId, 'message', args...)
sendChannel: (args...) ->
sendWrap('ATOM_INTERNAL_MESSAGE', args...)
module.exports = new Ipc

View file

@ -0,0 +1,35 @@
BrowserWindow = require 'browser-window'
nextCommandId = 0
class MenuItem
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
constructor: (options) ->
Menu = require 'menu'
{click, @selector, @type, @label, @sublabel, @accelerator, @enabled, @visible, @checked, @groupId, @submenu} = options
@type = 'submenu' if not @type? and @submenu?
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
@type = @type ? 'normal'
@label = @label ? ''
@sublabel = @sublabel ? ''
@accelerator = @accelerator ? null
@enabled = @enabled ? true
@visible = @visible ? true
@checked = @checked ? false
@groupId = @groupId ? null
@submenu = @submenu ? null
throw new Error('Unknown menu type') if MenuItem.types.indexOf(@type) is -1
@commandId = ++nextCommandId
@click = =>
if typeof click is 'function'
click this, BrowserWindow.getFocusedWindow()
else if typeof @selector is 'string'
Menu.sendActionToFirstResponder @selector
module.exports = MenuItem

View file

@ -0,0 +1,75 @@
BrowserWindow = require 'browser-window'
EventEmitter = require('events').EventEmitter
MenuItem = require 'menu-item'
bindings = process.atomBinding 'menu'
Menu = bindings.Menu
Menu::__proto__ = EventEmitter.prototype
popup = Menu::popup
Menu::popup = (window) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
popup.call this, window
Menu::append = (item) ->
@insert @getItemCount(), item
Menu::insert = (pos, item) ->
throw new TypeError('Invalid item') unless item?.constructor is MenuItem
switch item.type
when 'normal' then @insertItem pos, item.commandId, item.label
when 'checkbox' then @insertCheckItem pos, item.commandId, item.label
when 'radio' then @insertRadioItem pos, item.commandId, item.label, item.groupId
when 'separator' then @insertSeparator pos
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
@setSublabel pos, item.sublabel if item.sublabel?
unless @delegate?
@commandsMap = {}
@items = []
@delegate =
isCommandIdChecked: (commandId) => @commandsMap[commandId]?.checked
isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
executeCommand: (commandId) =>
activeItem = @commandsMap[commandId]
activeItem.click() if activeItem?
@items.splice pos, 0, item
@commandsMap[item.commandId] = item
applicationMenu = null
Menu.setApplicationMenu = (menu) ->
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
applicationMenu = menu # Keep a reference.
if process.platform is 'darwin'
bindings.setApplicationMenu menu
else
windows = BrowserWindow.getAllWindows()
w.setMenu menu for w in windows
Menu.getApplicationMenu = -> applicationMenu
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
Menu.buildFromTemplate = (template) ->
throw new TypeError('Invalid template for Menu') unless Array.isArray template
menu = new Menu
for item in template
throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object'
item.submenu = Menu.buildFromTemplate item.submenu if item.submenu?
menuItem = new MenuItem(item)
menuItem[key] = value for key, value of item when not menuItem[key]?
menu.append menuItem
menu
module.exports = Menu

View file

@ -0,0 +1,7 @@
bindings = process.atomBinding 'power_monitor'
EventEmitter = require('events').EventEmitter
PowerMonitor = bindings.PowerMonitor
PowerMonitor::__proto__ = EventEmitter.prototype
module.exports = new PowerMonitor

View file

@ -0,0 +1,20 @@
protocol = process.atomBinding 'protocol'
EventEmitter = require('events').EventEmitter
protocol[key] = value for key, value of EventEmitter.prototype
protocol.RequestStringJob =
class RequestStringJob
constructor: ({mimeType, charset, data}) ->
if typeof data isnt 'string' and not data instanceof Buffer
throw new TypeError('Data should be string or Buffer')
@mimeType = mimeType ? 'text/plain'
@charset = charset ? 'UTF-8'
@data = String data
protocol.RequestFileJob =
class RequestFileJob
constructor: (@path) ->
module.exports = protocol

View file

@ -0,0 +1,10 @@
// 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.
#import <Cocoa/Cocoa.h>
@interface AtomApplicationDelegate : NSObject<NSApplicationDelegate> {
}
@end

View file

@ -0,0 +1,49 @@
// 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.
#import "atom/browser/atom_application_delegate_mac.h"
#include "base/strings/sys_string_conversions.h"
#import "atom/browser/atom_application_mac.h"
#include "atom/browser/browser.h"
@implementation AtomApplicationDelegate
- (void)applicationWillFinishLaunching:(NSNotification*)notify {
atom::Browser::Get()->WillFinishLaunching();
}
- (void)applicationDidFinishLaunching:(NSNotification*)notify {
atom::Browser::Get()->DidFinishLaunching();
}
- (BOOL)application:(NSApplication*)sender
openFile:(NSString*)filename {
std::string filename_str(base::SysNSStringToUTF8(filename));
return atom::Browser::Get()->OpenFile(filename_str) ? YES : NO;
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender {
atom::Browser* browser = atom::Browser::Get();
if (browser->is_quiting()) {
return NSTerminateNow;
} else {
// System started termination.
atom::Browser::Get()->Quit();
return NSTerminateLater;
}
}
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication
hasVisibleWindows:(BOOL)flag {
atom::Browser* browser = atom::Browser::Get();
if (flag) {
return YES;
} else {
browser->ActivateWithNoOpenWindows();
return NO;
}
}
@end

View file

@ -0,0 +1,23 @@
// 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.
#import "base/mac/scoped_sending_event.h"
@interface AtomApplication : NSApplication<CrAppProtocol,
CrAppControlProtocol> {
@private
BOOL handlingSendEvent_;
}
+ (AtomApplication*)sharedApplication;
// CrAppProtocol:
- (BOOL)isHandlingSendEvent;
// CrAppControlProtocol:
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
- (IBAction)closeAllWindows:(id)sender;
@end

View file

@ -0,0 +1,49 @@
// 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.
#import "atom/browser/atom_application_mac.h"
#include "base/auto_reset.h"
#include "base/strings/sys_string_conversions.h"
#include "atom/browser/browser.h"
@implementation AtomApplication
+ (AtomApplication*)sharedApplication {
return (AtomApplication*)[super sharedApplication];
}
- (BOOL)isHandlingSendEvent {
return handlingSendEvent_;
}
- (void)sendEvent:(NSEvent*)event {
base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
[super sendEvent:event];
}
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
handlingSendEvent_ = handlingSendEvent;
}
- (void)awakeFromNib {
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:self
andSelector:@selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
}
- (IBAction)closeAllWindows:(id)sender {
atom::Browser::Get()->Quit();
}
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
NSString* url = [
[event paramDescriptorForKeyword:keyDirectObject] stringValue];
atom::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url));
}
@end

View file

@ -0,0 +1,124 @@
// 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 "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/net/atom_url_request_context_getter.h"
#include "atom/browser/window_list.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "webkit/common/webpreferences.h"
namespace atom {
namespace {
struct FindByProcessId {
explicit FindByProcessId(int child_process_id)
: child_process_id_(child_process_id) {
}
bool operator() (NativeWindow* const window) {
int id = window->GetWebContents()->GetRenderProcessHost()->GetID();
return id == child_process_id_;
}
int child_process_id_;
};
} // namespace
AtomBrowserClient::AtomBrowserClient()
: dying_render_process_(NULL) {
}
AtomBrowserClient::~AtomBrowserClient() {
}
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) {
return static_cast<AtomBrowserContext*>(browser_context)->
CreateRequestContext(protocol_handlers);
}
void AtomBrowserClient::OverrideWebkitPrefs(
content::RenderViewHost* render_view_host,
const GURL& url,
WebPreferences* prefs) {
prefs->javascript_enabled = true;
prefs->web_security_enabled = true;
prefs->javascript_can_open_windows_automatically = true;
prefs->plugins_enabled = false;
prefs->dom_paste_enabled = true;
prefs->java_enabled = false;
prefs->allow_scripts_to_close_windows = true;
prefs->javascript_can_access_clipboard = true;
prefs->local_storage_enabled = true;
prefs->databases_enabled = true;
prefs->application_cache_enabled = true;
prefs->allow_universal_access_from_file_urls = true;
prefs->allow_file_access_from_file_urls = true;
prefs->experimental_webgl_enabled = false;
prefs->allow_displaying_insecure_content = true;
prefs->allow_running_insecure_content = true;
NativeWindow* window = NativeWindow::FromRenderView(
render_view_host->GetProcess()->GetID(),
render_view_host->GetRoutingID());
if (window)
window->OverrideWebkitPrefs(url, prefs);
}
bool AtomBrowserClient::ShouldSwapProcessesForNavigation(
content::SiteInstance* site_instance,
const GURL& current_url,
const GURL& new_url) {
if (site_instance->HasProcess())
dying_render_process_ = site_instance->GetProcess();
// Restart renderer process for all navigations.
return true;
}
void AtomBrowserClient::AppendExtraCommandLineSwitches(
CommandLine* command_line,
int child_process_id) {
WindowList* list = WindowList::GetInstance();
NativeWindow* window = NULL;
// Find the owner of this child process.
WindowList::const_iterator iter = std::find_if(
list->begin(), list->end(), FindByProcessId(child_process_id));
if (iter != list->end())
window = *iter;
// If the render process is a newly started one, which means the window still
// uses the old going-to-be-swapped render process, then we try to find the
// window from the swapped render process.
if (window == NULL && dying_render_process_ != NULL) {
child_process_id = dying_render_process_->GetID();
WindowList::const_iterator iter = std::find_if(
list->begin(), list->end(), FindByProcessId(child_process_id));
if (iter != list->end())
window = *iter;
}
if (window != NULL)
window->AppendExtraCommandLineSwitches(command_line, child_process_id);
dying_render_process_ = NULL;
}
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) {
return new AtomBrowserMainParts;
}
} // namespace atom

View file

@ -0,0 +1,43 @@
// 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_ATOM_BROWSER_CLIENT_
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_
#include "brightray/browser/browser_client.h"
namespace atom {
class AtomBrowserClient : public brightray::BrowserClient {
public:
AtomBrowserClient();
virtual ~AtomBrowserClient();
protected:
net::URLRequestContextGetter* CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
const GURL& url,
WebPreferences* prefs) OVERRIDE;
virtual bool ShouldSwapProcessesForNavigation(
content::SiteInstance* site_instance,
const GURL& current_url,
const GURL& new_url) OVERRIDE;
virtual void AppendExtraCommandLineSwitches(CommandLine* command_line,
int child_process_id) OVERRIDE;
private:
virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) OVERRIDE;
// The render process which would be swapped out soon.
content::RenderProcessHost* dying_render_process_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_BROWSER_CLIENT_

View file

@ -0,0 +1,82 @@
// 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 "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/net/atom_url_request_context_getter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h"
#include "vendor/brightray/browser/network_delegate.h"
namespace atom {
using content::BrowserThread;
class AtomResourceContext : public content::ResourceContext {
public:
AtomResourceContext() : getter_(NULL) {}
void set_url_request_context_getter(AtomURLRequestContextGetter* getter) {
getter_ = getter;
}
protected:
virtual net::HostResolver* GetHostResolver() OVERRIDE {
DCHECK(getter_);
return getter_->host_resolver();
}
virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
DCHECK(getter_);
return getter_->GetURLRequestContext();
}
virtual bool AllowMicAccess(const GURL& origin) OVERRIDE {
return true;
}
virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE {
return true;
}
private:
AtomURLRequestContextGetter* getter_;
DISALLOW_COPY_AND_ASSIGN(AtomResourceContext);
};
AtomBrowserContext::AtomBrowserContext()
: resource_context_(new AtomResourceContext) {
}
AtomBrowserContext::~AtomBrowserContext() {
}
AtomURLRequestContextGetter* AtomBrowserContext::CreateRequestContext(
content::ProtocolHandlerMap* protocol_handlers) {
DCHECK(!url_request_getter_);
url_request_getter_ = new AtomURLRequestContextGetter(
GetPath(),
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO),
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE),
base::Bind(&AtomBrowserContext::CreateNetworkDelegate,
base::Unretained(this)),
protocol_handlers);
resource_context_->set_url_request_context_getter(url_request_getter_.get());
return url_request_getter_.get();
}
content::ResourceContext* AtomBrowserContext::GetResourceContext() {
return resource_context_.get();
}
// static
AtomBrowserContext* AtomBrowserContext::Get() {
return static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context());
}
} // namespace atom

View file

@ -0,0 +1,46 @@
// 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_ATOM_BROWSER_CONTEXT_H_
#define ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
#include "base/memory/scoped_ptr.h"
#include "brightray/browser/browser_context.h"
namespace atom {
class AtomResourceContext;
class AtomURLRequestContextGetter;
class AtomBrowserContext : public brightray::BrowserContext {
public:
AtomBrowserContext();
virtual ~AtomBrowserContext();
// Returns the browser context singleton.
static AtomBrowserContext* Get();
// Creates or returns the request context.
AtomURLRequestContextGetter* CreateRequestContext(
content::ProtocolHandlerMap*);
AtomURLRequestContextGetter* url_request_context_getter() const {
DCHECK(url_request_getter_);
return url_request_getter_.get();
}
protected:
// content::BrowserContext implementations:
virtual content::ResourceContext* GetResourceContext() OVERRIDE;
private:
scoped_ptr<AtomResourceContext> resource_context_;
scoped_refptr<AtomURLRequestContextGetter> url_request_getter_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_

View file

@ -0,0 +1,101 @@
// 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 "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/browser.h"
#include "atom/common/node_bindings.h"
#include "net/proxy/proxy_resolver_v8.h"
#if defined(OS_WIN)
#include "ui/gfx/win/dpi.h"
#endif
#include "atom/common/v8/node_common.h"
namespace atom {
// static
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
AtomBrowserMainParts::AtomBrowserMainParts()
: atom_bindings_(new AtomBrowserBindings),
browser_(new Browser),
node_bindings_(NodeBindings::Create(true)) {
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
self_ = this;
}
AtomBrowserMainParts::~AtomBrowserMainParts() {
}
// static
AtomBrowserMainParts* AtomBrowserMainParts::Get() {
DCHECK(self_);
return self_;
}
brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
return new AtomBrowserContext();
}
void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization();
node_bindings_->Initialize();
v8::V8::Initialize();
// Create context.
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::Context> context = v8::Context::New(node_isolate);
// Create the global environment.
global_env = node_bindings_->CreateEnvironment(context);
// Wrap whole process in one global context.
context->Enter();
// Add atom-shell extended APIs.
atom_bindings_->BindTo(global_env->process_object());
}
void AtomBrowserMainParts::PreMainMessageLoopRun() {
brightray::BrowserMainParts::PreMainMessageLoopRun();
node_bindings_->PrepareMessageLoop();
node_bindings_->RunMessageLoop();
// Make sure the url request job factory is created before the
// will-finish-launching event.
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
GetRequestContext();
#if !defined(OS_MACOSX)
// The corresponding call in OS X is in AtomApplicationDelegate.
Browser::Get()->WillFinishLaunching();
Browser::Get()->DidFinishLaunching();
#endif
}
int AtomBrowserMainParts::PreCreateThreads() {
// Note that we are overriding the PreCreateThreads of brightray, since we
// are integrating node in browser, we can just be sure that an V8 instance
// would be prepared, while the ProxyResolverV8::CreateIsolate() would
// try to create a V8 isolate, which messed everything on Windows, so we
// have to override and call RememberDefaultIsolate on Windows instead.
net::ProxyResolverV8::RememberDefaultIsolate();
#if defined(OS_WIN)
gfx::EnableHighDPISupport();
#endif
return 0;
}
} // namespace atom

View file

@ -0,0 +1,51 @@
// 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_ATOM_BROWSER_MAIN_PARTS_
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_
#include "brightray/browser/browser_main_parts.h"
namespace atom {
class AtomBrowserBindings;
class Browser;
class NodeBindings;
class AtomBrowserMainParts : public brightray::BrowserMainParts {
public:
AtomBrowserMainParts();
virtual ~AtomBrowserMainParts();
static AtomBrowserMainParts* Get();
AtomBrowserBindings* atom_bindings() { return atom_bindings_.get(); }
Browser* browser() { return browser_.get(); }
protected:
// Implementations of brightray::BrowserMainParts.
virtual brightray::BrowserContext* CreateBrowserContext() OVERRIDE;
// Implementations of content::BrowserMainParts.
virtual void PostEarlyInitialization() OVERRIDE;
virtual void PreMainMessageLoopRun() OVERRIDE;
virtual int PreCreateThreads() OVERRIDE;
#if defined(OS_MACOSX)
virtual void PreMainMessageLoopStart() OVERRIDE;
virtual void PostDestroyThreads() OVERRIDE;
#endif
private:
scoped_ptr<AtomBrowserBindings> atom_bindings_;
scoped_ptr<Browser> browser_;
scoped_ptr<NodeBindings> node_bindings_;
static AtomBrowserMainParts* self_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_

View file

@ -0,0 +1,43 @@
// 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 "atom/browser/atom_browser_main_parts.h"
#include "base/files/file_path.h"
#import "base/mac/foundation_util.h"
#import "atom/browser/atom_application_mac.h"
#import "atom/browser/atom_application_delegate_mac.h"
#import "vendor/brightray/common/mac/main_application_bundle.h"
namespace atom {
void AtomBrowserMainParts::PreMainMessageLoopStart() {
// Force the NSApplication subclass to be used.
NSApplication* application = [AtomApplication sharedApplication];
AtomApplicationDelegate* delegate = [AtomApplicationDelegate alloc];
[NSApp setDelegate:delegate];
base::FilePath frameworkPath = brightray::MainApplicationBundlePath()
.Append("Contents")
.Append("Frameworks")
.Append("Atom Framework.framework");
NSBundle* frameworkBundle = [NSBundle
bundleWithPath:base::mac::FilePathToNSString(frameworkPath)];
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:@"MainMenu"
bundle:frameworkBundle];
[mainNib instantiateWithOwner:application topLevelObjects:nil];
[mainNib release];
// Prevent Cocoa from turning command-line arguments into
// |-application:openFiles:|, since we already handle them directly.
[[NSUserDefaults standardUserDefaults]
setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
}
void AtomBrowserMainParts::PostDestroyThreads() {
[[AtomApplication sharedApplication] setDelegate:nil];
}
} // namespace atom

View file

@ -0,0 +1,34 @@
// 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 "atom/browser/atom_javascript_dialog_manager.h"
#include "base/strings/utf_string_conversions.h"
namespace atom {
void AtomJavaScriptDialogManager::RunJavaScriptDialog(
content::WebContents* web_contents,
const GURL& origin_url,
const std::string& accept_lang,
content::JavaScriptMessageType javascript_message_type,
const string16& message_text,
const string16& default_prompt_text,
const DialogClosedCallback& callback,
bool* did_suppress_message) {
callback.Run(false, string16());
}
void AtomJavaScriptDialogManager::RunBeforeUnloadDialog(
content::WebContents* web_contents,
const string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) {
bool prevent_reload = message_text.empty() ||
message_text == ASCIIToUTF16("false");
callback.Run(!prevent_reload, message_text);
}
} // namespace atom

View file

@ -0,0 +1,37 @@
// 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_BROSER_ATOM_JAVASCRIPT_DIALOG_MANAGER_H_
#define ATOM_BROSER_ATOM_JAVASCRIPT_DIALOG_MANAGER_H_
#include "content/public/browser/javascript_dialog_manager.h"
namespace atom {
class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager {
public:
// content::JavaScriptDialogManager implementations.
virtual void RunJavaScriptDialog(
content::WebContents* web_contents,
const GURL& origin_url,
const std::string& accept_lang,
content::JavaScriptMessageType javascript_message_type,
const string16& message_text,
const string16& default_prompt_text,
const DialogClosedCallback& callback,
bool* did_suppress_message) OVERRIDE;
virtual void RunBeforeUnloadDialog(
content::WebContents* web_contents,
const string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) OVERRIDE;
virtual void CancelActiveAndPendingDialogs(
content::WebContents* web_contents) OVERRIDE {}
virtual void WebContentsDestroyed(
content::WebContents* web_contents) OVERRIDE {}
};
} // namespace atom
#endif // ATOM_BROSER_ATOM_JAVASCRIPT_DIALOG_MANAGER_H_

View file

@ -0,0 +1,19 @@
// 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 "atom/browser/auto_updater.h"
namespace auto_updater {
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL;
AutoUpdaterDelegate* AutoUpdater::GetDelegate() {
return delegate_;
}
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) {
delegate_ = delegate;
}
} // namespace auto_updater

View file

@ -0,0 +1,33 @@
// 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_AUTO_UPDATER_H_
#define ATOM_BROWSER_AUTO_UPDATER_H_
#include <string>
#include "base/basictypes.h"
namespace auto_updater {
class AutoUpdaterDelegate;
class AutoUpdater {
public:
// Gets/Sets the delegate.
static AutoUpdaterDelegate* GetDelegate();
static void SetDelegate(AutoUpdaterDelegate* delegate);
static void SetFeedURL(const std::string& url);
static void CheckForUpdates();
private:
static AutoUpdaterDelegate* delegate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
};
} // namespace auto_updater
#endif // ATOM_BROWSER_AUTO_UPDATER_H_

View file

@ -0,0 +1,45 @@
// 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_AUTO_UPDATER_DELEGATE_H_
#define ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
#include <string>
#include "base/callback_forward.h"
namespace base {
class Time;
}
namespace auto_updater {
class AutoUpdaterDelegate {
public:
// An error happened.
virtual void OnError(const std::string& error) {}
// Checking to see if there is an update
virtual void OnCheckingForUpdate() {}
// There is an update available and it is being downloaded
virtual void OnUpdateAvailable() {}
// There is no available update.
virtual void OnUpdateNotAvailable() {}
// There is a new update which has been downloaded.
virtual void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {}
protected:
virtual ~AutoUpdaterDelegate() {}
};
} // namespace auto_updater
#endif // ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_

View file

@ -0,0 +1,17 @@
// 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 "atom/browser/auto_updater.h"
namespace auto_updater {
// static
void AutoUpdater::SetFeedURL(const std::string& url) {
}
// static
void AutoUpdater::CheckForUpdates() {
}
} // namespace auto_updater

View file

@ -0,0 +1,92 @@
// 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 "atom/browser/auto_updater.h"
#import <ReactiveCocoa/RACCommand.h>
#import <ReactiveCocoa/RACSignal.h>
#import <ReactiveCocoa/NSObject+RACPropertySubscribing.h>
#import <Squirrel/Squirrel.h>
#include "base/bind.h"
#include "base/time/time.h"
#include "base/strings/sys_string_conversions.h"
#include "atom/browser/auto_updater_delegate.h"
#include <iostream>
namespace auto_updater {
namespace {
// The gloal SQRLUpdater object.
SQRLUpdater* g_updater = nil;
void RelaunchToInstallUpdate() {
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
AutoUpdaterDelegate* delegate = AutoUpdater::GetDelegate();
if (delegate)
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
}];
}
} // namespace
// static
void AutoUpdater::SetFeedURL(const std::string& feed) {
if (g_updater == nil) {
// Initialize the SQRLUpdater.
NSURL* url = [NSURL URLWithString:base::SysUTF8ToNSString(feed)];
NSURLRequest* urlRequest = [NSURLRequest requestWithURL:url];
g_updater = [[SQRLUpdater alloc] initWithUpdateRequest:urlRequest];
AutoUpdaterDelegate* delegate = GetDelegate();
if (!delegate)
return;
[[g_updater rac_valuesForKeyPath:@"state" observer:g_updater]
subscribeNext:^(NSNumber *stateNumber) {
int state = [stateNumber integerValue];
if (state == SQRLUpdaterStateCheckingForUpdate) {
delegate->OnCheckingForUpdate();
} else if (state == SQRLUpdaterStateDownloadingUpdate) {
delegate->OnUpdateAvailable();
}
}];
}
}
// static
void AutoUpdater::CheckForUpdates() {
AutoUpdaterDelegate* delegate = GetDelegate();
if (!delegate)
return;
[[[[g_updater.checkForUpdatesCommand
execute:nil]
// Send a `nil` after everything...
concat:[RACSignal return:nil]]
// But only take the first value. If an update is sent, we'll get that.
// Otherwise, we'll get our inserted `nil` value.
take:1]
subscribeNext:^(SQRLDownloadedUpdate *downloadedUpdate) {
if (downloadedUpdate) {
SQRLUpdate* update = downloadedUpdate.update;
// There is a new update that has been downloaded.
delegate->OnUpdateDownloaded(
base::SysNSStringToUTF8(update.releaseNotes),
base::SysNSStringToUTF8(update.releaseName),
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
base::SysNSStringToUTF8(update.updateURL.absoluteString),
base::Bind(RelaunchToInstallUpdate));
} else {
// When the completed event is sent with no update, then we know there
// is no update available.
delegate->OnUpdateNotAvailable();
}
} error:^(NSError *error) {
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
}];
}
} // namespace auto_updater

View file

@ -0,0 +1,17 @@
// 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 "atom/browser/auto_updater.h"
namespace auto_updater {
// static
void AutoUpdater::SetFeedURL(const std::string& url) {
}
// static
void AutoUpdater::CheckForUpdates() {
}
} // namespace auto_updater

118
atom/browser/browser.cc Normal file
View file

@ -0,0 +1,118 @@
// 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 "atom/browser/browser.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/window_list.h"
namespace atom {
Browser::Browser()
: is_quiting_(false) {
WindowList::AddObserver(this);
}
Browser::~Browser() {
WindowList::RemoveObserver(this);
}
// static
Browser* Browser::Get() {
return AtomBrowserMainParts::Get()->browser();
}
void Browser::Quit() {
is_quiting_ = true;
atom::WindowList* window_list = atom::WindowList::GetInstance();
if (window_list->size() == 0)
NotifyAndTerminate();
window_list->CloseAllWindows();
}
std::string Browser::GetVersion() const {
if (version_override_.empty()) {
std::string version = GetExecutableFileVersion();
if (!version.empty())
return version;
}
return version_override_;
}
void Browser::SetVersion(const std::string& version) {
version_override_ = version;
}
std::string Browser::GetName() const {
if (name_override_.empty()) {
std::string name = GetExecutableFileProductName();
if (!name.empty())
return name;
}
return name_override_;
}
void Browser::SetName(const std::string& name) {
name_override_ = name;
}
bool Browser::OpenFile(const std::string& file_path) {
bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver,
observers_,
OnOpenFile(&prevent_default, file_path));
return prevent_default;
}
void Browser::OpenURL(const std::string& url) {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnOpenURL(url));
}
void Browser::ActivateWithNoOpenWindows() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnActivateWithNoOpenWindows());
}
void Browser::WillFinishLaunching() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillFinishLaunching());
}
void Browser::DidFinishLaunching() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
}
void Browser::NotifyAndTerminate() {
bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));
if (prevent_default) {
is_quiting_ = false;
return;
}
Terminate();
}
void Browser::OnWindowCloseCancelled(NativeWindow* window) {
if (is_quiting_) {
// Once a beforeunload handler has prevented the closing, we think the quit
// is cancelled too.
is_quiting_ = false;
CancelQuit();
}
}
void Browser::OnWindowAllClosed() {
if (is_quiting_)
NotifyAndTerminate();
else
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWindowAllClosed());
}
} // namespace atom

113
atom/browser/browser.h Normal file
View file

@ -0,0 +1,113 @@
// 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_BROWSER_H_
#define ATOM_BROWSER_BROWSER_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/observer_list.h"
#include "atom/browser/browser_observer.h"
#include "atom/browser/window_list_observer.h"
namespace atom {
// This class is used for control application-wide operations.
class Browser : public WindowListObserver {
public:
Browser();
~Browser();
static Browser* Get();
// Try to close all windows and quit the application.
void Quit();
// Quit the application immediately without cleanup work.
void Terminate();
// Focus the application.
void Focus();
// Returns the version of the executable (or bundle).
std::string GetVersion() const;
// Overrides the application version.
void SetVersion(const std::string& version);
// Returns the application's name, default is just Atom-Shell.
std::string GetName() const;
// Overrides the application name.
void SetName(const std::string& name);
#if defined(OS_MACOSX)
// Bounce the dock icon.
enum BounceType {
BOUNCE_CRITICAL = 0,
BOUNCE_INFORMATIONAL = 10,
};
int DockBounce(BounceType type);
void DockCancelBounce(int request_id);
// Set/Get dock's badge text.
void DockSetBadgeText(const std::string& label);
std::string DockGetBadgeText();
#endif // defined(OS_MACOSX)
// Tell the application to open a file.
bool OpenFile(const std::string& file_path);
// Tell the application to open a url.
void OpenURL(const std::string& url);
// Tell the application that application is activated with no open windows.
void ActivateWithNoOpenWindows();
// Tell the application the loading has been done.
void WillFinishLaunching();
void DidFinishLaunching();
void AddObserver(BrowserObserver* obs) {
observers_.AddObserver(obs);
}
void RemoveObserver(BrowserObserver* obs) {
observers_.RemoveObserver(obs);
}
bool is_quiting() const { return is_quiting_; }
protected:
// Returns the version of application bundle or executable file.
std::string GetExecutableFileVersion() const;
// Returns the name of application bundle or executable file.
std::string GetExecutableFileProductName() const;
// Send the will-quit message and then terminate the application.
void NotifyAndTerminate();
// Tell the system we have cancelled quiting.
void CancelQuit();
bool is_quiting_;
private:
// WindowListObserver implementations:
virtual void OnWindowCloseCancelled(NativeWindow* window) OVERRIDE;
virtual void OnWindowAllClosed() OVERRIDE;
// Observers of the browser.
ObserverList<BrowserObserver> observers_;
std::string version_override_;
std::string name_override_;
DISALLOW_COPY_AND_ASSIGN(Browser);
};
} // namespace atom
#endif // ATOM_BROWSER_BROWSER_H_

View file

@ -0,0 +1,44 @@
// 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 "atom/browser/browser.h"
#include <stdlib.h>
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/atom_version.h"
namespace atom {
void Browser::Terminate() {
is_quiting_ = true;
exit(0);
}
void Browser::Focus() {
// Focus on the first visible window.
WindowList* list = WindowList::GetInstance();
for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) {
NativeWindow* window = *iter;
if (window->IsVisible()) {
window->Focus(true);
break;
}
}
}
std::string Browser::GetExecutableFileVersion() const {
return ATOM_VERSION_STRING;
}
std::string Browser::GetExecutableFileProductName() const {
return "Atom-Shell";
}
void Browser::CancelQuit() {
// No way to cancel quit on Linux.
}
} // namespace atom

View file

@ -0,0 +1,56 @@
// 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 "atom/browser/browser.h"
#import "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h"
#import "atom/browser/atom_application_mac.h"
namespace atom {
void Browser::Terminate() {
is_quiting_ = true;
[[AtomApplication sharedApplication] terminate:nil];
}
void Browser::Focus() {
[[AtomApplication sharedApplication] activateIgnoringOtherApps:YES];
}
std::string Browser::GetExecutableFileVersion() const {
NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary;
NSString *version = [infoDictionary objectForKey:@"CFBundleVersion"];
return base::SysNSStringToUTF8(version);
}
std::string Browser::GetExecutableFileProductName() const {
NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary;
NSString *version = [infoDictionary objectForKey:@"CFBundleName"];
return base::SysNSStringToUTF8(version);
}
void Browser::CancelQuit() {
[[AtomApplication sharedApplication] replyToApplicationShouldTerminate:NO];
}
int Browser::DockBounce(BounceType type) {
return [[AtomApplication sharedApplication] requestUserAttention:type];
}
void Browser::DockCancelBounce(int rid) {
[[AtomApplication sharedApplication] cancelUserAttentionRequest:rid];
}
void Browser::DockSetBadgeText(const std::string& label) {
NSDockTile *tile = [[AtomApplication sharedApplication] dockTile];
[tile setBadgeLabel:base::SysUTF8ToNSString(label)];
}
std::string Browser::DockGetBadgeText() {
NSDockTile *tile = [[AtomApplication sharedApplication] dockTile];
return base::SysNSStringToUTF8([tile badgeLabel]);
}
} // namespace atom

View file

@ -0,0 +1,43 @@
// 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_BROSER_BROWSER_OBSERVER_H_
#define ATOM_BROSER_BROWSER_OBSERVER_H_
#include <string>
namespace atom {
class BrowserObserver {
public:
// The browser has closed all windows and will quit.
virtual void OnWillQuit(bool* prevent_default) {}
// The browser has closed all windows. If the browser is quiting, then this
// method will not be called, instead it will call OnWillQuit.
virtual void OnWindowAllClosed() {}
// The browser has opened a file by double clicking in Finder or dragging the
// file to the Dock icon. (OS X only)
virtual void OnOpenFile(bool* prevent_default,
const std::string& file_path) {}
// Browser is used to open a url.
virtual void OnOpenURL(const std::string& url) {}
// The browser is activated with no open windows (usually by clicking on the
// dock icon).
virtual void OnActivateWithNoOpenWindows() {}
// The browser has finished loading.
virtual void OnWillFinishLaunching() {}
virtual void OnFinishLaunching() {}
protected:
virtual ~BrowserObserver() {}
};
} // namespace atom
#endif // ATOM_BROSER_BROWSER_OBSERVER_H_

View file

@ -0,0 +1,73 @@
// 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 "atom/browser/browser.h"
#include <windows.h>
#include "base/base_paths.h"
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "atom/common/atom_version.h"
namespace atom {
namespace {
BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
DWORD target_process_id = *reinterpret_cast<DWORD*>(param);
DWORD process_id = 0;
GetWindowThreadProcessId(hwnd, &process_id);
if (process_id == target_process_id) {
SetFocus(hwnd);
return FALSE;
}
return TRUE;
}
} // namespace
void Browser::Terminate() {
is_quiting_ = true;
PostQuitMessage(0);
}
void Browser::Focus() {
// On Windows we just focus on the first window found for this process.
DWORD pid = GetCurrentProcessId();
EnumWindows(&WindowsEnumerationHandler, reinterpret_cast<LPARAM>(&pid));
}
std::string Browser::GetExecutableFileVersion() const {
base::FilePath path;
if (PathService::Get(base::FILE_EXE, &path)) {
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(path));
return UTF16ToUTF8(version_info->product_version());
}
return ATOM_VERSION_STRING;
}
std::string Browser::GetExecutableFileProductName() const {
base::FilePath path;
if (PathService::Get(base::FILE_EXE, &path)) {
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(path));
return UTF16ToUTF8(version_info->product_name());
}
return "Atom-Shell";
}
void Browser::CancelQuit() {
// TODO(zcbenz): Research on how to cancel shutdown in Windows.
}
} // namespace atom

View file

@ -0,0 +1,204 @@
var app = require('app');
var dialog = require('dialog');
var ipc = require('ipc');
var Menu = require('menu');
var MenuItem = require('menu-item');
var BrowserWindow = require('browser-window');
var mainWindow = null;
var menu = null;
// Quit when all windows are closed.
app.on('window-all-closed', function() {
app.terminate();
});
app.on('open-url', function(event, url) {
dialog.showMessageBox({message: url, buttons: ['OK']});
});
app.on('ready', function() {
app.commandLine.appendSwitch('js-flags', '--harmony_collections');
mainWindow = new BrowserWindow({ width: 800, height: 600 });
mainWindow.loadUrl('file://' + __dirname + '/index.html');
mainWindow.on('page-title-updated', function(event, title) {
event.preventDefault();
this.setTitle('Atom Shell - ' + title);
});
mainWindow.on('closed', function() {
mainWindow = null;
});
mainWindow.on('unresponsive', function() {
console.log('unresponsive');
});
if (process.platform == 'darwin') {
var template = [
{
label: 'Atom Shell',
submenu: [
{
label: 'About Atom Shell',
selector: 'orderFrontStandardAboutPanel:'
},
{
type: 'separator'
},
{
label: 'Hide Atom Shell',
accelerator: 'Command+H',
selector: 'hide:'
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
selector: 'hideOtherApplications:'
},
{
label: 'Show All',
selector: 'unhideAllApplications:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
},
]
},
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'Command+Z',
selector: 'undo:'
},
{
label: 'Redo',
accelerator: 'Shift+Command+Z',
selector: 'redo:'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'Command+X',
selector: 'cut:'
},
{
label: 'Copy',
accelerator: 'Command+C',
selector: 'copy:'
},
{
label: 'Paste',
accelerator: 'Command+V',
selector: 'paste:'
},
{
label: 'Select All',
accelerator: 'Command+A',
selector: 'selectAll:'
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: function() { BrowserWindow.getFocusedWindow().restart(); }
},
{
label: 'Enter Fullscreen',
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+Command+I',
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
},
]
},
{
label: 'Window',
submenu: [
{
label: 'Minimize',
accelerator: 'Command+M',
selector: 'performMiniaturize:'
},
{
label: 'Close',
accelerator: 'Command+W',
selector: 'performClose:'
},
{
type: 'separator'
},
{
label: 'Bring All to Front',
selector: 'arrangeInFront:'
},
]
},
];
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
} else {
var template = [
{
label: 'File',
submenu: [
{
label: 'Open',
accelerator: 'Ctrl+O',
},
{
label: 'Close',
accelerator: 'Ctrl+W',
click: function() { mainWindow.close(); }
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Ctrl+R',
click: function() { mainWindow.restart(); }
},
{
label: 'Enter Fullscreen',
click: function() { mainWindow.setFullScreen(true); }
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+Ctrl+I',
click: function() { mainWindow.toggleDevTools(); }
},
]
},
];
menu = Menu.buildFromTemplate(template);
mainWindow.setMenu(menu);
}
ipc.on('message', function(processId, routingId, type) {
if (type == 'menu')
menu.popup(mainWindow);
});
});

View file

@ -0,0 +1,18 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Atom Shell</title>
</head>
<body>
This is the default mode of Atom Shell, please follow the instructions in
wiki to get started.
<script type="text/javascript" charset="utf-8">
var ipc = require('ipc');
window.addEventListener('contextmenu', function (e) {
e.preventDefault();
ipc.send('menu');
}, false);
</script>
</body>
</html>

View file

@ -0,0 +1,32 @@
var app = require('app');
var path = require('path');
var optimist = require('optimist');
// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
if (app.listeners('window-all-closed').length == 1)
app.quit();
});
var argv = optimist(process.argv.slice(1)).boolean('ci').argv;
// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (argv._.length > 0) {
try {
require(path.resolve(argv._[0]));
} catch(e) {
if (e.code == 'MODULE_NOT_FOUND') {
console.error(e.stack);
console.error('Specified app is invalid');
process.exit(1);
} else {
throw e;
}
}
} else if (argv.version) {
console.log('v' + process.versions['atom-shell']);
process.exit(0);
} else {
require('./default_app.js');
}

View file

@ -0,0 +1,8 @@
{
"name": "atom-shell-default-app",
"version": "0.1.0",
"main": "main.js",
"dependencies": {
"optimist": "*"
}
}

View file

@ -0,0 +1,122 @@
// Copyright (c) 2014 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 "atom/browser/devtools_delegate.h"
#include "base/message_loop/message_loop.h"
#include "base/values.h"
#include "atom/browser/native_window.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/point.h"
namespace atom {
DevToolsDelegate::DevToolsDelegate(NativeWindow* window,
content::WebContents* target_web_contents)
: content::WebContentsObserver(window->GetWebContents()),
owner_window_(window),
delegate_(NULL),
embedder_message_dispatcher_(
new DevToolsEmbedderMessageDispatcher(this)) {
content::WebContents* web_contents = window->GetWebContents();
// Setup devtools.
devtools_agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(
target_web_contents->GetRenderViewHost());
devtools_client_host_.reset(
content::DevToolsClientHost::CreateDevToolsFrontendHost(web_contents,
this));
content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
devtools_agent_host_.get(), devtools_client_host_.get());
// Go!
base::DictionaryValue options;
options.SetString("title", "DevTools Debugger");
window->InitFromOptions(&options);
window->AddObserver(this);
web_contents->GetController().LoadURL(
GURL("chrome-devtools://devtools/devtools.html?dockSide=undocked"),
content::Referrer(),
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
}
DevToolsDelegate::~DevToolsDelegate() {
}
void DevToolsDelegate::DispatchOnEmbedder(const std::string& message) {
embedder_message_dispatcher_->Dispatch(message);
}
void DevToolsDelegate::InspectedContentsClosing() {
owner_window_->Close();
}
void DevToolsDelegate::AboutToNavigateRenderView(
content::RenderViewHost* render_view_host) {
content::DevToolsClientHost::SetupDevToolsFrontendClient(
owner_window_->GetWebContents()->GetRenderViewHost());
}
void DevToolsDelegate::OnWindowClosed() {
base::MessageLoop::current()->DeleteSoon(FROM_HERE, owner_window_);
}
void DevToolsDelegate::ActivateWindow() {
}
void DevToolsDelegate::CloseWindow() {
owner_window_->Close();
}
void DevToolsDelegate::MoveWindow(int x, int y) {
owner_window_->SetPosition(gfx::Point(x, y));
}
void DevToolsDelegate::SetDockSide(const std::string& dock_side) {
bool succeed = true;
if (delegate_ &&
delegate_->DevToolsSetDockSide("attach-back", &succeed) &&
succeed)
owner_window_->Close();
}
void DevToolsDelegate::OpenInNewTab(const std::string& url) {
}
void DevToolsDelegate::SaveToFile(
const std::string& url, const std::string& content, bool save_as) {
}
void DevToolsDelegate::AppendToFile(
const std::string& url, const std::string& content) {
}
void DevToolsDelegate::RequestFileSystems() {
}
void DevToolsDelegate::AddFileSystem() {
}
void DevToolsDelegate::RemoveFileSystem(const std::string& file_system_path) {
}
void DevToolsDelegate::IndexPath(
int request_id, const std::string& file_system_path) {
}
void DevToolsDelegate::StopIndexing(int request_id) {
}
void DevToolsDelegate::SearchInPath(
int request_id,
const std::string& file_system_path,
const std::string& query) {
}
} // namespace atom

View file

@ -0,0 +1,85 @@
// Copyright (c) 2014 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_DEVTOOLS_DELEGATE_H_
#define ATOM_BROWSER_DEVTOOLS_DELEGATE_H_
#include "base/memory/scoped_ptr.h"
#include "atom/browser/native_window_observer.h"
#include "content/public/browser/devtools_frontend_host_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "vendor/brightray/browser/devtools_embedder_message_dispatcher.h"
#include "vendor/brightray/browser/inspectable_web_contents_delegate.h"
namespace content {
class DevToolsAgentHost;
class DevToolsClientHost;
}
using brightray::DevToolsEmbedderMessageDispatcher;
namespace atom {
class NativeWindow;
class DevToolsDelegate : public content::DevToolsFrontendHostDelegate,
public content::WebContentsObserver,
public NativeWindowObserver,
public DevToolsEmbedderMessageDispatcher::Delegate {
public:
DevToolsDelegate(NativeWindow* window,
content::WebContents* target_web_contents);
virtual ~DevToolsDelegate();
void SetDelegate(brightray::InspectableWebContentsDelegate* delegate) {
delegate_ = delegate;
}
protected:
// Implementations of content::DevToolsFrontendHostDelegate.
virtual void DispatchOnEmbedder(const std::string& message) OVERRIDE;
virtual void InspectedContentsClosing() OVERRIDE;
// Implementations of content::WebContentsObserver.
virtual void AboutToNavigateRenderView(
content::RenderViewHost* render_view_host) OVERRIDE;
// Implementations of NativeWindowObserver.
virtual void OnWindowClosed() OVERRIDE;
// Implementations of DevToolsEmbedderMessageDispatcher::Delegate.
virtual void ActivateWindow() OVERRIDE;
virtual void CloseWindow() OVERRIDE;
virtual void MoveWindow(int x, int y) OVERRIDE;
virtual void SetDockSide(const std::string& dock_side) OVERRIDE;
virtual void OpenInNewTab(const std::string& url) OVERRIDE;
virtual void SaveToFile(const std::string& url,
const std::string& content,
bool save_as) OVERRIDE;
virtual void AppendToFile(const std::string& url,
const std::string& content) OVERRIDE;
virtual void RequestFileSystems() OVERRIDE;
virtual void AddFileSystem() OVERRIDE;
virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE;
virtual void IndexPath(int request_id,
const std::string& file_system_path) OVERRIDE;
virtual void StopIndexing(int request_id) OVERRIDE;
virtual void SearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) OVERRIDE;
private:
NativeWindow* owner_window_;
brightray::InspectableWebContentsDelegate* delegate_;
scoped_refptr<content::DevToolsAgentHost> devtools_agent_host_;
scoped_ptr<content::DevToolsClientHost> devtools_client_host_;
scoped_ptr<DevToolsEmbedderMessageDispatcher> embedder_message_dispatcher_;
DISALLOW_COPY_AND_ASSIGN(DevToolsDelegate);
};
} // namespace atom
#endif // ATOM_BROWSER_DEVTOOLS_DELEGATE_H_

View file

@ -0,0 +1,80 @@
fs = require 'fs'
path = require 'path'
util = require 'util'
# Expose information of current process.
process.__atom_type = 'browser'
process.resourcesPath = path.resolve process.argv[1], '..', '..', '..'
# We modified the original process.argv to let node.js load the atom.js,
# we need to restore it here.
process.argv.splice 1, 1
# Pick out switches appended by atom-shell.
startMark = process.argv.indexOf '--atom-shell-switches-start'
endMark = process.argv.indexOf '--atom-shell-switches-end'
process.execArgv = process.argv.splice startMark, endMark - startMark + 1
# Add browser/api/lib to require's search paths,
# which contains javascript part of Atom's built-in libraries.
globalPaths = require('module').globalPaths
globalPaths.push path.join process.resourcesPath, 'browser', 'api', 'lib'
# Do loading in next tick since we still need some initialize work before
# native bindings can work.
setImmediate ->
# Import common settings.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init.js')
if process.platform is 'win32'
# Redirect node's console to use our own implementations, since node can not
# handle console output when running as GUI program.
print = (args...) ->
process.log util.format(args...)
console.log = console.error = console.warn = print
process.stdout.write = process.stderr.write = print
# Always returns EOF for stdin stream.
Readable = require('stream').Readable
stdin = new Readable
stdin.push null
process.__defineGetter__ 'stdin', -> stdin
# Don't quit on fatal error.
process.on 'uncaughtException', (error) ->
# Show error in GUI.
message = error.stack ? "#{error.name}: #{error.message}"
require('dialog').showMessageBox
type: 'warning'
title: 'An javascript error occured in the browser'
message: 'uncaughtException'
detail: message
buttons: ['OK']
# Load the RPC server.
require './rpc-server.js'
# Now we try to load app's package.json.
packageJson = null
packagePath = path.join process.resourcesPath, 'app'
try
# First we try to load process.resourcesPath/app
packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json')))
catch error
# If not found then we load browser/default_app
packagePath = path.join process.resourcesPath, 'browser', 'default_app'
packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json')))
# Set application's version.
app = require 'app'
app.setVersion packageJson.version if packageJson.version?
# Set application's name.
if packageJson.productName?
app.setName packageJson.productName
else if packageJson.name?
app.setName packageJson.name
# Finally load app's main.js and transfer control to C++.
require path.join(packagePath, packageJson.main)

View file

@ -0,0 +1,84 @@
EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map'
v8Util = process.atomBinding 'v8_util'
# Class to reference all objects.
class ObjectsStore
@stores = {}
constructor: ->
@nextId = 0
@objects = []
getNextId: ->
++@nextId
add: (obj) ->
id = @getNextId()
@objects[id] = obj
id
has: (id) ->
@objects[id]?
remove: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
delete @objects[id]
get: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
@objects[id]
@forRenderView: (processId, routingId) ->
key = "#{processId}_#{routingId}"
@stores[key] = new ObjectsStore unless @stores[key]?
@stores[key]
@releaseForRenderView: (processId, routingId) ->
key = "#{processId}_#{routingId}"
delete @stores[key]
class ObjectsRegistry extends EventEmitter
constructor: ->
@setMaxListeners Number.MAX_VALUE
# Objects in weak map will be not referenced (so we won't leak memory), and
# every object created in browser will have a unique id in weak map.
@objectsWeakMap = new IDWeakMap
@objectsWeakMap.add = (obj) ->
id = IDWeakMap::add.call this, obj
v8Util.setHiddenValue obj, 'atomId', id
id
# Register a new object, the object would be kept referenced until you release
# it explicitly.
add: (processId, routingId, obj) ->
# Some native objects may already been added to objectsWeakMap, be care not
# to add it twice.
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
id = v8Util.getHiddenValue obj, 'atomId'
# Store and reference the object, then return the storeId which points to
# where the object is stored. The caller can later dereference the object
# with the storeId.
# We use a difference key because the same object can be referenced for
# multiple times by the same renderer view.
store = ObjectsStore.forRenderView processId, routingId
storeId = store.add obj
[id, storeId]
# Get an object according to its id.
get: (id) ->
@objectsWeakMap.get id
# Remove an object according to its storeId.
remove: (processId, routingId, storeId) ->
ObjectsStore.forRenderView(processId, routingId).remove storeId
# Clear all references to objects from renderer view.
clear: (processId, routingId) ->
@emit "release-renderer-view-#{processId}-#{routingId}"
ObjectsStore.releaseForRenderView processId, routingId
module.exports = new ObjectsRegistry

View file

@ -0,0 +1,158 @@
ipc = require 'ipc'
path = require 'path'
objectsRegistry = require './objects-registry.js'
v8Util = process.atomBinding 'v8_util'
# Convert a real value into meta data.
valueToMeta = (processId, routingId, value) ->
meta = type: typeof value
meta.type = 'value' if value is null
meta.type = 'array' if Array.isArray value
# Treat the arguments object as array.
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
if meta.type is 'array'
meta.members = []
meta.members.push valueToMeta(processId, routingId, el) for el in value
else if meta.type is 'object' or meta.type is 'function'
meta.name = value.constructor.name
# Reference the original value if it's an object, because when it's
# passed to renderer we would assume the renderer keeps a reference of
# it.
[meta.id, meta.storeId] = objectsRegistry.add processId, routingId, value
meta.members = []
meta.members.push {name: prop, type: typeof field} for prop, field of value
else
meta.type = 'value'
meta.value = value
meta
# Convert Error into meta data.
errorToMeta = (error) ->
type: 'error', message: error.message, stack: (error.stack || error)
# Convert array of meta data from renderer into array of real values.
unwrapArgs = (processId, routingId, args) ->
metaToValue = (meta) ->
switch meta.type
when 'value' then meta.value
when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs processId, routingId, meta.value
when 'object'
ret = v8Util.createObjectWithName meta.name
for member in meta.members
ret[member.name] = metaToValue(member.value)
ret
when 'function-with-return-value'
returnValue = metaToValue meta.value
-> returnValue
when 'function'
rendererReleased = false
objectsRegistry.once "release-renderer-view-#{processId}-#{routingId}", ->
rendererReleased = true
ret = ->
throw new Error('Calling a callback of released renderer view') if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
v8Util.setDestructor ret, ->
return if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
ret
else throw new TypeError("Unknown type: #{meta.type}")
args.map metaToValue
# Call a function and send reply asynchronously if it's a an asynchronous
# style function and the caller didn't pass a callback.
callFunction = (event, processId, routingId, func, caller, args) ->
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
args.push (ret) ->
event.returnValue = valueToMeta processId, routingId, ret
func.apply caller, args
else
ret = func.apply caller, args
event.returnValue = valueToMeta processId, routingId, ret
# Send by BrowserWindow when its render view is deleted.
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (processId, routingId) ->
objectsRegistry.clear processId, routingId
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) ->
try
event.returnValue = valueToMeta processId, routingId, require(module)
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) ->
try
event.returnValue = valueToMeta processId, routingId, global[name]
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) ->
try
BrowserWindow = require 'browser-window'
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
event.returnValue = valueToMeta processId, routingId, window
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
try
args = unwrapArgs processId, routingId, args
constructor = objectsRegistry.get id
# Call new with array of arguments.
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) ->
try
args = unwrapArgs processId, routingId, args
func = objectsRegistry.get id
callFunction event, processId, routingId, func, global, args
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, method, args) ->
try
args = unwrapArgs processId, routingId, args
constructor = objectsRegistry.get(id)[method]
# Call new with array of arguments.
obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) ->
try
args = unwrapArgs processId, routingId, args
obj = objectsRegistry.get id
callFunction event, processId, routingId, obj[method], obj, args
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value) ->
try
obj = objectsRegistry.get id
obj[name] = value
event.returnValue = null
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) ->
try
obj = objectsRegistry.get id
event.returnValue = valueToMeta processId, routingId, obj[name]
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) ->
objectsRegistry.remove processId, routingId, storeId

View file

@ -0,0 +1,555 @@
// 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 "atom/browser/native_window.h"
#include <string>
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/prefs/pref_service.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_javascript_dialog_manager.h"
#include "atom/browser/browser.h"
#include "atom/browser/devtools_delegate.h"
#include "atom/browser/window_list.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/renderer_preferences.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/atom_version.h"
#include "atom/common/options_switches.h"
#include "ipc/ipc_message_macros.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "vendor/brightray/browser/inspectable_web_contents.h"
#include "vendor/brightray/browser/inspectable_web_contents_view.h"
#include "webkit/common/user_agent/user_agent_util.h"
#include "webkit/common/webpreferences.h"
using content::NavigationEntry;
namespace atom {
namespace {
const char kDockSidePref[] = "brightray.devtools.dockside";
} // namespace
NativeWindow::NativeWindow(content::WebContents* web_contents,
base::DictionaryValue* options)
: content::WebContentsObserver(web_contents),
has_frame_(true),
is_closed_(false),
node_integration_("except-iframe"),
has_dialog_attached_(false),
weak_factory_(this),
inspectable_web_contents_(
brightray::InspectableWebContents::Create(web_contents)) {
options->GetBoolean(switches::kFrame, &has_frame_);
#if defined(OS_MACOSX)
// Temporary fix for flashing devtools, try removing this after upgraded to
// Chrome 32.
web_contents->GetView()->SetAllowOverlappingViews(false);
#endif
// Read icon before window is created.
std::string icon;
if (options->GetString(switches::kIcon, &icon) && !SetIcon(icon))
LOG(ERROR) << "Failed to set icon to " << icon;
// Read iframe security before any navigation.
options->GetString(switches::kNodeIntegration, &node_integration_);
web_contents->SetDelegate(this);
inspectable_web_contents()->SetDelegate(this);
WindowList::AddWindow(this);
// Override the user agent to contain application and atom-shell's version.
Browser* browser = Browser::Get();
std::string product_name = base::StringPrintf(
"%s/%s Atom-Shell/" ATOM_VERSION_STRING,
browser->GetName().c_str(),
browser->GetVersion().c_str());
web_contents->GetMutableRendererPrefs()->user_agent_override =
webkit_glue::BuildUserAgentFromProduct(product_name);
// Get notified of title updated message.
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
content::Source<content::WebContents>(web_contents));
}
NativeWindow::~NativeWindow() {
// It's possible that the windows gets destroyed before it's closed, in that
// case we need to ensure the OnWindowClosed message is still notified.
NotifyWindowClosed();
}
// static
NativeWindow* NativeWindow::Create(base::DictionaryValue* options) {
content::WebContents::CreateParams create_params(AtomBrowserContext::Get());
return Create(content::WebContents::Create(create_params), options);
}
// static
NativeWindow* NativeWindow::Debug(content::WebContents* web_contents) {
base::DictionaryValue options;
NativeWindow* window = NativeWindow::Create(&options);
window->devtools_delegate_.reset(new DevToolsDelegate(window, web_contents));
return window;
}
// static
NativeWindow* NativeWindow::FromRenderView(int process_id, int routing_id) {
// Stupid iterating.
WindowList& window_list = *WindowList::GetInstance();
for (auto w = window_list.begin(); w != window_list.end(); ++w) {
auto& window = *w;
content::WebContents* web_contents = window->GetWebContents();
int window_process_id = web_contents->GetRenderProcessHost()->GetID();
int window_routing_id = web_contents->GetRoutingID();
if (window_routing_id == routing_id && window_process_id == process_id)
return window;
}
return NULL;
}
void NativeWindow::InitFromOptions(base::DictionaryValue* options) {
// Setup window from options.
int x = -1, y = -1;
bool center;
if (options->GetInteger(switches::kX, &x) &&
options->GetInteger(switches::kY, &y)) {
int width = -1, height = -1;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
Move(gfx::Rect(x, y, width, height));
} else if (options->GetBoolean(switches::kCenter, &center) && center) {
Center();
}
int min_height = -1, min_width = -1;
if (options->GetInteger(switches::kMinHeight, &min_height) &&
options->GetInteger(switches::kMinWidth, &min_width)) {
SetMinimumSize(gfx::Size(min_width, min_height));
}
int max_height = -1, max_width = -1;
if (options->GetInteger(switches::kMaxHeight, &max_height) &&
options->GetInteger(switches::kMaxWidth, &max_width)) {
SetMaximumSize(gfx::Size(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();
}
bool NativeWindow::HasModalDialog() {
return has_dialog_attached_;
}
void NativeWindow::OpenDevTools() {
if (devtools_window_) {
devtools_window_->Focus(true);
} else {
inspectable_web_contents()->ShowDevTools();
#if defined(OS_MACOSX)
// Temporary fix for flashing devtools, try removing this after upgraded to
// Chrome 32.
GetDevToolsWebContents()->GetView()->SetAllowOverlappingViews(false);
#endif
}
}
void NativeWindow::CloseDevTools() {
if (devtools_window_)
devtools_window_->Close();
else
inspectable_web_contents()->GetView()->CloseDevTools();
}
bool NativeWindow::IsDevToolsOpened() {
return (devtools_window_ && devtools_window_->IsFocused()) ||
inspectable_web_contents()->IsDevToolsViewShowing();
}
void NativeWindow::InspectElement(int x, int y) {
OpenDevTools();
content::RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
scoped_refptr<content::DevToolsAgentHost> agent(
content::DevToolsAgentHost::GetOrCreateFor(rvh));
agent->InspectElement(x, y);
}
void NativeWindow::FocusOnWebView() {
GetWebContents()->GetRenderViewHost()->Focus();
}
void NativeWindow::BlurWebView() {
GetWebContents()->GetRenderViewHost()->Blur();
}
bool NativeWindow::IsWebViewFocused() {
content::RenderWidgetHostView* host_view =
GetWebContents()->GetRenderViewHost()->GetView();
return host_view && host_view->HasFocus();
}
bool NativeWindow::SetIcon(const std::string& str_path) {
base::FilePath path = base::FilePath::FromUTF8Unsafe(str_path);
// Read the file from disk.
std::string file_contents;
if (path.empty() || !base::ReadFileToString(path, &file_contents))
return false;
// Decode the bitmap using WebKit's image decoder.
const unsigned char* data =
reinterpret_cast<const unsigned char*>(file_contents.data());
scoped_ptr<SkBitmap> decoded(new SkBitmap());
gfx::PNGCodec::Decode(data, file_contents.length(), decoded.get());
if (decoded->empty())
return false; // Unable to decode.
icon_ = gfx::Image::CreateFrom1xBitmap(*decoded.release());
return true;
}
base::ProcessHandle NativeWindow::GetRenderProcessHandle() {
return GetWebContents()->GetRenderProcessHost()->GetHandle();
}
void NativeWindow::CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback) {
gfx::Rect flipped_y_rect = rect;
flipped_y_rect.set_y(-rect.y());
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
flipped_y_rect,
gfx::Size(),
base::Bind(&NativeWindow::OnCapturePageDone,
weak_factory_.GetWeakPtr(),
callback));
}
void NativeWindow::CloseWebContents() {
bool prevent_default = false;
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
WillCloseWindow(&prevent_default));
if (prevent_default) {
WindowList::WindowCloseCancelled(this);
return;
}
content::WebContents* web_contents(GetWebContents());
// Assume the window is not responding if it doesn't cancel the close and is
// not closed in 500ms, in this way we can quickly show the unresponsive
// dialog when the window is busy executing some script withouth waiting for
// the unresponsive timeout.
if (!Browser::Get()->is_quiting() &&
window_unresposive_closure_.IsCancelled()) {
window_unresposive_closure_.Reset(
base::Bind(&NativeWindow::RendererUnresponsive,
weak_factory_.GetWeakPtr(),
web_contents));
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
window_unresposive_closure_.callback(),
base::TimeDelta::FromMilliseconds(500));
}
if (web_contents->NeedToFireBeforeUnload())
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
else
web_contents->Close();
}
content::WebContents* NativeWindow::GetWebContents() const {
return inspectable_web_contents_->GetWebContents();
}
content::WebContents* NativeWindow::GetDevToolsWebContents() const {
return inspectable_web_contents()->devtools_web_contents();
}
void NativeWindow::AppendExtraCommandLineSwitches(CommandLine* command_line,
int child_process_id) {
// Append --node-integration to renderer process.
command_line->AppendSwitchASCII(switches::kNodeIntegration,
node_integration_);
}
void NativeWindow::OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs) {
// FIXME Disable accelerated composition in frameless window.
if (!has_frame_)
prefs->accelerated_compositing_enabled = false;
}
void NativeWindow::NotifyWindowClosed() {
if (is_closed_)
return;
// The OnRenderViewDeleted is not called when the WebContents is destroyed
// directly (e.g. when closing the window), so we make sure it's always
// emitted to users by sending it before window is closed..
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnRenderViewDeleted(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID()));
is_closed_ = true;
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowClosed());
WindowList::RemoveWindow(this);
}
void NativeWindow::NotifyWindowBlur() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowBlur());
}
// In atom-shell all reloads and navigations started by renderer process would
// be redirected to this method, so we can have precise control of how we
// would open the url (in our case, is to restart the renderer process). See
// AtomRendererClient::ShouldFork for how this is done.
content::WebContents* NativeWindow::OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) {
if (params.disposition != CURRENT_TAB)
return NULL;
content::NavigationController::LoadURLParams load_url_params(params.url);
load_url_params.referrer = params.referrer;
load_url_params.transition_type = params.transition;
load_url_params.extra_headers = params.extra_headers;
load_url_params.should_replace_current_entry =
params.should_replace_current_entry;
load_url_params.is_renderer_initiated = params.is_renderer_initiated;
load_url_params.transferred_global_request_id =
params.transferred_global_request_id;
source->GetController().LoadURLWithParams(load_url_params);
return source;
}
content::JavaScriptDialogManager* NativeWindow::GetJavaScriptDialogManager() {
if (!dialog_manager_)
dialog_manager_.reset(new AtomJavaScriptDialogManager);
return dialog_manager_.get();
}
void NativeWindow::BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) {
*proceed_to_fire_unload = proceed;
if (!proceed)
WindowList::WindowCloseCancelled(this);
// When the "beforeunload" callback is fired the window is certainly live.
window_unresposive_closure_.Cancel();
}
void NativeWindow::RequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) {
GetWebContents()->GotResponseToLockMouseRequest(true);
}
bool NativeWindow::CanOverscrollContent() const {
return false;
}
void NativeWindow::ActivateContents(content::WebContents* contents) {
FocusOnWebView();
}
void NativeWindow::DeactivateContents(content::WebContents* contents) {
BlurWebView();
}
void NativeWindow::LoadingStateChanged(content::WebContents* source) {
bool is_loading = source->IsLoading();
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnLoadingStateChanged(is_loading));
}
void NativeWindow::MoveContents(content::WebContents* source,
const gfx::Rect& pos) {
SetPosition(pos.origin());
SetSize(pos.size());
}
void NativeWindow::CloseContents(content::WebContents* source) {
// When the web contents is gone, close the window immediately, but the
// memory will not be freed until you call delete.
// In this way, it would be safe to manage windows via smart pointers. If you
// want to free memory when the window is closed, you can do deleting by
// overriding the OnWindowClosed method in the observer.
CloseImmediately();
NotifyWindowClosed();
// Do not sent "unresponsive" event after window is closed.
window_unresposive_closure_.Cancel();
}
bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
// Only popup window can use things like window.moveTo.
return true;
}
void NativeWindow::RendererUnresponsive(content::WebContents* source) {
window_unresposive_closure_.Cancel();
if (!HasModalDialog())
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnRendererUnresponsive());
}
void NativeWindow::RendererResponsive(content::WebContents* source) {
window_unresposive_closure_.Cancel();
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
}
void NativeWindow::RenderViewDeleted(content::RenderViewHost* rvh) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnRenderViewDeleted(rvh->GetProcess()->GetID(),
rvh->GetRoutingID()));
}
void NativeWindow::RenderProcessGone(base::TerminationStatus status) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
}
void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired.
}
bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NativeWindow, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions,
UpdateDraggableRegions)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void NativeWindow::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
if (type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
std::pair<NavigationEntry*, bool>* title =
content::Details<std::pair<NavigationEntry*, bool>>(details).ptr();
if (title->first) {
bool prevent_default = false;
std::string text = UTF16ToUTF8(title->first->GetTitle());
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnPageTitleUpdated(&prevent_default, text));
if (!prevent_default)
SetTitle(text);
}
}
}
bool NativeWindow::DevToolsSetDockSide(const std::string& dock_side,
bool* succeed) {
if (dock_side == "undocked") {
*succeed = false;
return true;
} else {
return false;
}
}
bool NativeWindow::DevToolsShow(std::string* dock_side) {
if (*dock_side == "undocked")
*dock_side = "bottom";
return false;
}
void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap) {
std::vector<unsigned char> data;
if (succeed)
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data);
callback.Run(data);
}
void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args);
}
void NativeWindow::OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args,
this,
reply_msg);
}
} // namespace atom

View file

@ -0,0 +1,292 @@
// 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 "base/basictypes.h"
#include "base/cancelable_callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "atom/browser/native_window_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_observer.h"
#include "ui/gfx/image/image.h"
#include "vendor/brightray/browser/default_web_contents_delegate.h"
#include "vendor/brightray/browser/inspectable_web_contents_delegate.h"
#include "vendor/brightray/browser/inspectable_web_contents_impl.h"
class CommandLine;
struct WebPreferences;
namespace base {
class DictionaryValue;
class ListValue;
}
namespace content {
class BrowserContext;
class WebContents;
}
namespace gfx {
class Point;
class Rect;
class Size;
}
namespace IPC {
class Message;
}
namespace atom {
class AtomJavaScriptDialogManager;
class DevToolsDelegate;
struct DraggableRegion;
class NativeWindow : public brightray::DefaultWebContentsDelegate,
public brightray::InspectableWebContentsDelegate,
public content::WebContentsObserver,
public content::NotificationObserver {
public:
typedef base::Callback<void(const std::vector<unsigned char>& buffer)>
CapturePageCallback;
class DialogScope {
public:
explicit DialogScope(NativeWindow* window)
: window_(window) {
if (window_ != NULL)
window_->set_has_dialog_attached(true);
}
~DialogScope() {
if (window_ != NULL)
window_->set_has_dialog_attached(false);
}
private:
NativeWindow* window_;
DISALLOW_COPY_AND_ASSIGN(DialogScope);
};
virtual ~NativeWindow();
// Create window with existing WebContents, the caller is responsible for
// managing the window's live.
static NativeWindow* Create(content::WebContents* web_contents,
base::DictionaryValue* options);
// Create window with new WebContents, the caller is responsible for
// managing the window's live.
static NativeWindow* Create(base::DictionaryValue* options);
// Creates a devtools window to debug the WebContents, the returned window
// will manage its own life.
static NativeWindow* Debug(content::WebContents* web_contents);
// Find a window from its process id and routing id.
static NativeWindow* FromRenderView(int process_id, int routing_id);
void InitFromOptions(base::DictionaryValue* options);
virtual void Close() = 0;
virtual void CloseImmediately() = 0;
virtual void Move(const gfx::Rect& pos) = 0;
virtual void Focus(bool focus) = 0;
virtual bool IsFocused() = 0;
virtual void Show() = 0;
virtual void Hide() = 0;
virtual bool IsVisible() = 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(const gfx::Size& size) = 0;
virtual gfx::Size GetMinimumSize() = 0;
virtual void SetMaximumSize(const gfx::Size& size) = 0;
virtual gfx::Size GetMaximumSize() = 0;
virtual void SetResizable(bool resizable) = 0;
virtual bool IsResizable() = 0;
virtual void SetAlwaysOnTop(bool top) = 0;
virtual bool IsAlwaysOnTop() = 0;
virtual void Center() = 0;
virtual void SetPosition(const gfx::Point& position) = 0;
virtual gfx::Point GetPosition() = 0;
virtual void SetTitle(const std::string& title) = 0;
virtual std::string GetTitle() = 0;
virtual void FlashFrame(bool flash) = 0;
virtual void SetKiosk(bool kiosk) = 0;
virtual bool IsKiosk() = 0;
virtual bool HasModalDialog();
virtual gfx::NativeWindow GetNativeWindow() = 0;
virtual bool IsClosed() const { return is_closed_; }
virtual void OpenDevTools();
virtual void CloseDevTools();
virtual bool IsDevToolsOpened();
virtual void InspectElement(int x, int y);
virtual void FocusOnWebView();
virtual void BlurWebView();
virtual bool IsWebViewFocused();
virtual bool SetIcon(const std::string& path);
// Returns the process handle of render process, useful for killing the
// render process manually
virtual base::ProcessHandle GetRenderProcessHandle();
// Captures the page with |rect|, |callback| would be called when capturing is
// done.
virtual void CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback);
// The same with closing a tab in a real browser.
//
// Should be called by platform code when user want to close the window.
virtual void CloseWebContents();
base::WeakPtr<NativeWindow> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
content::WebContents* GetWebContents() const;
content::WebContents* GetDevToolsWebContents() const;
// Called when renderer process is going to be started.
void AppendExtraCommandLineSwitches(CommandLine* command_line,
int child_process_id);
void OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs);
void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs);
}
void RemoveObserver(NativeWindowObserver* obs) {
observers_.RemoveObserver(obs);
}
bool has_frame() const { return has_frame_; }
void set_has_dialog_attached(bool has_dialog_attached) {
has_dialog_attached_ = has_dialog_attached;
}
protected:
explicit NativeWindow(content::WebContents* web_contents,
base::DictionaryValue* options);
brightray::InspectableWebContentsImpl* inspectable_web_contents() const {
return static_cast<brightray::InspectableWebContentsImpl*>(
inspectable_web_contents_.get());
}
void NotifyWindowClosed();
void NotifyWindowBlur();
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) = 0;
// Implementations of content::WebContentsDelegate.
virtual content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) OVERRIDE;
virtual content::JavaScriptDialogManager*
GetJavaScriptDialogManager() OVERRIDE;
virtual void BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) OVERRIDE;
virtual void RequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) OVERRIDE;
virtual bool CanOverscrollContent() const OVERRIDE;
virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
virtual void DeactivateContents(content::WebContents* contents) OVERRIDE;
virtual void LoadingStateChanged(content::WebContents* source) OVERRIDE;
virtual void MoveContents(content::WebContents* source,
const gfx::Rect& pos) OVERRIDE;
virtual void CloseContents(content::WebContents* source) OVERRIDE;
virtual bool IsPopupOrPanel(
const content::WebContents* source) const OVERRIDE;
virtual void RendererUnresponsive(content::WebContents* source) OVERRIDE;
virtual void RendererResponsive(content::WebContents* source) OVERRIDE;
// Implementations of content::WebContentsObserver.
virtual void RenderViewDeleted(content::RenderViewHost*) OVERRIDE;
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
// Implementations of content::NotificationObserver.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Implementations of brightray::InspectableWebContentsDelegate.
virtual bool DevToolsSetDockSide(const std::string& dock_side,
bool* succeed) OVERRIDE;
virtual bool DevToolsShow(std::string* dock_side) OVERRIDE;
// Whether window has standard frame.
bool has_frame_;
// Window icon.
gfx::Image icon_;
private:
// Called when CapturePage has done.
void OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap);
void OnRendererMessage(const string16& channel,
const base::ListValue& args);
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg);
// Notification manager.
content::NotificationRegistrar registrar_;
// Observers of this window.
ObserverList<NativeWindowObserver> observers_;
// The windows has been closed.
bool is_closed_;
// The security token of iframe.
std::string node_integration_;
// There is a dialog that has been attached to window.
bool has_dialog_attached_;
// Closure that would be called when window is unresponsive when closing,
// it should be cancelled when we can prove that the window is responsive.
base::CancelableClosure window_unresposive_closure_;
base::WeakPtrFactory<NativeWindow> weak_factory_;
base::WeakPtr<NativeWindow> devtools_window_;
scoped_ptr<DevToolsDelegate> devtools_delegate_;
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
scoped_ptr<brightray::InspectableWebContents> inspectable_web_contents_;
DISALLOW_COPY_AND_ASSIGN(NativeWindow);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_H_

View file

@ -0,0 +1,466 @@
// Copyright (c) 2014 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 "atom/browser/native_window_gtk.h"
#include "base/values.h"
#include "atom/browser/ui/gtk/gtk_window_util.h"
#include "atom/common/draggable_region.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/renderer_preferences.h"
#include "ui/base/accelerators/platform_accelerator_gtk.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/gtk_util.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_utils_gtk.h"
namespace atom {
namespace {
// Dividing GTK's cursor blink cycle time (in milliseconds) by this value yields
// an appropriate value for content::RendererPreferences::caret_blink_interval.
// This matches the logic in the WebKit GTK port.
const double kGtkCursorBlinkCycleFactor = 2000.0;
} // namespace
NativeWindowGtk::NativeWindowGtk(content::WebContents* web_contents,
base::DictionaryValue* options)
: NativeWindow(web_contents, options),
window_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))),
vbox_(gtk_vbox_new(FALSE, 0)),
state_(GDK_WINDOW_STATE_WITHDRAWN),
is_always_on_top_(false),
suppress_window_raise_(false),
frame_cursor_(NULL) {
gtk_container_add(GTK_CONTAINER(window_), vbox_);
gtk_container_add(GTK_CONTAINER(vbox_),
GetWebContents()->GetView()->GetNativeView());
int width = 800, height = 600;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
gtk_window_set_default_size(window_, width, height);
if (!icon_.IsEmpty())
gtk_window_set_icon(window_, icon_.ToGdkPixbuf());
// In some (older) versions of compiz, raising top-level windows when they
// are partially off-screen causes them to get snapped back on screen, not
// always even on the current virtual desktop. If we are running under
// compiz, suppress such raises, as they are not necessary in compiz anyway.
if (ui::GuessWindowManager() == ui::WM_COMPIZ)
suppress_window_raise_ = true;
g_signal_connect(window_, "delete-event",
G_CALLBACK(OnWindowDeleteEventThunk), this);
g_signal_connect(window_, "focus-out-event",
G_CALLBACK(OnFocusOutThunk), this);
g_signal_connect(window_, "key-press-event",
G_CALLBACK(OnKeyPressThunk), this);
if (!has_frame_) {
gtk_window_set_decorated(window_, false);
g_signal_connect(window_, "motion-notify-event",
G_CALLBACK(OnMouseMoveEventThunk), this);
g_signal_connect(window_, "button-press-event",
G_CALLBACK(OnButtonPressThunk), this);
}
SetWebKitColorStyle();
}
NativeWindowGtk::~NativeWindowGtk() {
if (window_)
gtk_widget_destroy(GTK_WIDGET(window_));
}
void NativeWindowGtk::Close() {
CloseWebContents();
}
void NativeWindowGtk::CloseImmediately() {
gtk_widget_destroy(GTK_WIDGET(window_));
window_ = NULL;
}
void NativeWindowGtk::Move(const gfx::Rect& pos) {
gtk_window_move(window_, pos.x(), pos.y());
gtk_window_resize(window_, pos.width(), pos.height());
}
void NativeWindowGtk::Focus(bool focus) {
if (!IsVisible())
return;
if (focus)
gtk_window_present(window_);
else
gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
}
bool NativeWindowGtk::IsFocused() {
return gtk_window_is_active(window_);
}
void NativeWindowGtk::Show() {
gtk_widget_show_all(GTK_WIDGET(window_));
}
void NativeWindowGtk::Hide() {
gtk_widget_hide(GTK_WIDGET(window_));
}
bool NativeWindowGtk::IsVisible() {
return gtk_widget_get_visible(GTK_WIDGET(window_));
}
void NativeWindowGtk::Maximize() {
gtk_window_maximize(window_);
}
void NativeWindowGtk::Unmaximize() {
gtk_window_unmaximize(window_);
}
void NativeWindowGtk::Minimize() {
gtk_window_iconify(window_);
}
void NativeWindowGtk::Restore() {
gtk_window_present(window_);
}
void NativeWindowGtk::SetFullscreen(bool fullscreen) {
if (fullscreen)
gtk_window_fullscreen(window_);
else
gtk_window_unfullscreen(window_);
}
bool NativeWindowGtk::IsFullscreen() {
return state_ & GDK_WINDOW_STATE_FULLSCREEN;
}
void NativeWindowGtk::SetSize(const gfx::Size& size) {
gtk_window_resize(window_, size.width(), size.height());
}
gfx::Size NativeWindowGtk::GetSize() {
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
GdkRectangle frame_extents;
gdk_window_get_frame_extents(gdk_window, &frame_extents);
return gfx::Size(frame_extents.width, frame_extents.height);
}
void NativeWindowGtk::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size;
GdkGeometry geometry = { 0 };
geometry.min_width = size.width();
geometry.min_height = size.height();
int hints = GDK_HINT_POS | GDK_HINT_MIN_SIZE;
gtk_window_set_geometry_hints(
window_, GTK_WIDGET(window_), &geometry, (GdkWindowHints)hints);
}
gfx::Size NativeWindowGtk::GetMinimumSize() {
return minimum_size_;
}
void NativeWindowGtk::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
GdkGeometry geometry = { 0 };
geometry.max_width = size.width();
geometry.max_height = size.height();
int hints = GDK_HINT_POS | GDK_HINT_MAX_SIZE;
gtk_window_set_geometry_hints(
window_, GTK_WIDGET(window_), &geometry, (GdkWindowHints)hints);
}
gfx::Size NativeWindowGtk::GetMaximumSize() {
return maximum_size_;
}
void NativeWindowGtk::SetResizable(bool resizable) {
// Should request widget size after setting unresizable, otherwise the
// window will shrink to a very small size.
if (!IsResizable()) {
gint width, height;
gtk_window_get_size(window_, &width, &height);
gtk_widget_set_size_request(GTK_WIDGET(window_), width, height);
}
gtk_window_set_resizable(window_, resizable);
}
bool NativeWindowGtk::IsResizable() {
return gtk_window_get_resizable(window_);
}
void NativeWindowGtk::SetAlwaysOnTop(bool top) {
is_always_on_top_ = top;
gtk_window_set_keep_above(window_, top ? TRUE : FALSE);
}
bool NativeWindowGtk::IsAlwaysOnTop() {
return is_always_on_top_;
}
void NativeWindowGtk::Center() {
gtk_window_set_position(window_, GTK_WIN_POS_CENTER);
}
void NativeWindowGtk::SetPosition(const gfx::Point& position) {
gtk_window_move(window_, position.x(), position.y());
}
gfx::Point NativeWindowGtk::GetPosition() {
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
GdkRectangle frame_extents;
gdk_window_get_frame_extents(gdk_window, &frame_extents);
return gfx::Point(frame_extents.x, frame_extents.y);
}
void NativeWindowGtk::SetTitle(const std::string& title) {
gtk_window_set_title(window_, title.c_str());
}
std::string NativeWindowGtk::GetTitle() {
return gtk_window_get_title(window_);
}
void NativeWindowGtk::FlashFrame(bool flash) {
gtk_window_set_urgency_hint(window_, flash);
}
void NativeWindowGtk::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
}
bool NativeWindowGtk::IsKiosk() {
return IsFullscreen();
}
bool NativeWindowGtk::HasModalDialog() {
// FIXME(zcbenz): Implement me.
return false;
}
gfx::NativeWindow NativeWindowGtk::GetNativeWindow() {
return window_;
}
void NativeWindowGtk::SetMenu(ui::MenuModel* menu_model) {
menu_.reset(new ::MenuGtk(this, menu_model, true));
gtk_box_pack_start(GTK_BOX(vbox_), menu_->widget(), FALSE, FALSE, 0);
gtk_box_reorder_child(GTK_BOX(vbox_), menu_->widget(), 0);
RegisterAccelerators();
}
void NativeWindowGtk::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
draggable_region_.reset(new SkRegion);
// By default, the whole window is non-draggable. We need to explicitly
// include those draggable regions.
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);
}
}
void NativeWindowGtk::RegisterAccelerators() {
DCHECK(menu_);
accelerator_table_.clear();
accelerator_util::GenerateAcceleratorTable(&accelerator_table_,
menu_->model());
}
void NativeWindowGtk::SetWebKitColorStyle() {
content::RendererPreferences* prefs =
GetWebContents()->GetMutableRendererPrefs();
GtkStyle* frame_style = gtk_rc_get_style(GTK_WIDGET(window_));
prefs->focus_ring_color =
gfx::GdkColorToSkColor(frame_style->bg[GTK_STATE_SELECTED]);
prefs->thumb_active_color = SkColorSetRGB(244, 244, 244);
prefs->thumb_inactive_color = SkColorSetRGB(234, 234, 234);
prefs->track_color = SkColorSetRGB(211, 211, 211);
GtkWidget* url_entry = gtk_entry_new();
GtkStyle* entry_style = gtk_rc_get_style(url_entry);
prefs->active_selection_bg_color =
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
prefs->active_selection_fg_color =
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
prefs->inactive_selection_bg_color =
gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
prefs->inactive_selection_fg_color =
gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]);
gtk_widget_destroy(url_entry);
const base::TimeDelta cursor_blink_time = gfx::GetCursorBlinkCycle();
prefs->caret_blink_interval =
cursor_blink_time.InMilliseconds() ?
cursor_blink_time.InMilliseconds() / kGtkCursorBlinkCycleFactor :
0;
}
bool NativeWindowGtk::IsMaximized() const {
return state_ & GDK_WINDOW_STATE_MAXIMIZED;
}
bool NativeWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) {
if (has_frame_)
return false;
if (IsMaximized() || IsFullscreen())
return false;
return gtk_window_util::GetWindowEdge(GetSize(), 0, x, y, edge);
}
gboolean NativeWindowGtk::OnWindowDeleteEvent(GtkWidget* widget,
GdkEvent* event) {
Close();
return TRUE;
}
gboolean NativeWindowGtk::OnFocusOut(GtkWidget* window, GdkEventFocus*) {
NotifyWindowBlur();
return FALSE;
}
gboolean NativeWindowGtk::OnWindowState(GtkWidget* window,
GdkEventWindowState* event) {
state_ = event->new_window_state;
return FALSE;
}
gboolean NativeWindowGtk::OnMouseMoveEvent(GtkWidget* widget,
GdkEventMotion* event) {
if (has_frame_) {
// Reset the cursor.
if (frame_cursor_) {
frame_cursor_ = NULL;
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL);
}
return FALSE;
}
if (!IsResizable())
return FALSE;
// Update the cursor if we're on the custom frame border.
GdkWindowEdge edge;
bool has_hit_edge = GetWindowEdge(static_cast<int>(event->x),
static_cast<int>(event->y), &edge);
GdkCursorType new_cursor = GDK_LAST_CURSOR;
if (has_hit_edge)
new_cursor = gtk_window_util::GdkWindowEdgeToGdkCursorType(edge);
GdkCursorType last_cursor = GDK_LAST_CURSOR;
if (frame_cursor_)
last_cursor = frame_cursor_->type;
if (last_cursor != new_cursor) {
frame_cursor_ = has_hit_edge ? gfx::GetCursor(new_cursor) : NULL;
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)),
frame_cursor_);
}
return FALSE;
}
gboolean NativeWindowGtk::OnButtonPress(GtkWidget* widget,
GdkEventButton* event) {
DCHECK(!has_frame_);
// Make the button press coordinate relative to the browser window.
int win_x, win_y;
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
gdk_window_get_origin(gdk_window, &win_x, &win_y);
GdkWindowEdge edge;
gfx::Point point(static_cast<int>(event->x_root - win_x),
static_cast<int>(event->y_root - win_y));
bool has_hit_edge = IsResizable() &&
GetWindowEdge(point.x(), point.y(), &edge);
bool has_hit_titlebar =
draggable_region_ && draggable_region_->contains(event->x, event->y);
if (event->button == 1) {
if (GDK_BUTTON_PRESS == event->type) {
// Raise the window after a click on either the titlebar or the border to
// match the behavior of most window managers, unless that behavior has
// been suppressed.
if ((has_hit_titlebar || has_hit_edge) && !suppress_window_raise_)
gdk_window_raise(GTK_WIDGET(widget)->window);
if (has_hit_edge) {
gtk_window_begin_resize_drag(window_, edge, event->button,
static_cast<gint>(event->x_root),
static_cast<gint>(event->y_root),
event->time);
return TRUE;
} else if (has_hit_titlebar) {
GdkRectangle window_bounds = {0};
gdk_window_get_frame_extents(gdk_window, &window_bounds);
gfx::Rect bounds(window_bounds.x, window_bounds.y,
window_bounds.width, window_bounds.height);
return gtk_window_util::HandleTitleBarLeftMousePress(
window_, bounds, event);
}
} else if (GDK_2BUTTON_PRESS == event->type) {
if (has_hit_titlebar && IsResizable()) {
// Maximize/restore on double click.
if (IsMaximized())
gtk_window_unmaximize(window_);
else
gtk_window_maximize(window_);
return TRUE;
}
}
} else if (event->button == 2) {
if (has_hit_titlebar || has_hit_edge)
gdk_window_lower(gdk_window);
return TRUE;
}
return FALSE;
}
gboolean NativeWindowGtk::OnKeyPress(GtkWidget* widget, GdkEventKey* event) {
ui::Accelerator accelerator = ui::AcceleratorForGdkKeyCodeAndModifier(
event->keyval, static_cast<GdkModifierType>(event->state));
return accelerator_util::TriggerAcceleratorTableCommand(
&accelerator_table_, accelerator) ? TRUE: FALSE;
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
base::DictionaryValue* options) {
return new NativeWindowGtk(web_contents, options);
}
} // namespace atom

View file

@ -0,0 +1,131 @@
// Copyright (c) 2014 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_GTK_H_
#define ATOM_BROWSER_NATIVE_WINDOW_GTK_H_
#include <gtk/gtk.h>
#include "atom/browser/native_window.h"
#include "atom/browser/ui/accelerator_util.h"
#include "atom/browser/ui/gtk/menu_gtk.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/gtk/gtk_signal.h"
#include "ui/gfx/size.h"
namespace atom {
class NativeWindowGtk : public NativeWindow,
public MenuGtk::Delegate {
public:
explicit NativeWindowGtk(content::WebContents* web_contents,
base::DictionaryValue* options);
virtual ~NativeWindowGtk();
// 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 Hide() OVERRIDE;
virtual bool IsVisible() 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(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 SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual bool HasModalDialog() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
// Set the native window menu.
void SetMenu(ui::MenuModel* menu_model);
protected:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
private:
// Register accelerators supported by the menu model.
void RegisterAccelerators();
// Set WebKit's style from current theme.
void SetWebKitColorStyle();
// Whether window is maximized.
bool IsMaximized() const;
// If the point (|x|, |y|) is within the resize border area of the window,
// returns true and sets |edge| to the appropriate GdkWindowEdge value.
// Otherwise, returns false.
bool GetWindowEdge(int x, int y, GdkWindowEdge* edge);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowDeleteEvent,
GdkEvent*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnFocusOut, GdkEventFocus*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnWindowState,
GdkEventWindowState*);
// Mouse move and mouse button press callbacks.
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnMouseMoveEvent,
GdkEventMotion*);
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnButtonPress,
GdkEventButton*);
// Key press event callback.
CHROMEGTK_CALLBACK_1(NativeWindowGtk, gboolean, OnKeyPress, GdkEventKey*);
GtkWindow* window_;
GtkWidget* vbox_;
GdkWindowState state_;
bool is_always_on_top_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
// The region is treated as title bar, can be dragged to move and double
// clicked to maximize.
scoped_ptr<SkRegion> draggable_region_;
// If true, don't call gdk_window_raise() when we get a click in the title
// bar or window border. This is to work around a compiz bug.
bool suppress_window_raise_;
// The current window cursor. We set it to a resize cursor when over the
// custom frame border. We set it to NULL if we want the default cursor.
GdkCursor* frame_cursor_;
// The window menu.
scoped_ptr<MenuGtk> menu_;
// Map from accelerator to menu item's command id.
accelerator_util::AcceleratorTable accelerator_table_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowGtk);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_GTK_H_

View file

@ -0,0 +1,113 @@
// 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 "atom/browser/native_window.h"
class SkRegion;
namespace atom {
class NativeWindowMac : public NativeWindow {
public:
explicit NativeWindowMac(content::WebContents* web_contents,
base::DictionaryValue* options);
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 Hide() OVERRIDE;
virtual bool IsVisible() 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(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 SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual bool HasModalDialog() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
void NotifyWindowBlur() { NativeWindow::NotifyWindowBlur(); }
// Returns true if |point| in local Cocoa coordinate system falls within
// the draggable region.
bool IsWithinDraggableRegion(NSPoint point) const;
// Called to handle a mouse event.
void HandleMouseEvent(NSEvent* event);
// Clip web view to rounded corner.
void ClipWebView();
NSWindow*& window() { return window_; }
SkRegion* draggable_region() const { return draggable_region_.get(); }
protected:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
// Implementations of content::WebContentsDelegate.
virtual void HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE;
private:
void InstallView();
void UninstallView();
void InstallDraggableRegionViews();
void UpdateDraggableRegionsForCustomDrag(
const std::vector<DraggableRegion>& regions);
NSWindow* window_;
bool is_kiosk_;
NSInteger attention_request_id_; // identifier from requestUserAttention
// 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
// has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Mouse location since the last mouse event, in screen coordinates. This is
// used in custom drag to compute the window movement.
NSPoint last_mouse_offset_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_MAC_H_

View file

@ -0,0 +1,562 @@
// 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 "atom/browser/native_window_mac.h"
#include <string>
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "atom/browser/ui/cocoa/event_processing_window.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "atom/common/draggable_region.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/browser/render_view_host.h"
static const CGFloat kAtomWindowCornerRadius = 4.0;
@interface NSView (PrivateMethods)
- (CGFloat)roundedCornerRadius;
@end
@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
@private
atom::NativeWindowMac* shell_;
BOOL acceptsFirstMouse_;
}
- (id)initWithShell:(atom::NativeWindowMac*)shell;
- (void)setAcceptsFirstMouse:(BOOL)accept;
@end
@implementation AtomNSWindowDelegate
- (id)initWithShell:(atom::NativeWindowMac*)shell {
if ((self = [super init])) {
shell_ = shell;
acceptsFirstMouse_ = NO;
}
return self;
}
- (void)setAcceptsFirstMouse:(BOOL)accept {
acceptsFirstMouse_ = accept;
}
- (void)windowDidResignMain:(NSNotification*)notification {
shell_->NotifyWindowBlur();
}
- (void)windowDidResize:(NSNotification*)otification {
if (!shell_->has_frame())
shell_->ClipWebView();
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
if (!shell_->has_frame()) {
NSWindow* window = shell_->GetNativeWindow();
[[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
}
}
- (void)windowWillClose:(NSNotification*)notification {
shell_->window() = nil;
[self autorelease];
}
- (BOOL)windowShouldClose:(id)window {
// When user tries to close the window by clicking the close button, we do
// not close the window immediately, instead we try to close the web page
// fisrt, and when the web page is closed the window will also be closed.
shell_->CloseWebContents();
return NO;
}
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
return acceptsFirstMouse_;
}
@end
@interface AtomNSWindow : EventProcessingWindow {
@protected
atom::NativeWindowMac* shell_;
}
- (void)setShell:(atom::NativeWindowMac*)shell;
@end
@implementation AtomNSWindow
- (void)setShell:(atom::NativeWindowMac*)shell {
shell_ = shell;
}
- (IBAction)reload:(id)sender {
shell_->GetWebContents()->GetController().ReloadIgnoringCache(false);
}
- (IBAction)showDevTools:(id)sender {
shell_->OpenDevTools();
}
@end
@interface ControlRegionView : NSView {
@private
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
}
@end
@implementation ControlRegionView
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
if ((self = [super init]))
shellWindow_ = shellWindow;
return self;
}
- (BOOL)mouseDownCanMoveWindow {
return NO;
}
- (NSView*)hitTest:(NSPoint)aPoint {
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
return nil;
}
return self;
}
- (void)mouseDown:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
- (void)mouseDragged:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
@end
namespace atom {
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
base::DictionaryValue* options)
: NativeWindow(web_contents, options),
is_kiosk_(false),
attention_request_id_(0) {
int width = 800, height = 600;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect cocoa_bounds = NSMakeRect(
round((NSWidth(main_screen_rect) - width) / 2) ,
round((NSHeight(main_screen_rect) - height) / 2),
width,
height);
AtomNSWindow* atomWindow;
atomWindow = [[AtomNSWindow alloc]
initWithContentRect:cocoa_bounds
styleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask
backing:NSBackingStoreBuffered
defer:YES];
[atomWindow setShell:this];
window_ = atomWindow;
AtomNSWindowDelegate* delegate =
[[AtomNSWindowDelegate alloc] initWithShell:this];
[window() setDelegate:delegate];
// Enable the NSView to accept first mouse event.
bool acceptsFirstMouse = false;
options->GetBoolean(switches::kAcceptFirstMouse, &acceptsFirstMouse);
[delegate setAcceptsFirstMouse:acceptsFirstMouse];
// 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 = inspectable_web_contents()->GetView()->GetNativeView();
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView();
}
NativeWindowMac::~NativeWindowMac() {
if (window())
[window() release];
}
void NativeWindowMac::Close() {
[window() performClose:nil];
}
void NativeWindowMac::CloseImmediately() {
[window() orderOut:nil];
[window() close];
}
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 (!IsVisible())
return;
if (focus) {
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[window() makeKeyAndOrderFront:nil];
} else {
[window() orderBack:nil];
}
}
bool NativeWindowMac::IsFocused() {
return [window() isKeyWindow];
}
void NativeWindowMac::Show() {
[window() makeKeyAndOrderFront:nil];
}
void NativeWindowMac::Hide() {
[window() orderOut:nil];
}
bool NativeWindowMac::IsVisible() {
return [window() isVisible];
}
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 == IsFullscreen())
return;
if (!base::mac::IsOSLionOrLater()) {
LOG(ERROR) << "Fullscreen mode is only supported above Lion";
return;
}
[window() toggleFullScreen:nil];
}
bool NativeWindowMac::IsFullscreen() {
return [window() styleMask] & NSFullScreenWindowMask;
}
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(const gfx::Size& size) {
NSSize min_size = NSMakeSize(size.width(), size.height());
NSView* content = [window() contentView];
[window() setContentMinSize:[content convertSize:min_size toView:nil]];
}
gfx::Size NativeWindowMac::GetMinimumSize() {
NSView* content = [window() contentView];
NSSize min_size = [content convertSize:[window() contentMinSize]
fromView:nil];
return gfx::Size(min_size.width, min_size.height);
}
void NativeWindowMac::SetMaximumSize(const gfx::Size& size) {
NSSize max_size = NSMakeSize(size.width(), size.height());
NSView* content = [window() contentView];
[window() setContentMaxSize:[content convertSize:max_size toView:nil]];
}
gfx::Size NativeWindowMac::GetMaximumSize() {
NSView* content = [window() contentView];
NSSize max_size = [content convertSize:[window() contentMaxSize]
fromView:nil];
return gfx::Size(max_size.width, max_size.height);
}
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];
}
}
bool NativeWindowMac::IsResizable() {
return [window() styleMask] & NSResizableWindowMask;
}
void NativeWindowMac::SetAlwaysOnTop(bool top) {
[window() setLevel:(top ? NSFloatingWindowLevel : NSNormalWindowLevel)];
}
bool NativeWindowMac::IsAlwaysOnTop() {
return [window() level] == NSFloatingWindowLevel;
}
void NativeWindowMac::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)];
}
std::string NativeWindowMac::GetTitle() {
return base::SysNSStringToUTF8([window() 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;
SetFullscreen(true);
} else {
[NSApp setPresentationOptions:[NSApp currentSystemPresentationOptions]];
is_kiosk_ = false;
SetFullscreen(false);
}
}
bool NativeWindowMac::IsKiosk() {
return is_kiosk_;
}
bool NativeWindowMac::HasModalDialog() {
return [window() attachedSheet] != nil;
}
gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
return window();
}
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region_)
return false;
NSView* webView = GetWebContents()->GetView()->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
// to match these two.
return draggable_region_->contains(point.x, webViewHeight - point.y);
}
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
NSPoint current_mouse_location =
[window() convertBaseToScreen:[event locationInWindow]];
if ([event type] == NSLeftMouseDown) {
NSPoint frame_origin = [window() frame].origin;
last_mouse_offset_ = NSMakePoint(
frame_origin.x - current_mouse_location.x,
frame_origin.y - current_mouse_location.y);
} else if ([event type] == NSLeftMouseDragged) {
[window() setFrameOrigin:NSMakePoint(
current_mouse_location.x + last_mouse_offset_.x,
current_mouse_location.y + last_mouse_offset_.y)];
}
}
void NativeWindowMac::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
UpdateDraggableRegionsForCustomDrag(regions);
InstallDraggableRegionViews();
}
void NativeWindowMac::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
if (event.skip_in_browser ||
event.type == content::NativeWebKeyboardEvent::Char)
return;
EventProcessingWindow* event_window =
static_cast<EventProcessingWindow*>(window());
DCHECK([event_window isKindOfClass:[EventProcessingWindow class]]);
[event_window redispatchKeyEvent:event.os_event];
}
void NativeWindowMac::InstallView() {
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
if (has_frame_) {
[view setFrame:[[window() contentView] bounds]];
[[window() contentView] addSubview:view];
} else {
NSView* frameView = [[window() contentView] superview];
[view setFrame:[frameView bounds]];
[frameView addSubview:view];
ClipWebView();
[[window() standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window() standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window() standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
}
}
void NativeWindowMac::UninstallView() {
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
[view removeFromSuperview];
}
void NativeWindowMac::ClipWebView() {
NSView* view = GetWebContents()->GetView()->GetNativeView();
view.wantsLayer = YES;
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()->GetView()->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<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(
const std::vector<DraggableRegion>& regions) {
// We still need one ControlRegionView to cover the whole window such that
// mouse events could be captured.
NSView* web_view = GetWebContents()->GetView()->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<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
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
base::DictionaryValue* options) {
return new NativeWindowMac(web_contents, options);
}
} // namespace atom

View file

@ -0,0 +1,47 @@
// 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_OBSERVER_H_
#define ATOM_BROWSER_NATIVE_WINDOW_OBSERVER_H_
#include <string>
namespace atom {
class NativeWindowObserver {
public:
virtual ~NativeWindowObserver() {}
// Called when the web page of the window has updated it's document title.
virtual void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) {}
// Called when the window is starting or is done loading a page.
virtual void OnLoadingStateChanged(bool is_loading) {}
// Called when the window is gonna closed.
virtual void WillCloseWindow(bool* prevent_default) {}
// Called when the window is closed.
virtual void OnWindowClosed() {}
// Called when window loses focus.
virtual void OnWindowBlur() {}
// Called when renderer is hung.
virtual void OnRendererUnresponsive() {}
// Called when renderer recovers.
virtual void OnRendererResponsive() {}
// Called when a render view has been deleted.
virtual void OnRenderViewDeleted(int process_id, int routing_id) {}
// Called when renderer has crashed.
virtual void OnRendererCrashed() {}
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_OBSERVER_H_

View file

@ -0,0 +1,544 @@
// 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 "atom/browser/native_window_win.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/ui/win/menu_2.h"
#include "atom/browser/ui/win/native_menu_win.h"
#include "atom/common/draggable_region.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/gfx/path.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/native_widget_win.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/native_frame_view.h"
namespace atom {
namespace {
const int kResizeInsideBoundsSize = 5;
const int kResizeAreaCornerSize = 16;
// Wrapper of NativeWidgetWin to handle WM_MENUCOMMAND messages, which are
// triggered by window menus.
class MenuCommandNativeWidget : public views::NativeWidgetWin {
public:
explicit MenuCommandNativeWidget(NativeWindowWin* delegate)
: views::NativeWidgetWin(delegate->window()),
delegate_(delegate) {}
virtual ~MenuCommandNativeWidget() {}
protected:
virtual bool PreHandleMSG(UINT message,
WPARAM w_param,
LPARAM l_param,
LRESULT* result) OVERRIDE {
if (message == WM_MENUCOMMAND) {
delegate_->OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
*result = 0;
return true;
} else {
return false;
}
}
private:
NativeWindowWin* delegate_;
DISALLOW_COPY_AND_ASSIGN(MenuCommandNativeWidget);
};
class NativeWindowClientView : public views::ClientView {
public:
NativeWindowClientView(views::Widget* widget,
NativeWindowWin* contents_view)
: views::ClientView(widget, contents_view) {
}
virtual ~NativeWindowClientView() {}
virtual bool CanClose() OVERRIDE {
static_cast<NativeWindowWin*>(contents_view())->CloseWebContents();
return false;
}
private:
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
};
class NativeWindowFrameView : public views::NativeFrameView {
public:
explicit NativeWindowFrameView(views::Widget* frame, NativeWindowWin* shell)
: NativeFrameView(frame),
shell_(shell) {
}
virtual ~NativeWindowFrameView() {}
virtual gfx::Size GetMinimumSize() OVERRIDE {
return shell_->GetMinimumSize();
}
virtual gfx::Size GetMaximumSize() OVERRIDE {
return shell_->GetMaximumSize();
}
private:
NativeWindowWin* shell_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
};
class NativeWindowFramelessView : public views::NonClientFrameView {
public:
explicit NativeWindowFramelessView(views::Widget* frame,
NativeWindowWin* shell)
: frame_(frame),
shell_(shell) {
}
virtual ~NativeWindowFramelessView() {}
// views::NonClientFrameView implementations:
virtual gfx::Rect NativeWindowFramelessView::GetBoundsForClientView() const
OVERRIDE {
return bounds();
}
virtual gfx::Rect NativeWindowFramelessView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const OVERRIDE {
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;
}
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
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 (shell_->draggable_region() &&
shell_->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;
}
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 implementations:
virtual gfx::Size NativeWindowFramelessView::GetPreferredSize() OVERRIDE {
gfx::Size pref = frame_->client_view()->GetPreferredSize();
gfx::Rect bounds(0, 0, pref.width(), pref.height());
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
bounds).size();
}
virtual gfx::Size GetMinimumSize() OVERRIDE {
return shell_->GetMinimumSize();
}
virtual gfx::Size GetMaximumSize() OVERRIDE {
return shell_->GetMaximumSize();
}
private:
views::Widget* frame_;
NativeWindowWin* shell_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
};
} // namespace
NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
base::DictionaryValue* options)
: NativeWindow(web_contents, options),
window_(new views::Widget),
web_view_(new views::WebView(NULL)),
resizable_(true) {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.delegate = this;
params.native_widget = new MenuCommandNativeWidget(this);
params.remove_standard_frame = !has_frame_;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
window_->Init(params);
int width = 800, height = 600;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
gfx::Size size(width, height);
window_->CenterWindow(size);
window_->UpdateWindowIcon();
web_view_->SetWebContents(web_contents);
OnViewWasResized();
}
NativeWindowWin::~NativeWindowWin() {
}
void NativeWindowWin::Close() {
window_->Close();
}
void NativeWindowWin::CloseImmediately() {
window_->CloseNow();
}
void NativeWindowWin::Move(const gfx::Rect& bounds) {
window_->SetBounds(bounds);
}
void NativeWindowWin::Focus(bool focus) {
if (focus)
window_->Activate();
else
window_->Deactivate();
}
bool NativeWindowWin::IsFocused() {
return window_->IsActive();
}
void NativeWindowWin::Show() {
window_->Show();
}
void NativeWindowWin::Hide() {
window_->Hide();
}
void NativeWindowWin::Maximize() {
window_->Maximize();
}
void NativeWindowWin::Unmaximize() {
window_->Restore();
}
bool NativeWindowWin::IsVisible() {
return window_->IsVisible();
}
void NativeWindowWin::Minimize() {
window_->Minimize();
}
void NativeWindowWin::Restore() {
window_->Restore();
}
void NativeWindowWin::SetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
}
bool NativeWindowWin::IsFullscreen() {
return window_->IsFullscreen();
}
void NativeWindowWin::SetSize(const gfx::Size& size) {
window_->SetSize(size);
}
gfx::Size NativeWindowWin::GetSize() {
return window_->GetWindowBoundsInScreen().size();
}
void NativeWindowWin::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size;
}
gfx::Size NativeWindowWin::GetMinimumSize() {
return minimum_size_;
}
void NativeWindowWin::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
}
gfx::Size NativeWindowWin::GetMaximumSize() {
return maximum_size_;
}
void NativeWindowWin::SetResizable(bool resizable) {
resizable_ = resizable;
}
bool NativeWindowWin::IsResizable() {
return resizable_;
}
void NativeWindowWin::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top);
}
bool NativeWindowWin::IsAlwaysOnTop() {
DWORD style = ::GetWindowLong(window_->GetNativeView(), GWL_EXSTYLE);
return style & WS_EX_TOPMOST;
}
void NativeWindowWin::Center() {
window_->CenterWindow(GetSize());
}
void NativeWindowWin::SetPosition(const gfx::Point& position) {
window_->SetBounds(gfx::Rect(position, GetSize()));
}
gfx::Point NativeWindowWin::GetPosition() {
return window_->GetWindowBoundsInScreen().origin();
}
void NativeWindowWin::SetTitle(const std::string& title) {
title_ = UTF8ToUTF16(title);
window_->UpdateWindowTitle();
}
std::string NativeWindowWin::GetTitle() {
return UTF16ToUTF8(title_);
}
void NativeWindowWin::FlashFrame(bool flash) {
window_->FlashFrame(flash);
}
void NativeWindowWin::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
}
bool NativeWindowWin::IsKiosk() {
return IsFullscreen();
}
gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
return window_->GetNativeView();
}
void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
DCHECK(menu_);
menu_->wrapper()->OnMenuCommand(position, menu);
}
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
menu_.reset(new atom::Menu2(menu_model, true));
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
RegisterAccelerators();
}
void NativeWindowWin::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
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<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);
OnViewWasResized();
}
void NativeWindowWin::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
if (event.type == WebKit::WebInputEvent::RawKeyDown) {
ui::Accelerator accelerator(
static_cast<ui::KeyboardCode>(event.windowsKeyCode),
content::GetModifiersFromNativeWebKeyboardEvent(event));
if (GetFocusManager()->ProcessAccelerator(accelerator)) {
return;
}
}
// Any unhandled keyboard/character messages should be defproced.
// This allows stuff like F10, etc to work correctly.
DefWindowProc(event.os_event.hwnd, event.os_event.message,
event.os_event.wParam, event.os_event.lParam);
}
void NativeWindowWin::Layout() {
DCHECK(web_view_);
web_view_->SetBounds(0, 0, width(), height());
OnViewWasResized();
}
void NativeWindowWin::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && details.child == this)
AddChildView(web_view_);
}
bool NativeWindowWin::AcceleratorPressed(
const ui::Accelerator& accelerator) {
return accelerator_util::TriggerAcceleratorTableCommand(
&accelerator_table_, accelerator);
}
void NativeWindowWin::DeleteDelegate() {
// Do nothing, window is managed by users.
}
views::View* NativeWindowWin::GetInitiallyFocusedView() {
return web_view_;
}
bool NativeWindowWin::CanResize() const {
return resizable_;
}
bool NativeWindowWin::CanMaximize() const {
return resizable_;
}
string16 NativeWindowWin::GetWindowTitle() const {
return title_;
}
bool NativeWindowWin::ShouldHandleSystemCommands() const {
return true;
}
gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
if (icon_.IsEmpty())
return gfx::ImageSkia();
else
return *icon_.ToImageSkia();
}
gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
return GetWindowAppIcon();
}
views::Widget* NativeWindowWin::GetWidget() {
return window_.get();
}
const views::Widget* NativeWindowWin::GetWidget() const {
return window_.get();
}
views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
return new NativeWindowClientView(widget, this);
}
views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
views::Widget* widget) {
if (has_frame_)
return new NativeWindowFrameView(widget, this);
return new NativeWindowFramelessView(widget, this);
}
void NativeWindowWin::OnViewWasResized() {
// Set the window shape of the RWHV.
gfx::Size sz = web_view_->size();
int height = sz.height(), width = sz.width();
gfx::Path path;
path.addRect(0, 0, width, height);
SetWindowRgn(web_contents()->GetView()->GetNativeView(),
path.CreateNativeRegion(),
1);
SkRegion* rgn = new SkRegion;
if (!window_->IsFullscreen() && !window_->IsMaximized()) {
if (draggable_region())
rgn->op(*draggable_region(), SkRegion::kUnion_Op);
if (!has_frame_ && CanResize()) {
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);
}
}
content::WebContents* web_contents = GetWebContents();
if (web_contents->GetRenderViewHost()->GetView())
web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
}
void NativeWindowWin::RegisterAccelerators() {
views::FocusManager* focus_manager = GetFocusManager();
accelerator_table_.clear();
focus_manager->UnregisterAccelerators(this);
accelerator_util::GenerateAcceleratorTable(&accelerator_table_,
menu_->model());
accelerator_util::AcceleratorTable::const_iterator iter;
for (iter = accelerator_table_.begin();
iter != accelerator_table_.end();
++iter) {
focus_manager->RegisterAccelerator(
iter->first, ui::AcceleratorManager::kNormalPriority, this);
}
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
base::DictionaryValue* options) {
return new NativeWindowWin(web_contents, options);
}
} // namespace atom

View file

@ -0,0 +1,138 @@
// 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_WIN_H_
#define ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/accelerator_util.h"
#include "ui/gfx/size.h"
#include "ui/views/widget/widget_delegate.h"
namespace ui {
class MenuModel;
}
namespace views {
class WebView;
class Widget;
}
namespace atom {
class Menu2;
class NativeWindowWin : public NativeWindow,
public views::WidgetDelegateView {
public:
explicit NativeWindowWin(content::WebContents* web_contents,
base::DictionaryValue* options);
virtual ~NativeWindowWin();
// 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 Hide() OVERRIDE;
virtual bool IsVisible() 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(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 SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
void OnMenuCommand(int position, HMENU menu);
// Set the native window menu.
void SetMenu(ui::MenuModel* menu_model);
views::Widget* window() const { return window_.get(); }
SkRegion* draggable_region() { return draggable_region_.get(); }
protected:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
// Overridden from content::WebContentsDelegate:
virtual void HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE;
// Overridden from views::View:
virtual void Layout() OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
// Overridden from views::WidgetDelegate:
virtual void DeleteDelegate() OVERRIDE;
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
virtual bool CanResize() const OVERRIDE;
virtual bool CanMaximize() const OVERRIDE;
virtual string16 GetWindowTitle() const OVERRIDE;
virtual bool ShouldHandleSystemCommands() const OVERRIDE;
virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
virtual views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) OVERRIDE;
private:
typedef struct { int position; ui::MenuModel* model; } MenuItem;
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
void OnViewWasResized();
// Register accelerators supported by the menu model.
void RegisterAccelerators();
scoped_ptr<views::Widget> window_;
views::WebView* web_view_; // managed by window_.
// The window menu.
scoped_ptr<atom::Menu2> menu_;
// Map from accelerator to menu item's command id.
accelerator_util::AcceleratorTable accelerator_table_;
scoped_ptr<SkRegion> draggable_region_;
bool resizable_;
string16 title_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowWin);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_WINDOW_WIN_H_

View file

@ -0,0 +1,112 @@
// 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 "atom/browser/net/adapter_request_job.h"
#include "base/threading/sequenced_worker_pool.h"
#include "atom/browser/net/url_request_string_job.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_file_job.h"
namespace atom {
AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
net::URLRequest* request,
net::NetworkDelegate* network_delegate)
: URLRequestJob(request, network_delegate),
protocol_handler_(protocol_handler),
weak_factory_(this) {
}
void AdapterRequestJob::Start() {
DCHECK(!real_job_);
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
weak_factory_.GetWeakPtr()));
}
void AdapterRequestJob::Kill() {
if (real_job_) // Kill could happen when real_job_ is created.
real_job_->Kill();
}
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) {
DCHECK(real_job_);
return real_job_->ReadRawData(buf, buf_size, bytes_read);
}
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
DCHECK(real_job_);
return real_job_->IsRedirectResponse(location, http_status_code);
}
net::Filter* AdapterRequestJob::SetupFilter() const {
DCHECK(real_job_);
return real_job_->SetupFilter();
}
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
DCHECK(real_job_);
return real_job_->GetMimeType(mime_type);
}
bool AdapterRequestJob::GetCharset(std::string* charset) {
DCHECK(real_job_);
return real_job_->GetCharset(charset);
}
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void AdapterRequestJob::CreateErrorJobAndStart(int error_code) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
real_job_ = new net::URLRequestErrorJob(
request(), network_delegate(), error_code);
real_job_->Start();
}
void AdapterRequestJob::CreateStringJobAndStart(const std::string& mime_type,
const std::string& charset,
const std::string& data) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
real_job_ = new URLRequestStringJob(
request(), network_delegate(), mime_type, charset, data);
real_job_->Start();
}
void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
real_job_ = new net::URLRequestFileJob(
request(),
network_delegate(),
path,
content::BrowserThread::GetBlockingPool()->
GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
real_job_->Start();
}
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
DCHECK(protocol_handler_);
real_job_ = protocol_handler_->MaybeCreateJob(request(),
network_delegate());
if (!real_job_.get())
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
else
real_job_->Start();
}
} // namespace atom

View file

@ -0,0 +1,68 @@
// 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_NET_ADAPTER_REQUEST_JOB_H_
#define ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
#include "base/memory/weak_ptr.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
namespace base {
class FilePath;
}
namespace atom {
// Ask JS which type of job it wants, and then delegate corresponding methods.
class AdapterRequestJob : public net::URLRequestJob {
public:
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
AdapterRequestJob(ProtocolHandler* protocol_handler,
net::URLRequest* request,
net::NetworkDelegate* network_delegate);
public:
// net::URLRequestJob:
virtual void Start() OVERRIDE;
virtual void Kill() OVERRIDE;
virtual bool ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) OVERRIDE;
virtual bool IsRedirectResponse(GURL* location,
int* http_status_code) OVERRIDE;
virtual net::Filter* SetupFilter() const OVERRIDE;
virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
virtual bool GetCharset(std::string* charset) OVERRIDE;
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
// Override this function to determine which job should be started.
virtual void GetJobTypeInUI() = 0;
void CreateErrorJobAndStart(int error_code);
void CreateStringJobAndStart(const std::string& mime_type,
const std::string& charset,
const std::string& data);
void CreateFileJobAndStart(const base::FilePath& path);
void CreateJobFromProtocolHandlerAndStart();
private:
// The delegated request job.
scoped_refptr<net::URLRequestJob> real_job_;
// Default protocol handler.
ProtocolHandler* protocol_handler_;
base::WeakPtrFactory<AdapterRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AdapterRequestJob);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_

View file

@ -0,0 +1,183 @@
// 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 "atom/browser/net/atom_url_request_context_getter.h"
#include "base/strings/string_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "content/public/common/url_constants.h"
#include "net/cert/cert_verifier.h"
#include "net/cookies/cookie_monster.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_server_properties_impl.h"
#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_script_fetcher_impl.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_service_v8.h"
#include "net/ssl/default_server_bound_cert_store.h"
#include "net/ssl/server_bound_cert_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/file_protocol_handler.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "vendor/brightray/browser/network_delegate.h"
namespace atom {
using content::BrowserThread;
AtomURLRequestContextGetter::AtomURLRequestContextGetter(
const base::FilePath& base_path,
base::MessageLoop* io_loop,
base::MessageLoop* file_loop,
base::Callback<scoped_ptr<brightray::NetworkDelegate>(void)> factory,
content::ProtocolHandlerMap* protocol_handlers)
: base_path_(base_path),
io_loop_(io_loop),
file_loop_(file_loop),
job_factory_(NULL),
network_delegate_factory_(factory) {
// Must first be created on the UI thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::swap(protocol_handlers_, *protocol_handlers);
// We must create the proxy config service on the UI loop on Linux because it
// must synchronously run on the glib message loop. This will be passed to
// the URLRequestContextStorage on the IO thread in GetURLRequestContext().
proxy_config_service_.reset(
net::ProxyService::CreateSystemProxyConfigService(
io_loop_->message_loop_proxy(),
file_loop_));
}
AtomURLRequestContextGetter::~AtomURLRequestContextGetter() {
}
net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
base::AutoLock auto_lock(lock_);
if (!url_request_context_.get()) {
url_request_context_.reset(new net::URLRequestContext());
network_delegate_ = network_delegate_factory_.Run().Pass();
url_request_context_->set_network_delegate(network_delegate_.get());
storage_.reset(
new net::URLRequestContextStorage(url_request_context_.get()));
storage_->set_cookie_store(content::CreatePersistentCookieStore(
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
false,
nullptr,
nullptr,
nullptr));
storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
new net::DefaultServerBoundCertStore(NULL),
base::WorkerPool::GetTaskRunner(true)));
storage_->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings(
"en-us,en", EmptyString()));
scoped_ptr<net::HostResolver> host_resolver(
net::HostResolver::CreateDefaultResolver(NULL));
net::DhcpProxyScriptFetcherFactory dhcp_factory;
storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
storage_->set_transport_security_state(new net::TransportSecurityState);
storage_->set_proxy_service(
net::CreateProxyServiceUsingV8ProxyResolver(
proxy_config_service_.release(),
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
dhcp_factory.Create(url_request_context_.get()),
host_resolver.get(),
NULL,
url_request_context_->network_delegate()));
storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
storage_->set_http_auth_handler_factory(
net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
scoped_ptr<net::HttpServerProperties> server_properties(
new net::HttpServerPropertiesImpl);
storage_->set_http_server_properties(server_properties.Pass());
base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
net::HttpCache::DefaultBackend* main_backend =
new net::HttpCache::DefaultBackend(
net::DISK_CACHE,
net::CACHE_BACKEND_DEFAULT,
cache_path,
0,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
net::HttpNetworkSession::Params network_session_params;
network_session_params.cert_verifier =
url_request_context_->cert_verifier();
network_session_params.transport_security_state =
url_request_context_->transport_security_state();
network_session_params.server_bound_cert_service =
url_request_context_->server_bound_cert_service();
network_session_params.proxy_service =
url_request_context_->proxy_service();
network_session_params.ssl_config_service =
url_request_context_->ssl_config_service();
network_session_params.http_auth_handler_factory =
url_request_context_->http_auth_handler_factory();
network_session_params.network_delegate =
url_request_context_->network_delegate();
network_session_params.http_server_properties =
url_request_context_->http_server_properties();
network_session_params.ignore_certificate_errors = false;
// Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
storage_->set_host_resolver(host_resolver.Pass());
network_session_params.host_resolver =
url_request_context_->host_resolver();
net::HttpCache* main_cache = new net::HttpCache(
network_session_params, main_backend);
storage_->set_http_transaction_factory(main_cache);
DCHECK(!job_factory_);
job_factory_ = new AtomURLRequestJobFactory;
for (content::ProtocolHandlerMap::iterator it = protocol_handlers_.begin();
it != protocol_handlers_.end();
++it) {
bool set_protocol = job_factory_->SetProtocolHandler(
it->first,
it->second.release());
DCHECK(set_protocol);
}
protocol_handlers_.clear();
scoped_ptr<net::FileProtocolHandler> file_protocol_handler(
new net::FileProtocolHandler(
content::BrowserThread::GetBlockingPool()->
GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
job_factory_->SetProtocolHandler(chrome::kDataScheme,
new net::DataProtocolHandler);
job_factory_->SetProtocolHandler(chrome::kFileScheme,
file_protocol_handler.release());
storage_->set_job_factory(job_factory_);
}
return url_request_context_.get();
}
scoped_refptr<base::SingleThreadTaskRunner>
AtomURLRequestContextGetter::GetNetworkTaskRunner() const {
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
net::HostResolver* AtomURLRequestContextGetter::host_resolver() {
return url_request_context_->host_resolver();
}
} // namespace atom

View file

@ -0,0 +1,76 @@
// 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_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/content_browser_client.h"
#include "net/url_request/url_request_context_getter.h"
namespace base {
class MessageLoop;
}
namespace brightray {
class NetworkDelegate;
}
namespace net {
class HostResolver;
class ProxyConfigService;
class URLRequestContextStorage;
}
namespace atom {
class AtomURLRequestJobFactory;
class AtomURLRequestContextGetter : public net::URLRequestContextGetter {
public:
AtomURLRequestContextGetter(
const base::FilePath& base_path,
base::MessageLoop* io_loop,
base::MessageLoop* file_loop,
base::Callback<scoped_ptr<brightray::NetworkDelegate>(void)>,
content::ProtocolHandlerMap* protocol_handlers);
// net::URLRequestContextGetter implementations:
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
virtual scoped_refptr<base::SingleThreadTaskRunner>
GetNetworkTaskRunner() const OVERRIDE;
net::HostResolver* host_resolver();
net::URLRequestContextStorage* storage() const { return storage_.get(); }
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
protected:
virtual ~AtomURLRequestContextGetter();
private:
base::FilePath base_path_;
base::MessageLoop* io_loop_;
base::MessageLoop* file_loop_;
AtomURLRequestJobFactory* job_factory_;
base::Callback<scoped_ptr<brightray::NetworkDelegate>(void)>
network_delegate_factory_;
base::Lock lock_;
scoped_ptr<net::ProxyConfigService> proxy_config_service_;
scoped_ptr<brightray::NetworkDelegate> network_delegate_;
scoped_ptr<net::URLRequestContextStorage> storage_;
scoped_ptr<net::URLRequestContext> url_request_context_;
content::ProtocolHandlerMap protocol_handlers_;
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestContextGetter);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_

View file

@ -0,0 +1,109 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "base/stl_util.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
namespace atom {
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
AtomURLRequestJobFactory::AtomURLRequestJobFactory() {}
AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
STLDeleteValues(&protocol_handler_map_);
}
bool AtomURLRequestJobFactory::SetProtocolHandler(
const std::string& scheme,
ProtocolHandler* protocol_handler) {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
if (!protocol_handler) {
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return false;
delete it->second;
protocol_handler_map_.erase(it);
return true;
}
if (ContainsKey(protocol_handler_map_, scheme))
return false;
protocol_handler_map_[scheme] = protocol_handler;
return true;
}
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
const std::string& scheme,
ProtocolHandler* protocol_handler) {
DCHECK(CalledOnValidThread());
DCHECK(protocol_handler);
base::AutoLock locked(lock_);
if (!ContainsKey(protocol_handler_map_, scheme))
return NULL;
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
protocol_handler_map_[scheme] = protocol_handler;
return original_protocol_handler;
}
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return NULL;
return it->second;
}
bool AtomURLRequestJobFactory::HasProtocolHandler(
const std::string& scheme) const {
base::AutoLock locked(lock_);
return ContainsKey(protocol_handler_map_, scheme);
}
net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return NULL;
return it->second->MaybeCreateJob(request, network_delegate);
}
bool AtomURLRequestJobFactory::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
return HasProtocolHandler(scheme) ||
net::URLRequest::IsHandledProtocol(scheme);
}
bool AtomURLRequestJobFactory::IsHandledURL(const GURL& url) const {
if (!url.is_valid()) {
// We handle error cases.
return true;
}
return IsHandledProtocol(url.scheme());
}
bool AtomURLRequestJobFactory::IsSafeRedirectTarget(
const GURL& location) const {
return IsHandledURL(location);
}
} // namespace atom

View file

@ -0,0 +1,62 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. 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_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
#include <map>
#include <vector>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/synchronization/lock.h"
#include "net/url_request/url_request_job_factory.h"
namespace atom {
class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
public:
AtomURLRequestJobFactory();
virtual ~AtomURLRequestJobFactory();
// Sets the ProtocolHandler for a scheme. Returns true on success, false on
// failure (a ProtocolHandler already exists for |scheme|). On success,
// URLRequestJobFactory takes ownership of |protocol_handler|.
bool SetProtocolHandler(const std::string& scheme,
ProtocolHandler* protocol_handler);
// Intercepts the ProtocolHandler for a scheme. Returns the original protocol
// handler on success, otherwise returns NULL.
ProtocolHandler* ReplaceProtocol(const std::string& scheme,
ProtocolHandler* protocol_handler);
// Returns the protocol handler registered with scheme.
ProtocolHandler* GetProtocolHandler(const std::string& scheme) const;
// Whether the protocol handler is registered by the job factory.
bool HasProtocolHandler(const std::string& scheme) const;
// URLRequestJobFactory implementation
virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const OVERRIDE;
virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE;
virtual bool IsHandledURL(const GURL& url) const OVERRIDE;
virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE;
private:
typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap;
ProtocolHandlerMap protocol_handler_map_;
mutable base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_

View file

@ -0,0 +1,33 @@
// 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 "atom/browser/net/url_request_string_job.h"
#include "net/base/net_errors.h"
namespace atom {
URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const std::string& mime_type,
const std::string& charset,
const std::string& data)
: net::URLRequestSimpleJob(request, network_delegate),
mime_type_(mime_type),
charset_(charset),
data_(data) {
}
int URLRequestStringJob::GetData(
std::string* mime_type,
std::string* charset,
std::string* data,
const net::CompletionCallback& callback) const {
*mime_type = mime_type_;
*charset = charset_;
*data = data_;
return net::OK;
}
} // namespace atom

View 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_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
#define ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
#include "net/url_request/url_request_simple_job.h"
namespace atom {
class URLRequestStringJob : public net::URLRequestSimpleJob {
public:
URLRequestStringJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const std::string& mime_type,
const std::string& charset,
const std::string& data);
// URLRequestSimpleJob:
virtual int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
const net::CompletionCallback& callback) const OVERRIDE;
private:
std::string mime_type_;
std::string charset_;
std::string data_;
DISALLOW_COPY_AND_ASSIGN(URLRequestStringJob);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.github.atom</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.10.7</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>AtomApplication</string>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

View file

@ -0,0 +1,107 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,7,0
PRODUCTVERSION 0,10,7,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Atom-Shell"
VALUE "FileVersion", "0.10.7"
VALUE "InternalName", "atom.exe"
VALUE "LegalCopyright", "Copyright (C) 2013 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "atom.exe"
VALUE "ProductName", "Atom-Shell"
VALUE "ProductVersion", "0.10.7"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
IDR_MAINFRAME ICON "atom.ico"
/////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,15 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
#define IDR_MAINFRAME 1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,218 @@
// 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 "atom/browser/ui/accelerator_util.h"
#include <stdio.h>
#include <string>
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "ui/base/models/simple_menu_model.h"
namespace accelerator_util {
namespace {
// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
*shifted = false;
switch (c) {
case 8: case 0x7F: return ui::VKEY_BACK;
case 9: return ui::VKEY_TAB;
case 0xD: case 3: return ui::VKEY_RETURN;
case 0x1B: return ui::VKEY_ESCAPE;
case ' ': return ui::VKEY_SPACE;
case 'a': return ui::VKEY_A;
case 'b': return ui::VKEY_B;
case 'c': return ui::VKEY_C;
case 'd': return ui::VKEY_D;
case 'e': return ui::VKEY_E;
case 'f': return ui::VKEY_F;
case 'g': return ui::VKEY_G;
case 'h': return ui::VKEY_H;
case 'i': return ui::VKEY_I;
case 'j': return ui::VKEY_J;
case 'k': return ui::VKEY_K;
case 'l': return ui::VKEY_L;
case 'm': return ui::VKEY_M;
case 'n': return ui::VKEY_N;
case 'o': return ui::VKEY_O;
case 'p': return ui::VKEY_P;
case 'q': return ui::VKEY_Q;
case 'r': return ui::VKEY_R;
case 's': return ui::VKEY_S;
case 't': return ui::VKEY_T;
case 'u': return ui::VKEY_U;
case 'v': return ui::VKEY_V;
case 'w': return ui::VKEY_W;
case 'x': return ui::VKEY_X;
case 'y': return ui::VKEY_Y;
case 'z': return ui::VKEY_Z;
case ')': *shifted = true; case '0': return ui::VKEY_0;
case '!': *shifted = true; case '1': return ui::VKEY_1;
case '@': *shifted = true; case '2': return ui::VKEY_2;
case '#': *shifted = true; case '3': return ui::VKEY_3;
case '$': *shifted = true; case '4': return ui::VKEY_4;
case '%': *shifted = true; case '5': return ui::VKEY_5;
case '^': *shifted = true; case '6': return ui::VKEY_6;
case '&': *shifted = true; case '7': return ui::VKEY_7;
case '*': *shifted = true; case '8': return ui::VKEY_8;
case '(': *shifted = true; case '9': return ui::VKEY_9;
case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;
default: return ui::VKEY_UNKNOWN;
}
}
} // namespace
bool StringToAccelerator(const std::string& description,
ui::Accelerator* accelerator) {
if (!IsStringASCII(description)) {
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
return false;
}
std::string shortcut(StringToLowerASCII(description));
std::vector<std::string> tokens;
base::SplitString(shortcut, '+', &tokens);
// Now, parse it into an accelerator.
int modifiers = ui::EF_NONE;
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
for (size_t i = 0; i < tokens.size(); i++) {
// We use straight comparing instead of map because the accelerator tends
// to be correct and usually only uses few special tokens.
if (tokens[i].size() == 1) {
bool shifted = false;
key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
if (shifted)
modifiers |= ui::EF_SHIFT_DOWN;
} else if (tokens[i] == "ctrl" || tokens[i] == "control") {
modifiers |= ui::EF_CONTROL_DOWN;
} else if (tokens[i] == "cmd" || tokens[i] == "command") {
modifiers |= ui::EF_COMMAND_DOWN;
} else if (tokens[i] == "commandorcontrol" || tokens[i] == "cmdorctrl") {
#if defined(OS_MACOSX)
modifiers |= ui::EF_COMMAND_DOWN;
#else
modifiers |= ui::EF_CONTROL_DOWN;
#endif
} else if (tokens[i] == "alt") {
modifiers |= ui::EF_ALT_DOWN;
} else if (tokens[i] == "shift") {
modifiers |= ui::EF_SHIFT_DOWN;
} else if (tokens[i] == "tab") {
key = ui::VKEY_TAB;
} else if (tokens[i] == "space") {
key = ui::VKEY_SPACE;
} else if (tokens[i] == "backspace") {
key = ui::VKEY_BACK;
} else if (tokens[i] == "delete") {
key = ui::VKEY_DELETE;
} else if (tokens[i] == "enter" || tokens[i] == "return") {
key = ui::VKEY_RETURN;
} else if (tokens[i] == "up") {
key = ui::VKEY_UP;
} else if (tokens[i] == "down") {
key = ui::VKEY_DOWN;
} else if (tokens[i] == "left") {
key = ui::VKEY_LEFT;
} else if (tokens[i] == "right") {
key = ui::VKEY_RIGHT;
} else if (tokens[i] == "home") {
key = ui::VKEY_HOME;
} else if (tokens[i] == "end") {
key = ui::VKEY_END;
} else if (tokens[i] == "pagedown") {
key = ui::VKEY_PRIOR;
} else if (tokens[i] == "pageup") {
key = ui::VKEY_NEXT;
} else if (tokens[i] == "esc") {
key = ui::VKEY_ESCAPE;
} else if (tokens[i] == "volumemute") {
key = ui::VKEY_VOLUME_MUTE;
} else if (tokens[i] == "volumeup") {
key = ui::VKEY_VOLUME_UP;
} else if (tokens[i] == "volumedown") {
key = ui::VKEY_VOLUME_DOWN;
} else if (tokens[i] == "medianexttrack") {
key = ui::VKEY_MEDIA_NEXT_TRACK;
} else if (tokens[i] == "mediaprevioustrack") {
key = ui::VKEY_MEDIA_PREV_TRACK;
} else if (tokens[i] == "mediastop") {
key = ui::VKEY_MEDIA_STOP;
} else if (tokens[i] == "mediaplaypause") {
key = ui::VKEY_MEDIA_PLAY_PAUSE;
} else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
// F1 - F24.
int n;
if (base::StringToInt(tokens[i].c_str() + 1, &n)) {
key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
} else {
LOG(WARNING) << tokens[i] << "is not available on keyboard";
return false;
}
} else {
LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
return false;
}
}
if (key == ui::VKEY_UNKNOWN) {
LOG(WARNING) << "The accelerator doesn't contain a valid key";
return false;
}
*accelerator = ui::Accelerator(key, modifiers);
SetPlatformAccelerator(accelerator);
return true;
}
void GenerateAcceleratorTable(AcceleratorTable* table, ui::MenuModel* model) {
int count = model->GetItemCount();
for (int i = 0; i < count; ++i) {
ui::MenuModel::ItemType type = model->GetTypeAt(i);
if (type == ui::MenuModel::TYPE_SUBMENU) {
ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
GenerateAcceleratorTable(table, submodel);
} else {
ui::Accelerator accelerator;
if (model->GetAcceleratorAt(i, &accelerator)) {
MenuItem item = { i, model };
(*table)[accelerator] = item;
}
}
}
}
bool TriggerAcceleratorTableCommand(AcceleratorTable* table,
const ui::Accelerator& accelerator) {
if (ContainsKey(*table, accelerator)) {
const accelerator_util::MenuItem& item = (*table)[accelerator];
item.model->ActivatedAt(item.position);
return true;
} else {
return false;
}
}
} // namespace accelerator_util

View file

@ -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.
#ifndef BROWSER_UI_ACCELERATOR_UTIL_H_
#define BROWSER_UI_ACCELERATOR_UTIL_H_
#include <map>
#include <string>
#include "ui/base/accelerators/accelerator.h"
namespace ui {
class MenuModel;
}
namespace accelerator_util {
typedef struct { int position; ui::MenuModel* model; } MenuItem;
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
// Parse a string as an accelerator.
bool StringToAccelerator(const std::string& description,
ui::Accelerator* accelerator);
// Set platform accelerator for the Accelerator.
void SetPlatformAccelerator(ui::Accelerator* accelerator);
// Generate a table that contains memu model's accelerators and command ids.
void GenerateAcceleratorTable(AcceleratorTable* table, ui::MenuModel* model);
// Trigger command from the accelerators table.
bool TriggerAcceleratorTableCommand(AcceleratorTable* table,
const ui::Accelerator& accelerator);
} // namespace accelerator_util
#endif // BROWSER_UI_ACCELERATOR_UTIL_H_

View file

@ -0,0 +1,20 @@
// 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 "atom/browser/ui/accelerator_util.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_gtk.h"
namespace accelerator_util {
void SetPlatformAccelerator(ui::Accelerator* accelerator) {
scoped_ptr<ui::PlatformAccelerator> platform_accelerator(
new ui::PlatformAcceleratorGtk(
GetGdkKeyCodeForAccelerator(*accelerator),
GetGdkModifierForAccelerator(*accelerator)));
accelerator->set_platform_accelerator(platform_accelerator.Pass());
}
} // namespace accelerator_util

View file

@ -0,0 +1,34 @@
// 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 "atom/browser/ui/accelerator_util.h"
#include "ui/base/accelerators/accelerator.h"
#import "ui/base/accelerators/platform_accelerator_cocoa.h"
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
namespace accelerator_util {
void SetPlatformAccelerator(ui::Accelerator* accelerator) {
unichar character;
unichar characterIgnoringModifiers;
ui::MacKeyCodeForWindowsKeyCode(accelerator->key_code(),
0,
&character,
&characterIgnoringModifiers);
NSString* characters =
[[[NSString alloc] initWithCharacters:&character length:1] autorelease];
NSUInteger modifiers =
(accelerator->IsCtrlDown() ? NSControlKeyMask : 0) |
(accelerator->IsCmdDown() ? NSCommandKeyMask : 0) |
(accelerator->IsAltDown() ? NSAlternateKeyMask : 0) |
(accelerator->IsShiftDown() ? NSShiftKeyMask : 0);
scoped_ptr<ui::PlatformAccelerator> platform_accelerator(
new ui::PlatformAcceleratorCocoa(characters, modifiers));
accelerator->set_platform_accelerator(platform_accelerator.Pass());
}
} // namespace accelerator_util

View file

@ -0,0 +1,14 @@
// 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 "atom/browser/ui/accelerator_util.h"
#include "ui/base/accelerators/accelerator.h"
namespace accelerator_util {
void SetPlatformAccelerator(ui::Accelerator* accelerator) {
}
} // namespace accelerator_util

View file

@ -0,0 +1,72 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2012 The Chromium Authors. 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_UI_COCOA_ATOM_MENU_CONTROLLER_H_
#define ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
#include "base/strings/string16.h"
namespace ui {
class MenuModel;
}
// A controller for the cross-platform menu model. The menu that's created
// has the tag and represented object set for each menu item. The object is a
// NSValue holding a pointer to the model for that level of the menu (to
// allow for hierarchical menus). The tag is the index into that model for
// that particular item. It is important that the model outlives this object
// as it only maintains weak references.
@interface AtomMenuController : NSObject<NSMenuDelegate> {
@protected
ui::MenuModel* model_; // weak
base::scoped_nsobject<NSMenu> menu_;
BOOL isMenuOpen_;
}
@property(nonatomic, assign) ui::MenuModel* model;
// NIB-based initializer. This does not create a menu. Clients can set the
// properties of the object and the menu will be created upon the first call to
// |-menu|. Note that the menu will be immutable after creation.
- (id)init;
// Builds a NSMenu from the pre-built model (must not be nil). Changes made
// to the contents of the model after calling this will not be noticed.
- (id)initWithModel:(ui::MenuModel*)model;
// Programmatically close the constructed menu.
- (void)cancel;
// Access to the constructed menu if the complex initializer was used. If the
// default initializer was used, then this will create the menu on first call.
- (NSMenu*)menu;
// Whether the menu is currently open.
- (BOOL)isMenuOpen;
// NSMenuDelegate methods this class implements. Subclasses should call super
// if extending the behavior.
- (void)menuWillOpen:(NSMenu*)menu;
- (void)menuDidClose:(NSMenu*)menu;
@end
// Exposed only for unit testing, do not call directly.
@interface AtomMenuController (PrivateExposedForTesting)
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
@end
// Protected methods that subclassers can override.
@interface AtomMenuController (Protected)
- (void)addItemToMenu:(NSMenu*)menu
atIndex:(NSInteger)index
fromModel:(ui::MenuModel*)model;
- (NSMenu*)menuFromModel:(ui::MenuModel*)model;
@end
#endif // ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_

View file

@ -0,0 +1,258 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/gfx/image/image.h"
namespace {
bool isLeftButtonEvent(NSEvent* event) {
NSEventType type = [event type];
return type == NSLeftMouseDown ||
type == NSLeftMouseDragged ||
type == NSLeftMouseUp;
}
bool isRightButtonEvent(NSEvent* event) {
NSEventType type = [event type];
return type == NSRightMouseDown ||
type == NSRightMouseDragged ||
type == NSRightMouseUp;
}
bool isMiddleButtonEvent(NSEvent* event) {
if ([event buttonNumber] != 2)
return false;
NSEventType type = [event type];
return type == NSOtherMouseDown ||
type == NSOtherMouseDragged ||
type == NSOtherMouseUp;
}
int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
int flags = 0;
flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
flags |= isLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
flags |= isRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
flags |= isMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
return flags;
}
// Retrieves a bitsum of ui::EventFlags from NSEvent.
int EventFlagsFromNSEvent(NSEvent* event) {
NSUInteger modifiers = [event modifierFlags];
return EventFlagsFromNSEventWithModifiers(event, modifiers);
}
} // namespace
@interface AtomMenuController (Private)
- (void)addSeparatorToMenu:(NSMenu*)menu
atIndex:(int)index;
@end
@implementation AtomMenuController
@synthesize model = model_;
- (id)init {
self = [super init];
return self;
}
- (id)initWithModel:(ui::MenuModel*)model {
if ((self = [super init])) {
model_ = model;
[self menu];
}
return self;
}
- (void)dealloc {
[menu_ setDelegate:nil];
// Close the menu if it is still open. This could happen if a tab gets closed
// while its context menu is still open.
[self cancel];
model_ = NULL;
[super dealloc];
}
- (void)cancel {
if (isMenuOpen_) {
[menu_ cancelTracking];
model_->MenuClosed();
isMenuOpen_ = NO;
}
}
// Creates a NSMenu from the given model. If the model has submenus, this can
// be invoked recursively.
- (NSMenu*)menuFromModel:(ui::MenuModel*)model {
NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
const int count = model->GetItemCount();
for (int index = 0; index < count; index++) {
if (model->GetTypeAt(index) == ui::MenuModel::TYPE_SEPARATOR)
[self addSeparatorToMenu:menu atIndex:index];
else
[self addItemToMenu:menu atIndex:index fromModel:model];
}
return menu;
}
// Adds a separator item at the given index. As the separator doesn't need
// anything from the model, this method doesn't need the model index as the
// other method below does.
- (void)addSeparatorToMenu:(NSMenu*)menu
atIndex:(int)index {
NSMenuItem* separator = [NSMenuItem separatorItem];
[menu insertItem:separator atIndex:index];
}
// Adds an item or a hierarchical menu to the item at the |index|,
// associated with the entry in the model identified by |modelIndex|.
- (void)addItemToMenu:(NSMenu*)menu
atIndex:(NSInteger)index
fromModel:(ui::MenuModel*)model {
string16 label16 = model->GetLabelAt(index);
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
base::scoped_nsobject<NSMenuItem> item(
[[NSMenuItem alloc] initWithTitle:label
action:@selector(itemSelected:)
keyEquivalent:@""]);
// If the menu item has an icon, set it.
gfx::Image icon;
if (model->GetIconAt(index, &icon) && !icon.IsEmpty())
[item setImage:icon.ToNSImage()];
ui::MenuModel::ItemType type = model->GetTypeAt(index);
if (type == ui::MenuModel::TYPE_SUBMENU) {
// Recursively build a submenu from the sub-model at this index.
[item setTarget:nil];
[item setAction:nil];
ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index);
NSMenu* submenu =
[self menuFromModel:(ui::SimpleMenuModel*)submenuModel];
[submenu setTitle:[item title]];
[item setSubmenu:submenu];
// Hack to set window and help menu.
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
[NSApp setWindowsMenu:submenu];
else if ([[item title] isEqualToString:@"Help"])
[NSApp setHelpMenu:submenu];
} else {
// The MenuModel works on indexes so we can't just set the command id as the
// tag like we do in other menus. Also set the represented object to be
// the model so hierarchical menus check the correct index in the correct
// model. Setting the target to |self| allows this class to participate
// in validation of the menu items.
[item setTag:index];
[item setTarget:self];
NSValue* modelObject = [NSValue valueWithPointer:model];
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
ui::Accelerator accelerator;
if (model->GetAcceleratorAt(index, &accelerator)) {
const ui::PlatformAcceleratorCocoa* platformAccelerator =
static_cast<const ui::PlatformAcceleratorCocoa*>(
accelerator.platform_accelerator());
if (platformAccelerator) {
[item setKeyEquivalent:platformAccelerator->characters()];
[item setKeyEquivalentModifierMask:
platformAccelerator->modifier_mask()];
}
}
}
[menu insertItem:item atIndex:index];
}
// Called before the menu is to be displayed to update the state (enabled,
// radio, etc) of each item in the menu. Also will update the title if
// the item is marked as "dynamic".
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
SEL action = [item action];
if (action != @selector(itemSelected:))
return NO;
NSInteger modelIndex = [item tag];
ui::MenuModel* model =
static_cast<ui::MenuModel*>(
[[(id)item representedObject] pointerValue]);
DCHECK(model);
if (model) {
BOOL checked = model->IsItemCheckedAt(modelIndex);
DCHECK([(id)item isKindOfClass:[NSMenuItem class]]);
[(id)item setState:(checked ? NSOnState : NSOffState)];
[(id)item setHidden:(!model->IsVisibleAt(modelIndex))];
if (model->IsItemDynamicAt(modelIndex)) {
// Update the label and the icon.
NSString* label =
l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex));
[(id)item setTitle:label];
gfx::Image icon;
model->GetIconAt(modelIndex, &icon);
[(id)item setImage:icon.IsEmpty() ? nil : icon.ToNSImage()];
}
return model->IsEnabledAt(modelIndex);
}
return NO;
}
// Called when the user chooses a particular menu item. |sender| is the menu
// item chosen.
- (void)itemSelected:(id)sender {
NSInteger modelIndex = [sender tag];
ui::MenuModel* model =
static_cast<ui::MenuModel*>(
[[sender representedObject] pointerValue]);
DCHECK(model);
if (model) {
int event_flags = EventFlagsFromNSEvent([NSApp currentEvent]);
model->ActivatedAt(modelIndex, event_flags);
}
}
- (NSMenu*)menu {
if (!menu_ && model_) {
menu_.reset([[self menuFromModel:model_] retain]);
[menu_ setDelegate:self];
}
return menu_.get();
}
- (BOOL)isMenuOpen {
return isMenuOpen_;
}
- (void)menuWillOpen:(NSMenu*)menu {
isMenuOpen_ = YES;
model_->MenuWillShow();
}
- (void)menuDidClose:(NSMenu*)menu {
if (isMenuOpen_) {
model_->MenuClosed();
isMenuOpen_ = NO;
}
}
@end

View file

@ -0,0 +1,30 @@
// 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_UI_COCOA_EVENT_PROCESSING_WINDOW_H_
#define ATOM_BROWSER_UI_COCOA_EVENT_PROCESSING_WINDOW_H_
#import <Cocoa/Cocoa.h>
// Override NSWindow to access unhandled keyboard events (for command
// processing); subclassing NSWindow is the only method to do
// this.
@interface EventProcessingWindow : NSWindow {
@private
BOOL redispatchingEvent_;
BOOL eventHandled_;
}
// Sends a key event to |NSApp sendEvent:|, but also makes sure that it's not
// short-circuited to the RWHV. This is used to send keyboard events to the menu
// and the cmd-` handler if a keyboard event comes back unhandled from the
// renderer. The event must be of type |NSKeyDown|, |NSKeyUp|, or
// |NSFlagsChanged|.
// Returns |YES| if |event| has been handled.
- (BOOL)redispatchKeyEvent:(NSEvent*)event;
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
@end
#endif // ATOM_BROWSER_UI_COCOA_EVENT_PROCESSING_WINDOW_H_

Some files were not shown because too many files have changed in this diff Show more