diff --git a/Atom-Linux/atom.cpp b/Atom-Linux/atom.cpp index 9e684d616..3f7de7fd7 100644 --- a/Atom-Linux/atom.cpp +++ b/Atom-Linux/atom.cpp @@ -6,12 +6,14 @@ #include #include #include "atom.h" +#include "atom_cef_app.h" #include "include/cef_app.h" #include "include/cef_browser.h" #include "include/cef_frame.h" #include "include/cef_runnable.h" #include "client_handler.h" #include "onig_regexp_extension.h" +#include "atom_handler.h" #include "io_utils.h" char* szWorkingDir; // The current working directory @@ -30,6 +32,7 @@ void AppGetSettings(CefSettings& settings, CefRefPtr& app) { CefString(&settings.log_file) = ""; CefString(&settings.javascript_flags) = ""; + settings.remote_debugging_port = 9090; settings.log_severity = LOGSEVERITY_ERROR; } @@ -80,7 +83,7 @@ int main(int argc, char *argv[]) { gtk_init(&argc, &argv); CefSettings settings; - CefRefPtr app; + CefRefPtr app(new AtomCefApp); AppGetSettings(settings, app); CefInitialize(main_args, settings, app.get()); @@ -103,7 +106,8 @@ int main(int argc, char *argv[]) { g_handler->SetMainHwnd(vbox); g_handler->SetWindow(window); - new OnigRegexpExtension(); + //new OnigRegexpExtension(); + //new AtomHandler(); // Create the browser view. CefWindowInfo window_info; @@ -117,10 +121,12 @@ int main(int argc, char *argv[]) { std::string resolved("file://"); resolved.append(path); + resolved.append("?bootstrapScript=window-bootstrap"); + resolved.append("&pathToOpen="); + resolved.append(PathToOpen()); - CefBrowserHost::CreateBrowserSync( - window_info, g_handler.get(), - resolved, browserSettings); + CefBrowserHost::CreateBrowserSync(window_info, g_handler.get(), resolved, + browserSettings); gtk_container_add(GTK_CONTAINER(window), vbox); gtk_widget_show_all(GTK_WIDGET(window)); diff --git a/Atom-Linux/atom.gyp b/Atom-Linux/atom.gyp index b1fa370b0..5708b2f7b 100644 --- a/Atom-Linux/atom.gyp +++ b/Atom-Linux/atom.gyp @@ -5,6 +5,7 @@ 'type': 'executable', 'variables': { 'pkg-config': 'pkg-config', + 'install-dir': '/usr/share/atom', }, 'dependencies': [ ], @@ -15,8 +16,11 @@ ], 'sources': [ 'atom.cpp', + 'atom_cef_render_process_handler.cpp', + 'atom_handler.cpp', 'client_handler.cpp', 'io_utils.cpp', + 'message_translation.cpp', 'native_handler.cpp', 'onig_regexp_extension.cpp', ], @@ -27,6 +31,7 @@ 'ldflags': [ ' GetRenderProcessHandler() + OVERRIDE { + return CefRefPtr(new AtomCefRenderProcessHandler); + } + +IMPLEMENT_REFCOUNTING(AtomCefApp) + ; +}; + +#endif diff --git a/Atom-Linux/atom_cef_render_process_handler.cpp b/Atom-Linux/atom_cef_render_process_handler.cpp new file mode 100644 index 000000000..957fdb8d1 --- /dev/null +++ b/Atom-Linux/atom_cef_render_process_handler.cpp @@ -0,0 +1,77 @@ +#include "atom_cef_render_process_handler.h" +#include "atom_handler.h" +#include "native_handler.h" +#include "onig_regexp_extension.h" +#include "io_utils.h" +#include "message_translation.h" +#include + +void AtomCefRenderProcessHandler::OnWebKitInitialized() { + new AtomHandler(); + new NativeHandler(); + new OnigRegexpExtension(); +} + +void AtomCefRenderProcessHandler::OnContextCreated( + CefRefPtr browser, CefRefPtr frame, + CefRefPtr context) { + CefRefPtr resourcePath = CefV8Value::CreateString( + io_util_app_directory()); + + CefRefPtr global = context->GetGlobal(); + CefRefPtr atom = global->GetValue("atom"); + atom->SetValue("resourcePath", resourcePath, V8_PROPERTY_ATTRIBUTE_NONE); +} + +bool AtomCefRenderProcessHandler::OnProcessMessageReceived( + CefRefPtr browser, CefProcessId source_process, + CefRefPtr message) { + return CallMessageReceivedHandler(browser->GetMainFrame()->GetV8Context(), + message); +} + +void AtomCefRenderProcessHandler::Reload(CefRefPtr browser) { + CefRefPtr context = browser->GetMainFrame()->GetV8Context(); + CefRefPtr global = context->GetGlobal(); + + context->Enter(); + CefV8ValueList arguments; + + CefRefPtr reloadFunction = global->GetValue("reload"); + reloadFunction->ExecuteFunction(global, arguments); + if (reloadFunction->HasException()) { + browser->ReloadIgnoreCache(); + } + context->Exit(); +} + +bool AtomCefRenderProcessHandler::CallMessageReceivedHandler( + CefRefPtr context, CefRefPtr message) { + context->Enter(); + + CefRefPtr atom = context->GetGlobal()->GetValue("atom"); + CefRefPtr receiveFn = atom->GetValue( + "receiveMessageFromBrowserProcess"); + + CefV8ValueList arguments; + arguments.push_back(CefV8Value::CreateString(message->GetName().ToString())); + + CefRefPtr messageArguments = message->GetArgumentList(); + if (messageArguments->GetSize() > 0) { + CefRefPtr data = CefV8Value::CreateArray( + messageArguments->GetSize()); + TranslateList(messageArguments, data); + arguments.push_back(data); + } + + receiveFn->ExecuteFunction(atom, arguments); + context->Exit(); + + if (receiveFn->HasException()) { + std::cout << "ERROR: Exception in JS receiving message " + << message->GetName().ToString() << "\n"; + return false; + } else { + return true; + } +} diff --git a/Atom-Linux/atom_cef_render_process_handler.h b/Atom-Linux/atom_cef_render_process_handler.h new file mode 100644 index 000000000..61dd370d8 --- /dev/null +++ b/Atom-Linux/atom_cef_render_process_handler.h @@ -0,0 +1,24 @@ +#ifndef ATOM_CEF_RENDER_PROCESS_HANDLER_H_ +#define ATOM_CEF_RENDER_PROCESS_HANDLER_H_ +#pragma once + +#include "include/cef_app.h" + +class AtomCefRenderProcessHandler: public CefRenderProcessHandler { + + virtual void OnWebKitInitialized() OVERRIDE; + virtual void OnContextCreated(CefRefPtr browser, + CefRefPtr frame, CefRefPtr context) OVERRIDE; + virtual bool OnProcessMessageReceived(CefRefPtr browser, + CefProcessId source_process, CefRefPtr message) + OVERRIDE; + + void Reload(CefRefPtr browser); + bool CallMessageReceivedHandler(CefRefPtr context, + CefRefPtr message); + +IMPLEMENT_REFCOUNTING(AtomCefRenderProcessHandler) + ; +}; + +#endif // ATOM_CEF_RENDER_PROCESS_HANDLER_H_ diff --git a/Atom-Linux/atom_handler.cpp b/Atom-Linux/atom_handler.cpp new file mode 100644 index 000000000..aa576f9c8 --- /dev/null +++ b/Atom-Linux/atom_handler.cpp @@ -0,0 +1,44 @@ +#include "atom_handler.h" +#include "include/cef_base.h" +#include "include/cef_runnable.h" +#include +#include +#include "io_utils.h" +#include "message_translation.h" + +using namespace std; + +AtomHandler::AtomHandler() : + CefV8Handler() { + string realFilePath = io_utils_real_app_path("/native/v8_extensions/atom.js"); + if (!realFilePath.empty()) { + string extensionCode; + if (io_utils_read(realFilePath, &extensionCode) > 0) + CefRegisterExtension("v8/atom", extensionCode, this); + } +} + +bool AtomHandler::Execute(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) { + CefRefPtr browser = + CefV8Context::GetCurrentContext()->GetBrowser(); + + if (name == "sendMessageToBrowserProcess") { + if (arguments.size() == 0 || !arguments[0]->IsString()) { + exception = "You must supply a message name"; + return false; + } + + CefString name = arguments[0]->GetStringValue(); + CefRefPtr message = CefProcessMessage::Create(name); + + if (arguments.size() > 1 && arguments[1]->IsArray()) { + TranslateList(arguments[1], message->GetArgumentList()); + } + + browser->SendProcessMessage(PID_BROWSER, message); + return true; + } + return false; +} diff --git a/Atom-Linux/atom_handler.h b/Atom-Linux/atom_handler.h new file mode 100644 index 000000000..a11c9a7f9 --- /dev/null +++ b/Atom-Linux/atom_handler.h @@ -0,0 +1,21 @@ +#ifndef ATOM_HANDLER_H_ +#define ATOM_HANDLER_H_ + +#include "include/cef_base.h" +#include "include/cef_v8.h" + +class AtomHandler: public CefV8Handler { + +public: + AtomHandler(); + + virtual bool Execute(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + +IMPLEMENT_REFCOUNTING(AtomHandler) + ; + +}; + +#endif diff --git a/Atom-Linux/cef.pak b/Atom-Linux/cef.pak new file mode 100644 index 000000000..34e11ac29 Binary files /dev/null and b/Atom-Linux/cef.pak differ diff --git a/Atom-Linux/cef_resources.pak b/Atom-Linux/cef_resources.pak new file mode 100644 index 000000000..3f169e457 Binary files /dev/null and b/Atom-Linux/cef_resources.pak differ diff --git a/Atom-Linux/client_handler.cpp b/Atom-Linux/client_handler.cpp index 833ad8da9..41baf0351 100644 --- a/Atom-Linux/client_handler.cpp +++ b/Atom-Linux/client_handler.cpp @@ -10,24 +10,39 @@ #include "include/cef_browser.h" #include "include/cef_frame.h" #include "atom.h" -#include "native_handler.h" -#include "atom.h" #include #include ClientHandler::ClientHandler() : m_MainHwnd(NULL), m_BrowserHwnd(NULL) { - m_nativeHandler = new NativeHandler(); } ClientHandler::~ClientHandler() { } +bool ClientHandler::OnProcessMessageReceived(CefRefPtr browser, + CefProcessId source_process, CefRefPtr message) { + std::string name = message->GetName().ToString(); + std::cout << "Message " << name << std::endl; + if (name == "showDevTools") { + std::string devtools_url = browser->GetHost()->GetDevToolsURL(true); + std::cout << "url" << devtools_url << std::endl; + if (!devtools_url.empty()) { + browser->GetMainFrame()->ExecuteJavaScript( + "window.open('" + devtools_url + "');", "about:blank", 0); + } + } else { + return false; + } + + return true; +} + void ClientHandler::OnAfterCreated(CefRefPtr browser) { REQUIRE_UI_THREAD(); AutoLock lock_scope(this); - if (!m_Browser.get()) { + if (!m_Browser.get()) { // We need to keep the main child window, but not popup windows m_Browser = browser; m_BrowserId = browser->GetIdentifier(); @@ -72,39 +87,6 @@ void ClientHandler::OnLoadStart(CefRefPtr browser, CefRefPtr frame) { REQUIRE_UI_THREAD(); - if (m_BrowserId == browser->GetIdentifier() && frame->IsMain()) { - CefRefPtr context = frame->GetV8Context(); - CefRefPtr global = context->GetGlobal(); - context->Enter(); - - CefRefPtr windowNumber = CefV8Value::CreateInt(0); - global->SetValue("$windowNumber", windowNumber, V8_PROPERTY_ATTRIBUTE_NONE); - - std::string path; - if (m_nativeHandler && !m_nativeHandler->path.empty()) - path = m_nativeHandler->path; - else - path.append(PathToOpen()); - - CefRefPtr pathToOpen = CefV8Value::CreateString(path); - global->SetValue("$pathToOpen", pathToOpen, V8_PROPERTY_ATTRIBUTE_NONE); - - m_nativeHandler->window = window; - m_nativeHandler->path = path; - - CefRefPtr atom = CefV8Value::CreateObject(NULL); - global->SetValue("atom", atom, V8_PROPERTY_ATTRIBUTE_NONE); - - CefRefPtr loadPath = CefV8Value::CreateString(AppPath()); - atom->SetValue("loadPath", loadPath, V8_PROPERTY_ATTRIBUTE_NONE); - - CefRefPtr bootstrapScript = CefV8Value::CreateString( - "single-window-bootstrap"); - global->SetValue("$bootstrapScript", bootstrapScript, - V8_PROPERTY_ATTRIBUTE_NONE); - - context->Exit(); - } } void ClientHandler::OnLoadEnd(CefRefPtr browser, diff --git a/Atom-Linux/client_handler.h b/Atom-Linux/client_handler.h index b7eafd1fe..311018e86 100644 --- a/Atom-Linux/client_handler.h +++ b/Atom-Linux/client_handler.h @@ -6,7 +6,6 @@ #include #include "include/cef_client.h" #include "util.h" -#include "native_handler.h" // ClientHandler implementation. class ClientHandler: public CefClient, @@ -64,6 +63,10 @@ public: virtual void OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node) OVERRIDE; + virtual bool OnProcessMessageReceived(CefRefPtr browser, + CefProcessId source_process, CefRefPtr message) + OVERRIDE; + void SetWindow(GtkWidget* window); void SetMainHwnd(CefWindowHandle hwnd); CefWindowHandle GetMainHwnd() { @@ -88,8 +91,6 @@ protected: GtkWidget* window; - CefRefPtr m_nativeHandler; - // The child browser window CefRefPtr m_Browser; diff --git a/Atom-Linux/content_resources.pak b/Atom-Linux/content_resources.pak new file mode 100644 index 000000000..a14a346c9 Binary files /dev/null and b/Atom-Linux/content_resources.pak differ diff --git a/Atom-Linux/chrome.pak b/Atom-Linux/devtools_resources.pak similarity index 74% rename from Atom-Linux/chrome.pak rename to Atom-Linux/devtools_resources.pak index 51266259d..342d06fdd 100644 Binary files a/Atom-Linux/chrome.pak and b/Atom-Linux/devtools_resources.pak differ diff --git a/Atom-Linux/install.sh b/Atom-Linux/install.sh new file mode 100755 index 000000000..21c452c11 --- /dev/null +++ b/Atom-Linux/install.sh @@ -0,0 +1,19 @@ +#!/bin/sh +INSTALLDIR=/usr/share/atom + +mkdir -p $INSTALLDIR +cp out/Default/atom $INSTALLDIR +cp -t $INSTALLDIR *.pak +cp -R locales $INSTALLDIR +cp atom.png $INSTALLDIR +cp lib/libcef.so $INSTALLDIR +cp lib/libcef_dll_wrapper.a $INSTALLDIR +cp -R ../src $INSTALLDIR +cp -R ../static $INSTALLDIR +cp -R ../vendor $INSTALLDIR +cp -R ../bundles $INSTALLDIR +cp -R ../themes $INSTALLDIR +mkdir -p $INSTALLDIR/native/v8_extensions +cp -t $INSTALLDIR/native/v8_extensions ../native/v8_extensions/*.js +coffee -c -o $INSTALLDIR/src/stdlib ../src/stdlib/require.coffee +ln -sf $INSTALLDIR/atom /usr/local/bin/atom diff --git a/Atom-Linux/locales/en-US.pak b/Atom-Linux/locales/en-US.pak index 00fc0cba9..d5df85b54 100644 Binary files a/Atom-Linux/locales/en-US.pak and b/Atom-Linux/locales/en-US.pak differ diff --git a/Atom-Linux/message_translation.cpp b/Atom-Linux/message_translation.cpp new file mode 100644 index 000000000..0913279b9 --- /dev/null +++ b/Atom-Linux/message_translation.cpp @@ -0,0 +1,82 @@ +#include +#include "message_translation.h" + +// Transfer a V8 value to a List index. +void TranslateListValue(CefRefPtr list, int index, CefRefPtr value) { + if (value->IsArray()) { + CefRefPtr new_list = CefListValue::Create(); + TranslateList(value, new_list); + list->SetList(index, new_list); + } else if (value->IsString()) { + list->SetString(index, value->GetStringValue()); + } else if (value->IsBool()) { + list->SetBool(index, value->GetBoolValue()); + } else if (value->IsInt()) { + list->SetInt(index, value->GetIntValue()); + } else if (value->IsDouble()) { + list->SetDouble(index, value->GetDoubleValue()); + } +} + +// Transfer a V8 array to a List. +void TranslateList(CefRefPtr source, CefRefPtr target) { + assert(source->IsArray()); + + int arg_length = source->GetArrayLength(); + if (arg_length == 0) + return; + + // Start with null types in all spaces. + target->SetSize(arg_length); + + for (int i = 0; i < arg_length; ++i) { + TranslateListValue(target, i, source->GetValue(i)); + } +} + +// Transfer a List value to a V8 array index. +void TranslateListValue(CefRefPtr list, int index, CefRefPtr value) { + CefRefPtr new_value; + + CefValueType type = value->GetType(index); + switch (type) { + case VTYPE_LIST: { + CefRefPtr list = value->GetList(index); + new_value = CefV8Value::CreateArray(list->GetSize()); + TranslateList(list, new_value); + } break; + case VTYPE_BOOL: + new_value = CefV8Value::CreateBool(value->GetBool(index)); + break; + case VTYPE_DOUBLE: + new_value = CefV8Value::CreateDouble(value->GetDouble(index)); + break; + case VTYPE_INT: + new_value = CefV8Value::CreateInt(value->GetInt(index)); + break; + case VTYPE_STRING: + new_value = CefV8Value::CreateString(value->GetString(index)); + break; + default: + break; + } + + if (new_value.get()) { + list->SetValue(index, new_value); + } else { + list->SetValue(index, CefV8Value::CreateNull()); + } +} + +// Transfer a List to a V8 array. +void TranslateList(CefRefPtr source, CefRefPtr target) { + assert(target->IsArray()); + + int arg_length = source->GetSize(); + if (arg_length == 0) + return; + + for (int i = 0; i < arg_length; ++i) { + TranslateListValue(target, i, source); + } +} diff --git a/Atom-Linux/message_translation.h b/Atom-Linux/message_translation.h new file mode 100644 index 000000000..e6caaf332 --- /dev/null +++ b/Atom-Linux/message_translation.h @@ -0,0 +1,11 @@ +#ifndef ATOM_CEF_CLIENT_H_ +#define ATOM_CEF_CLIENT_H_ +#pragma once + +#include "include/cef_v8.h" + +// IPC data translation functions: translate a V8 array to a List, and vice versa +void TranslateList(CefRefPtr source, CefRefPtr target); +void TranslateList(CefRefPtr source, CefRefPtr target); + +#endif \ No newline at end of file diff --git a/Atom-Linux/native_handler.cpp b/Atom-Linux/native_handler.cpp index 1b8c1cdad..063d631bb 100644 --- a/Atom-Linux/native_handler.cpp +++ b/Atom-Linux/native_handler.cpp @@ -51,11 +51,11 @@ void ExecuteWatchCallback(NotifyContext notifyContext) { NativeHandler::NativeHandler() : CefV8Handler() { - string nativePath = io_utils_real_app_path("/src/stdlib/native-handler.js"); + string nativePath = io_utils_real_app_path("/native/v8_extensions/native.js"); if (!nativePath.empty()) { string extensionCode; if (io_utils_read(nativePath, &extensionCode) > 0) - CefRegisterExtension("v8/native-handler", extensionCode, this); + CefRegisterExtension("v8/native", extensionCode, this); } notifyFd = inotify_init(); @@ -488,8 +488,6 @@ bool NativeHandler::Execute(const CefString& name, CefRefPtr object, IsFile(name, object, arguments, retval, exception); else if (name == "isDirectory") IsDirectory(name, object, arguments, retval, exception); -// else if (name == "showDevTools") -// CefV8Context::GetCurrentContext()->GetBrowser()->ShowDevTools(); else if (name == "openDialog") OpenDialog(name, object, arguments, retval, exception); else if (name == "open") diff --git a/Atom-Linux/onig_regexp_extension.cpp b/Atom-Linux/onig_regexp_extension.cpp index 949b2b84b..90f13d8ef 100644 --- a/Atom-Linux/onig_regexp_extension.cpp +++ b/Atom-Linux/onig_regexp_extension.cpp @@ -55,8 +55,10 @@ public: return CefV8Value::CreateNull(); CefRefPtr indices; - CefRefPtr resultArray = CefV8Value::CreateArray(region->num_regs); - CefRefPtr indicesArray = CefV8Value::CreateArray(region->num_regs); + CefRefPtr resultArray = CefV8Value::CreateArray( + region->num_regs); + CefRefPtr indicesArray = CefV8Value::CreateArray( + region->num_regs); for (int i = 0; i < region->num_regs; i++) { int begin = region->beg[i]; int end = region->end[i]; @@ -95,7 +97,7 @@ public: } CefRefPtr BuildCaptureIndices(OnigRegion *region) { - CefRefPtr array = CefV8Value::CreateArray(region->num_regs); + CefRefPtr array = CefV8Value::CreateArray(region->num_regs * 3); int i = 0; for (int index = 0; index < region->num_regs; index++) { int begin = region->beg[index]; @@ -127,17 +129,55 @@ IMPLEMENT_REFCOUNTING(OnigRegexpUserData) OnigRegexpExtension::OnigRegexpExtension() : CefV8Handler() { string realFilePath = io_utils_real_app_path( - "/src/stdlib/onig-reg-exp-extension.js"); + "/native/v8_extensions/onig_reg_exp.js"); if (!realFilePath.empty()) { string extensionCode; if (io_utils_read(realFilePath, &extensionCode) > 0) - CefRegisterExtension("v8/oniguruma", extensionCode, this); + CefRegisterExtension("v8/onig-reg-exp", extensionCode, this); } } bool OnigRegexpExtension::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) { + if (name == "captureIndices") { + CefRefPtr string = arguments[0]; + CefRefPtr index = arguments[1]; + CefRefPtr regexes = arguments[2]; + + int bestIndex = -1; + CefRefPtr captureIndicesForBestIndex; + CefRefPtr captureIndices; + + retval = CefV8Value::CreateObject(NULL); + for (int i = 0; i < regexes->GetArrayLength(); i++) { + OnigRegexpUserData *userData = + (OnigRegexpUserData *) regexes->GetValue(i)->GetUserData().get(); + captureIndices = userData->GetCaptureIndices(string, index); + if (captureIndices->IsNull()) + continue; + + if (bestIndex == -1 + || captureIndices->GetValue(1)->GetIntValue() + < captureIndicesForBestIndex->GetValue(1)->GetIntValue()) { + bestIndex = i; + captureIndicesForBestIndex = captureIndices; + if (captureIndices->GetValue(1)->GetIntValue() == 0) + break; // If the match starts at 0, just use it! + } + } + + if (bestIndex != -1) { + retval->SetValue("index", CefV8Value::CreateInt(bestIndex), + V8_PROPERTY_ATTRIBUTE_NONE); + retval->SetValue("captureIndices", captureIndicesForBestIndex, + V8_PROPERTY_ATTRIBUTE_NONE); + } + + return true; + + } + if (name == "getCaptureIndices") { CefRefPtr string = arguments[0]; CefRefPtr index =