Initial work towards a Linux build

This commit is contained in:
Kevin Sawicki
2012-06-03 19:15:00 -07:00
parent a589557aaa
commit a393f02d5a
78 changed files with 2023 additions and 0 deletions

4
Atom-Linux/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.o
atom
chrome.pak
locales/

79
Atom-Linux/Makefile Normal file
View File

@@ -0,0 +1,79 @@
CFLAGS_Release := -Werror \
-pthread \
-fno-exceptions \
-fno-strict-aliasing \
-Wall \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-fvisibility=hidden \
-pipe \
-fPIC \
-pthread \
-D_REENTRANT \
-I/usr/include/gtk-2.0 \
-I/usr/lib/gtk-2.0/include \
-I/usr/include/atk-1.0 \
-I/usr/include/cairo \
-I/usr/include/pango-1.0 \
-I/usr/include/gio-unix-2.0/ \
-I/usr/include/glib-2.0 \
-I/usr/lib/glib-2.0/include \
-I/usr/include/pixman-1 \
-I/usr/include/freetype2 \
-I/usr/include/directfb \
-I/usr/include/libpng12 \
-Icefclient \
-I../cef \
-O2 \
-fno-ident \
-fdata-sections \
-ffunction-sections
CFLAGS_CC_Release := -fno-rtti \
-fno-threadsafe-statics \
-fvisibility-inlines-hidden \
-Wsign-compare
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-fPIC \
-Lobj/cef \
-Wl,-O1 \
-Wl,--as-needed \
-Wl,--gc-sections \
-Wl,-rpath=obj/cef \
-Wl,-rpath-link=obj/cef
LIBS := -lX11 \
-lgtk-x11-2.0 \
-lgdk-x11-2.0 \
-latk-1.0 \
-lgio-2.0 \
-lpangoft2-1.0 \
-lgdk_pixbuf-2.0 \
-lm \
-lpangocairo-1.0 \
-lcairo \
-lpango-1.0 \
-lfreetype \
-lfontconfig \
-lgobject-2.0 \
-lgmodule-2.0 \
-lgthread-2.0 \
-lrt \
-lglib-2.0 \
-lcef \
-lcef_dll_wrapper
SOURCES=atom.cpp cefclient.cpp string_util.cpp native_handler.cpp cefclient_switches.cpp client_handler.cpp client_handler_gtk.cpp
OBJECTS=$(SOURCES:.cpp=.o)
all:
g++ $(CFLAGS_Release) $(CFLAGS_CC_Release) -c $(SOURCES)
g++ -o atom $(OBJECTS) $(LDFLAGS_Release) $(LIBS)
cp ../Atom/Resources/chrome.pak .
mkdir -p locales/
cp ../Atom/Resources/en.lproj/locale.pak locales/en-US.pak
clean:
rm -rf *.o atom chrome.pak locales

129
Atom-Linux/atom.cpp Normal file
View File

@@ -0,0 +1,129 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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 <gtk/gtk.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include "cefclient.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"
char szWorkingDir[512]; // The current working directory
// The global ClientHandler reference.
extern CefRefPtr<ClientHandler> g_handler;
void destroy(void) {
CefQuitMessageLoop();
}
void TerminationSignalHandler(int signatl) {
destroy();
}
// Callback for when you press enter in the URL box.
void URLEntryActivate(GtkEntry* entry) {
if (!g_handler.get() || !g_handler->GetBrowserHwnd())
return;
const gchar* url = gtk_entry_get_text(entry);
g_handler->GetBrowser()->GetMainFrame()->LoadURL(std::string(url).c_str());
}
// GTK utility functions ----------------------------------------------
GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text,
GCallback callback) {
GtkWidget* entry = gtk_menu_item_new_with_label(text);
g_signal_connect(entry, "activate", callback, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry);
return entry;
}
GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text) {
GtkWidget* menu_widget = gtk_menu_new();
GtkWidget* menu_header = gtk_menu_item_new_with_label(text);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_header), menu_widget);
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_header);
return menu_widget;
}
// WebViewDelegate::TakeFocus in the test webview delegate.
static gboolean HandleFocus(GtkWidget* widget,
GdkEventFocus* focus) {
if (g_handler.get() && g_handler->GetBrowserHwnd()) {
// Give focus to the browser window.
g_handler->GetBrowser()->SetFocus(true);
}
return TRUE;
}
int main(int argc, char *argv[]) {
if (!getcwd(szWorkingDir, sizeof (szWorkingDir)))
return -1;
GtkWidget* window;
gtk_init(&argc, &argv);
CefSettings settings;
CefRefPtr<CefApp> app;
// Initialize CEF.
CefInitialize(settings, app);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Atom");
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
g_signal_connect(window, "focus", G_CALLBACK(&HandleFocus), NULL);
GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), NULL, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_widget_destroyed), &window);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(destroy), NULL);
// Create the handler.
g_handler = new ClientHandler();
g_handler->SetMainHwnd(vbox);
// Create the browser view.
CefWindowInfo window_info;
CefBrowserSettings browserSettings;
window_info.SetAsChild(vbox);
CefBrowser::CreateBrowserSync(window_info,
static_cast<CefRefPtr<CefClient> >(g_handler),
"", browserSettings);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(GTK_WIDGET(window));
// Install an signal handler so we clean up after ourselves.
signal(SIGINT, TerminationSignalHandler);
signal(SIGTERM, TerminationSignalHandler);
CefRunMessageLoop();
CefShutdown();
return 0;
}
// Global functions
std::string AppGetWorkingDirectory() {
return szWorkingDir;
}

653
Atom-Linux/cefclient.cpp Normal file
View File

@@ -0,0 +1,653 @@
// Copyright (c) 2010 The Chromium Embedded Framework 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 "cefclient.h"
#include <stdio.h>
#include <cstdlib>
#include <sstream>
#include <string>
#include "include/cef_app.h"
#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/cef_frame.h"
#include "include/cef_runnable.h"
#include "include/cef_web_plugin.h"
#include "include/cef_web_urlrequest.h"
#include "cefclient_switches.h"
#include "client_handler.h"
#include "string_util.h"
#include "util.h"
namespace {
void UIT_InvokeScript(CefRefPtr<CefBrowser> browser) {
REQUIRE_UI_THREAD();
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
CefRefPtr<CefV8Context> v8Context = frame->GetV8Context();
CefString url = frame->GetURL();
if (!v8Context.get()) {
frame->ExecuteJavaScript("alert('Failed to get V8 context!');", url, 0);
} else if (v8Context->Enter()) {
CefRefPtr<CefV8Value> globalObj = v8Context->GetGlobal();
CefRefPtr<CefV8Value> evalFunc = globalObj->GetValue("eval");
CefRefPtr<CefV8Value> arg0 = CefV8Value::CreateString("1+2");
CefV8ValueList args;
args.push_back(arg0);
CefRefPtr<CefV8Value> retVal;
CefRefPtr<CefV8Exception> exception;
if (evalFunc->ExecuteFunctionWithContext(v8Context, globalObj, args, retVal,
exception, false)) {
if (retVal.get()) {
frame->ExecuteJavaScript(
std::string("alert('InvokeScript returns ") +
retVal->GetStringValue().ToString() + "!');",
url, 0);
} else {
frame->ExecuteJavaScript(
std::string("alert('InvokeScript returns exception: ") +
exception->GetMessage().ToString() + "!');",
url, 0);
}
} else {
frame->ExecuteJavaScript("alert('Failed to execute function!');", url, 0);
}
v8Context->Exit();
} else {
frame->ExecuteJavaScript("alert('Failed to enter into V8 context!');",
url, 0);
}
}
void UIT_RunPluginInfoTest(CefRefPtr<CefBrowser> browser) {
std::string html = "<html><head><title>Plugin Info Test</title></head><body>";
// Find the flash plugin first to test that get by name works.
std::string flash_name;
CefRefPtr<CefWebPluginInfo> info = CefGetWebPluginInfo("Shockwave Flash");
if (info.get()) {
flash_name = info->GetName();
html += "\n<b>Flash is installed!</b>"
"<br/>Name: " + flash_name +
"\n<br/>Description: " + info->GetDescription().ToString() +
"\n<br/>Version: " + info->GetVersion().ToString() +
"\n<br/>Path: " + info->GetPath().ToString();
}
if (!flash_name.empty()) {
html += "\n<br/><br/><b>Other installed plugins:</b>";
} else {
html += "\n<b>Installed plugins:</b>";
}
// Display all other plugins.
size_t count = CefGetWebPluginCount();
for (size_t i = 0; i < count; ++i) {
CefRefPtr<CefWebPluginInfo> info = CefGetWebPluginInfo(i);
ASSERT(info.get());
if (!flash_name.empty() && info->GetName() == flash_name)
continue;
html += "\n<br/><br/>Name: " + info->GetName().ToString() +
"\n<br/>Description: " + info->GetDescription().ToString() +
"\n<br/>Version: " + info->GetVersion().ToString() +
"\n<br/>Path: " + info->GetPath().ToString();
}
html += "</body></html>";
browser->GetMainFrame()->LoadString(html, "http://tests/plugin_info");
}
// Return the int representation of the specified string.
int GetIntValue(const CefString& str) {
if (str.empty())
return 0;
std::string stdStr = str;
return atoi(stdStr.c_str());
}
// ClientApp implementation.
class ClientApp : public CefApp,
public CefProxyHandler {
public:
ClientApp(cef_proxy_type_t proxy_type, const CefString& proxy_config)
: proxy_type_(proxy_type),
proxy_config_(proxy_config) {
}
// CefApp methods
virtual CefRefPtr<CefProxyHandler> GetProxyHandler() OVERRIDE { return this; }
// CefProxyHandler methods
virtual void GetProxyForUrl(const CefString& url,
CefProxyInfo& proxy_info) OVERRIDE {
proxy_info.proxyType = proxy_type_;
if (!proxy_config_.empty())
CefString(&proxy_info.proxyList) = proxy_config_;
}
protected:
cef_proxy_type_t proxy_type_;
CefString proxy_config_;
IMPLEMENT_REFCOUNTING(ClientApp);
};
} // namespace
CefRefPtr<ClientHandler> g_handler;
CefRefPtr<CefCommandLine> g_command_line;
CefRefPtr<CefBrowser> AppGetBrowser() {
if (!g_handler.get())
return NULL;
return g_handler->GetBrowser();
}
CefWindowHandle AppGetMainHwnd() {
if (!g_handler.get())
return NULL;
return g_handler->GetMainHwnd();
}
void AppInitCommandLine(int argc, const char* const* argv) {
g_command_line = CefCommandLine::CreateCommandLine();
#if defined(OS_WIN)
g_command_line->InitFromString(::GetCommandLineW());
#else
g_command_line->InitFromArgv(argc, argv);
#endif
}
// Returns the application command line object.
CefRefPtr<CefCommandLine> AppGetCommandLine() {
return g_command_line;
}
// Returns the application settings based on command line arguments.
void AppGetSettings(CefSettings& settings, CefRefPtr<CefApp>& app) {
ASSERT(g_command_line.get());
if (!g_command_line.get())
return;
CefString str;
#if defined(OS_WIN)
settings.multi_threaded_message_loop =
g_command_line->HasSwitch(cefclient::kMultiThreadedMessageLoop);
#endif
CefString(&settings.cache_path) =
g_command_line->GetSwitchValue(cefclient::kCachePath);
CefString(&settings.user_agent) =
g_command_line->GetSwitchValue(cefclient::kUserAgent);
CefString(&settings.product_version) =
g_command_line->GetSwitchValue(cefclient::kProductVersion);
CefString(&settings.locale) =
g_command_line->GetSwitchValue(cefclient::kLocale);
CefString(&settings.log_file) =
g_command_line->GetSwitchValue(cefclient::kLogFile);
{
std::string str = g_command_line->GetSwitchValue(cefclient::kLogSeverity);
bool invalid = false;
if (!str.empty()) {
if (str == cefclient::kLogSeverity_Verbose)
settings.log_severity = LOGSEVERITY_VERBOSE;
else if (str == cefclient::kLogSeverity_Info)
settings.log_severity = LOGSEVERITY_INFO;
else if (str == cefclient::kLogSeverity_Warning)
settings.log_severity = LOGSEVERITY_WARNING;
else if (str == cefclient::kLogSeverity_Error)
settings.log_severity = LOGSEVERITY_ERROR;
else if (str == cefclient::kLogSeverity_ErrorReport)
settings.log_severity = LOGSEVERITY_ERROR_REPORT;
else if (str == cefclient::kLogSeverity_Disable)
settings.log_severity = LOGSEVERITY_DISABLE;
else
invalid = true;
}
if (str.empty() || invalid) {
#ifdef NDEBUG
// Only log error messages and higher in release build.
settings.log_severity = LOGSEVERITY_ERROR;
#endif
}
}
{
std::string str = g_command_line->GetSwitchValue(cefclient::kGraphicsImpl);
if (!str.empty()) {
#if defined(OS_WIN)
if (str == cefclient::kGraphicsImpl_Angle)
settings.graphics_implementation = ANGLE_IN_PROCESS;
else if (str == cefclient::kGraphicsImpl_AngleCmdBuffer)
settings.graphics_implementation = ANGLE_IN_PROCESS_COMMAND_BUFFER;
else
#endif
if (str == cefclient::kGraphicsImpl_Desktop)
settings.graphics_implementation = DESKTOP_IN_PROCESS;
else if (str == cefclient::kGraphicsImpl_DesktopCmdBuffer)
settings.graphics_implementation = DESKTOP_IN_PROCESS_COMMAND_BUFFER;
}
}
settings.local_storage_quota = GetIntValue(
g_command_line->GetSwitchValue(cefclient::kLocalStorageQuota));
settings.session_storage_quota = GetIntValue(
g_command_line->GetSwitchValue(cefclient::kSessionStorageQuota));
CefString(&settings.javascript_flags) =
g_command_line->GetSwitchValue(cefclient::kJavascriptFlags);
CefString(&settings.pack_file_path) =
g_command_line->GetSwitchValue(cefclient::kPackFilePath);
CefString(&settings.locales_dir_path) =
g_command_line->GetSwitchValue(cefclient::kLocalesDirPath);
settings.pack_loading_disabled =
g_command_line->HasSwitch(cefclient::kPackLoadingDisabled);
// Retrieve command-line proxy configuration, if any.
bool has_proxy = false;
cef_proxy_type_t proxy_type = PROXY_TYPE_DIRECT;
CefString proxy_config;
if (g_command_line->HasSwitch(cefclient::kProxyType)) {
std::string str = g_command_line->GetSwitchValue(cefclient::kProxyType);
if (str == cefclient::kProxyType_Direct) {
has_proxy = true;
proxy_type = PROXY_TYPE_DIRECT;
} else if (str == cefclient::kProxyType_Named ||
str == cefclient::kProxyType_Pac) {
proxy_config = g_command_line->GetSwitchValue(cefclient::kProxyConfig);
if (!proxy_config.empty()) {
has_proxy = true;
proxy_type = (str == cefclient::kProxyType_Named?
PROXY_TYPE_NAMED:PROXY_TYPE_PAC_STRING);
}
}
}
if (has_proxy) {
// Provide a ClientApp instance to handle proxy resolution.
app = new ClientApp(proxy_type, proxy_config);
}
}
// Returns the application browser settings based on command line arguments.
void AppGetBrowserSettings(CefBrowserSettings& settings) {
ASSERT(g_command_line.get());
if (!g_command_line.get())
return;
settings.drag_drop_disabled =
g_command_line->HasSwitch(cefclient::kDragDropDisabled);
settings.load_drops_disabled =
g_command_line->HasSwitch(cefclient::kLoadDropsDisabled);
settings.history_disabled =
g_command_line->HasSwitch(cefclient::kHistoryDisabled);
settings.remote_fonts_disabled =
g_command_line->HasSwitch(cefclient::kRemoteFontsDisabled);
CefString(&settings.default_encoding) =
g_command_line->GetSwitchValue(cefclient::kDefaultEncoding);
settings.encoding_detector_enabled =
g_command_line->HasSwitch(cefclient::kEncodingDetectorEnabled);
settings.javascript_disabled =
g_command_line->HasSwitch(cefclient::kJavascriptDisabled);
settings.javascript_open_windows_disallowed =
g_command_line->HasSwitch(cefclient::kJavascriptOpenWindowsDisallowed);
settings.javascript_close_windows_disallowed =
g_command_line->HasSwitch(cefclient::kJavascriptCloseWindowsDisallowed);
settings.javascript_access_clipboard_disallowed =
g_command_line->HasSwitch(
cefclient::kJavascriptAccessClipboardDisallowed);
settings.dom_paste_disabled =
g_command_line->HasSwitch(cefclient::kDomPasteDisabled);
settings.caret_browsing_enabled =
g_command_line->HasSwitch(cefclient::kCaretBrowsingDisabled);
settings.java_disabled =
g_command_line->HasSwitch(cefclient::kJavaDisabled);
settings.plugins_disabled =
g_command_line->HasSwitch(cefclient::kPluginsDisabled);
settings.universal_access_from_file_urls_allowed =
g_command_line->HasSwitch(cefclient::kUniversalAccessFromFileUrlsAllowed);
settings.file_access_from_file_urls_allowed =
g_command_line->HasSwitch(cefclient::kFileAccessFromFileUrlsAllowed);
settings.web_security_disabled =
g_command_line->HasSwitch(cefclient::kWebSecurityDisabled);
settings.xss_auditor_enabled =
g_command_line->HasSwitch(cefclient::kXssAuditorEnabled);
settings.image_load_disabled =
g_command_line->HasSwitch(cefclient::kImageLoadingDisabled);
settings.shrink_standalone_images_to_fit =
g_command_line->HasSwitch(cefclient::kShrinkStandaloneImagesToFit);
settings.site_specific_quirks_disabled =
g_command_line->HasSwitch(cefclient::kSiteSpecificQuirksDisabled);
settings.text_area_resize_disabled =
g_command_line->HasSwitch(cefclient::kTextAreaResizeDisabled);
settings.page_cache_disabled =
g_command_line->HasSwitch(cefclient::kPageCacheDisabled);
settings.tab_to_links_disabled =
g_command_line->HasSwitch(cefclient::kTabToLinksDisabled);
settings.hyperlink_auditing_disabled =
g_command_line->HasSwitch(cefclient::kHyperlinkAuditingDisabled);
settings.user_style_sheet_enabled =
g_command_line->HasSwitch(cefclient::kUserStyleSheetEnabled);
CefString(&settings.user_style_sheet_location) =
g_command_line->GetSwitchValue(cefclient::kUserStyleSheetLocation);
settings.author_and_user_styles_disabled =
g_command_line->HasSwitch(cefclient::kAuthorAndUserStylesDisabled);
settings.local_storage_disabled =
g_command_line->HasSwitch(cefclient::kLocalStorageDisabled);
settings.databases_disabled =
g_command_line->HasSwitch(cefclient::kDatabasesDisabled);
settings.application_cache_disabled =
g_command_line->HasSwitch(cefclient::kApplicationCacheDisabled);
settings.webgl_disabled =
g_command_line->HasSwitch(cefclient::kWebglDisabled);
settings.accelerated_compositing_enabled =
g_command_line->HasSwitch(cefclient::kAcceleratedCompositingEnabled);
settings.threaded_compositing_enabled =
g_command_line->HasSwitch(cefclient::kThreadedCompositingEnabled);
settings.accelerated_layers_disabled =
g_command_line->HasSwitch(cefclient::kAcceleratedLayersDisabled);
settings.accelerated_video_disabled =
g_command_line->HasSwitch(cefclient::kAcceleratedVideoDisabled);
settings.accelerated_2d_canvas_disabled =
g_command_line->HasSwitch(cefclient::kAcceledated2dCanvasDisabled);
settings.accelerated_painting_disabled =
g_command_line->HasSwitch(cefclient::kAcceleratedPaintingDisabled);
settings.accelerated_filters_disabled =
g_command_line->HasSwitch(cefclient::kAcceleratedFiltersDisabled);
settings.accelerated_plugins_disabled =
g_command_line->HasSwitch(cefclient::kAcceleratedPluginsDisabled);
settings.developer_tools_disabled =
g_command_line->HasSwitch(cefclient::kDeveloperToolsDisabled);
settings.fullscreen_enabled =
g_command_line->HasSwitch(cefclient::kFullscreenEnabled);
}
static void ExecuteGetSource(CefRefPtr<CefFrame> frame) {
// Retrieve the current page source and display.
std::string source = frame->GetSource();
source = StringReplace(source, "<", "&lt;");
source = StringReplace(source, ">", "&gt;");
std::stringstream ss;
ss << "<html><body>Source:<pre>" << source << "</pre></body></html>";
frame->LoadString(ss.str(), "http://tests/getsource");
}
void RunGetSourceTest(CefRefPtr<CefBrowser> browser) {
// Execute the GetSource() call on the UI thread.
CefPostTask(TID_UI,
NewCefRunnableFunction(&ExecuteGetSource, browser->GetMainFrame()));
}
static void ExecuteGetText(CefRefPtr<CefFrame> frame) {
std::string text = frame->GetText();
text = StringReplace(text, "<", "&lt;");
text = StringReplace(text, ">", "&gt;");
std::stringstream ss;
ss << "<html><body>Text:<pre>" << text << "</pre></body></html>";
frame->LoadString(ss.str(), "http://tests/gettext");
}
void RunGetTextTest(CefRefPtr<CefBrowser> browser) {
// Execute the GetText() call on the UI thread.
CefPostTask(TID_UI,
NewCefRunnableFunction(&ExecuteGetText, browser->GetMainFrame()));
}
void RunRequestTest(CefRefPtr<CefBrowser> browser) {
// Create a new request
CefRefPtr<CefRequest> request(CefRequest::CreateRequest());
// Set the request URL
request->SetURL("http://tests/request");
// Add post data to the request. The correct method and content-
// type headers will be set by CEF.
CefRefPtr<CefPostDataElement> postDataElement(
CefPostDataElement::CreatePostDataElement());
std::string data = "arg1=val1&arg2=val2";
postDataElement->SetToBytes(data.length(), data.c_str());
CefRefPtr<CefPostData> postData(CefPostData::CreatePostData());
postData->AddElement(postDataElement);
request->SetPostData(postData);
// Add a custom header
CefRequest::HeaderMap headerMap;
headerMap.insert(
std::make_pair("X-My-Header", "My Header Value"));
request->SetHeaderMap(headerMap);
// Load the request
browser->GetMainFrame()->LoadRequest(request);
}
void RunJavaScriptExecuteTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->ExecuteJavaScript(
"alert('JavaScript execute works!');", "about:blank", 0);
}
void RunJavaScriptInvokeTest(CefRefPtr<CefBrowser> browser) {
if (CefCurrentlyOn(TID_UI)) {
UIT_InvokeScript(browser);
} else {
// Execute on the UI thread.
CefPostTask(TID_UI, NewCefRunnableFunction(&UIT_InvokeScript, browser));
}
}
void RunPopupTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->ExecuteJavaScript(
"window.open('http://www.google.com');", "about:blank", 0);
}
void RunLocalStorageTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL("http://tests/localstorage");
}
void RunAccelerated2DCanvasTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL(
"http://mudcu.be/labs/JS1k/BreathingGalaxies.html");
}
void RunAcceleratedLayersTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL(
"http://webkit.org/blog-files/3d-transforms/poster-circle.html");
}
void RunWebGLTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL(
"http://webglsamples.googlecode.com/hg/field/field.html");
}
void RunHTML5VideoTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL(
"http://www.youtube.com/watch?v=siOHh0uzcuY&html5=True");
}
void RunXMLHTTPRequestTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL("http://tests/xmlhttprequest");
}
void RunWebURLRequestTest(CefRefPtr<CefBrowser> browser) {
class RequestClient : public CefWebURLRequestClient {
public:
explicit RequestClient(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
virtual void OnStateChange(CefRefPtr<CefWebURLRequest> requester,
RequestState state) {
REQUIRE_UI_THREAD();
if (state == WUR_STATE_DONE) {
buffer_ = StringReplace(buffer_, "<", "&lt;");
buffer_ = StringReplace(buffer_, ">", "&gt;");
std::stringstream ss;
ss << "<html><body>Source:<pre>" << buffer_ << "</pre></body></html>";
browser_->GetMainFrame()->LoadString(ss.str(),
"http://tests/weburlrequest");
}
}
virtual void OnRedirect(CefRefPtr<CefWebURLRequest> requester,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
REQUIRE_UI_THREAD();
}
virtual void OnHeadersReceived(CefRefPtr<CefWebURLRequest> requester,
CefRefPtr<CefResponse> response) {
REQUIRE_UI_THREAD();
}
virtual void OnProgress(CefRefPtr<CefWebURLRequest> requester,
uint64 bytesSent, uint64 totalBytesToBeSent) {
REQUIRE_UI_THREAD();
}
virtual void OnData(CefRefPtr<CefWebURLRequest> requester,
const void* data, int dataLength) {
REQUIRE_UI_THREAD();
buffer_.append(static_cast<const char*>(data), dataLength);
}
virtual void OnError(CefRefPtr<CefWebURLRequest> requester,
ErrorCode errorCode) {
REQUIRE_UI_THREAD();
std::stringstream ss;
ss << "Load failed with error code " << errorCode;
browser_->GetMainFrame()->LoadString(ss.str(),
"http://tests/weburlrequest");
}
protected:
CefRefPtr<CefBrowser> browser_;
std::string buffer_;
IMPLEMENT_REFCOUNTING(CefWebURLRequestClient);
};
CefRefPtr<CefRequest> request(CefRequest::CreateRequest());
request->SetURL("http://www.google.com");
CefRefPtr<CefWebURLRequestClient> client(new RequestClient(browser));
CefRefPtr<CefWebURLRequest> requester(
CefWebURLRequest::CreateWebURLRequest(request, client));
}
void RunDOMAccessTest(CefRefPtr<CefBrowser> browser) {
class Listener : public CefDOMEventListener {
public:
Listener() {}
virtual void HandleEvent(CefRefPtr<CefDOMEvent> event) {
CefRefPtr<CefDOMDocument> document = event->GetDocument();
ASSERT(document.get());
std::stringstream ss;
CefRefPtr<CefDOMNode> button = event->GetTarget();
ASSERT(button.get());
std::string buttonValue = button->GetElementAttribute("value");
ss << "You clicked the " << buttonValue.c_str() << " button. ";
if (document->HasSelection()) {
std::string startName, endName;
// Determine the start name by first trying to locate the "id" attribute
// and then defaulting to the tag name.
{
CefRefPtr<CefDOMNode> node = document->GetSelectionStartNode();
if (!node->IsElement())
node = node->GetParent();
if (node->IsElement() && node->HasElementAttribute("id"))
startName = node->GetElementAttribute("id");
else
startName = node->GetName();
}
// Determine the end name by first trying to locate the "id" attribute
// and then defaulting to the tag name.
{
CefRefPtr<CefDOMNode> node = document->GetSelectionEndNode();
if (!node->IsElement())
node = node->GetParent();
if (node->IsElement() && node->HasElementAttribute("id"))
endName = node->GetElementAttribute("id");
else
endName = node->GetName();
}
ss << "The selection is from " <<
startName.c_str() << ":" << document->GetSelectionStartOffset() <<
" to " <<
endName.c_str() << ":" << document->GetSelectionEndOffset();
} else {
ss << "Nothing is selected.";
}
// Update the description.
CefRefPtr<CefDOMNode> desc = document->GetElementById("description");
ASSERT(desc.get());
CefRefPtr<CefDOMNode> text = desc->GetFirstChild();
ASSERT(text.get());
ASSERT(text->IsText());
text->SetValue(ss.str());
}
IMPLEMENT_REFCOUNTING(Listener);
};
class Visitor : public CefDOMVisitor {
public:
Visitor() {}
virtual void Visit(CefRefPtr<CefDOMDocument> document) {
// Register an click listener for the button.
CefRefPtr<CefDOMNode> button = document->GetElementById("button");
ASSERT(button.get());
button->AddEventListener("click", new Listener(), false);
}
IMPLEMENT_REFCOUNTING(Visitor);
};
// The DOM visitor will be called after the path is loaded.
CefRefPtr<CefClient> client = browser->GetClient();
static_cast<ClientHandler*>(client.get())->AddDOMVisitor(
"http://tests/domaccess", new Visitor());
browser->GetMainFrame()->LoadURL("http://tests/domaccess");
}
void RunDragDropTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL("http://html5demos.com/drag");
}
void RunModalDialogTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL("http://tests/modalmain");
}
void RunPluginInfoTest(CefRefPtr<CefBrowser> browser) {
if (CefCurrentlyOn(TID_UI)) {
UIT_RunPluginInfoTest(browser);
} else {
// Execute on the UI thread.
CefPostTask(TID_UI,
NewCefRunnableFunction(&UIT_RunPluginInfoTest, browser));
}
}

61
Atom-Linux/cefclient.h Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_CEFCLIENT_H_
#define CEF_TESTS_CEFCLIENT_CEFCLIENT_H_
#pragma once
#include <string>
#include "include/cef_base.h"
class CefApp;
class CefBrowser;
class CefCommandLine;
// Returns the main browser window instance.
CefRefPtr<CefBrowser> AppGetBrowser();
// Returns the main application window handle.
CefWindowHandle AppGetMainHwnd();
// Returns the application working directory.
std::string AppGetWorkingDirectory();
// Initialize the application command line.
void AppInitCommandLine(int argc, const char* const* argv);
// Returns the application command line object.
CefRefPtr<CefCommandLine> AppGetCommandLine();
// Returns the application settings based on command line arguments.
void AppGetSettings(CefSettings& settings, CefRefPtr<CefApp>& app);
// Returns the application browser settings based on command line arguments.
void AppGetBrowserSettings(CefBrowserSettings& settings);
// Implementations for various tests.
void RunGetSourceTest(CefRefPtr<CefBrowser> browser);
void RunGetTextTest(CefRefPtr<CefBrowser> browser);
void RunRequestTest(CefRefPtr<CefBrowser> browser);
void RunJavaScriptExecuteTest(CefRefPtr<CefBrowser> browser);
void RunJavaScriptInvokeTest(CefRefPtr<CefBrowser> browser);
void RunPopupTest(CefRefPtr<CefBrowser> browser);
void RunLocalStorageTest(CefRefPtr<CefBrowser> browser);
void RunAccelerated2DCanvasTest(CefRefPtr<CefBrowser> browser);
void RunAcceleratedLayersTest(CefRefPtr<CefBrowser> browser);
void RunWebGLTest(CefRefPtr<CefBrowser> browser);
void RunHTML5VideoTest(CefRefPtr<CefBrowser> browser);
void RunXMLHTTPRequestTest(CefRefPtr<CefBrowser> browser);
void RunWebURLRequestTest(CefRefPtr<CefBrowser> browser);
void RunDOMAccessTest(CefRefPtr<CefBrowser> browser);
void RunDragDropTest(CefRefPtr<CefBrowser> browser);
void RunModalDialogTest(CefRefPtr<CefBrowser> browser);
void RunPluginInfoTest(CefRefPtr<CefBrowser> browser);
#if defined(OS_WIN)
void RunTransparentPopupTest(CefRefPtr<CefBrowser> browser);
void RunGetImageTest(CefRefPtr<CefBrowser> browser);
#endif
#endif // CEF_TESTS_CEFCLIENT_CEFCLIENT_H_

View File

@@ -0,0 +1,93 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
// This file is shared by cefclient and cef_unittests so don't include using
// a qualified path.
#include "cefclient_switches.h" // NOLINT(build/include)
namespace cefclient {
// CefSettings attributes.
const char kMultiThreadedMessageLoop[] = "multi-threaded-message-loop";
const char kCachePath[] = "cache-path";
const char kUserAgent[] = "user-agent";
const char kProductVersion[] = "product-version";
const char kLocale[] = "locale";
const char kLogFile[] = "log-file";
const char kLogSeverity[] = "log-severity";
const char kLogSeverity_Verbose[] = "verbose";
const char kLogSeverity_Info[] = "info";
const char kLogSeverity_Warning[] = "warning";
const char kLogSeverity_Error[] = "error";
const char kLogSeverity_ErrorReport[] = "error-report";
const char kLogSeverity_Disable[] = "disable";
const char kGraphicsImpl[] = "graphics-implementation";
const char kGraphicsImpl_Angle[] = "angle";
const char kGraphicsImpl_AngleCmdBuffer[] = "angle-command-buffer";
const char kGraphicsImpl_Desktop[] = "desktop";
const char kGraphicsImpl_DesktopCmdBuffer[] = "desktop-command-buffer";
const char kLocalStorageQuota[] = "local-storage-quota";
const char kSessionStorageQuota[] = "session-storage-quota";
const char kJavascriptFlags[] = "javascript-flags";
const char kPackFilePath[] = "pack-file-path";
const char kLocalesDirPath[] = "locales-dir-path";
const char kPackLoadingDisabled[] = "pack-loading-disabled";
// CefBrowserSettings attributes.
const char kDragDropDisabled[] = "drag-drop-disabled";
const char kLoadDropsDisabled[] = "load-drops-disabled";
const char kHistoryDisabled[] = "history-disabled";
const char kRemoteFontsDisabled[] = "remote-fonts-disabled";
const char kDefaultEncoding[] = "default-encoding";
const char kEncodingDetectorEnabled[] = "encoding-detector-enabled";
const char kJavascriptDisabled[] = "javascript-disabled";
const char kJavascriptOpenWindowsDisallowed[] =
"javascript-open-windows-disallowed";
const char kJavascriptCloseWindowsDisallowed[] =
"javascript-close-windows-disallowed";
const char kJavascriptAccessClipboardDisallowed[] =
"javascript-access-clipboard-disallowed";
const char kDomPasteDisabled[] = "dom-paste-disabled";
const char kCaretBrowsingDisabled[] = "caret-browsing-enabled";
const char kJavaDisabled[] = "java-disabled";
const char kPluginsDisabled[] = "plugins-disabled";
const char kUniversalAccessFromFileUrlsAllowed[] =
"universal-access-from-file-urls-allowed";
const char kFileAccessFromFileUrlsAllowed[] =
"file-access-from-file-urls-allowed";
const char kWebSecurityDisabled[] = "web-security-disabled";
const char kXssAuditorEnabled[] = "xss-auditor-enabled";
const char kImageLoadingDisabled[] = "image-load-disabled";
const char kShrinkStandaloneImagesToFit[] = "shrink-standalone-images-to-fit";
const char kSiteSpecificQuirksDisabled[] = "site-specific-quirks-disabled";
const char kTextAreaResizeDisabled[] = "text-area-resize-disabled";
const char kPageCacheDisabled[] = "page-cache-disabled";
const char kTabToLinksDisabled[] = "tab-to-links-disabled";
const char kHyperlinkAuditingDisabled[] = "hyperlink-auditing-disabled";
const char kUserStyleSheetEnabled[] = "user-style-sheet-enabled";
const char kUserStyleSheetLocation[] = "user-style-sheet-location";
const char kAuthorAndUserStylesDisabled[] = "author-and-user-styles-disabled";
const char kLocalStorageDisabled[] = "local-storage-disabled";
const char kDatabasesDisabled[] = "databases-disabled";
const char kApplicationCacheDisabled[] = "application-cache-disabled";
const char kWebglDisabled[] = "webgl-disabled";
const char kAcceleratedCompositingEnabled[] = "accelerated-compositing-enabled";
const char kThreadedCompositingEnabled[] = "threaded-compositing-enabled";
const char kAcceleratedLayersDisabled[] = "accelerated-layers-disabled";
const char kAcceleratedVideoDisabled[] = "accelerated-video-disabled";
const char kAcceledated2dCanvasDisabled[] = "accelerated-2d-canvas-disabled";
const char kAcceleratedPaintingDisabled[] = "accelerated-painting-disabled";
const char kAcceleratedFiltersDisabled[] = "accelerated-filters-disabled";
const char kAcceleratedPluginsDisabled[] = "accelerated-plugins-disabled";
const char kDeveloperToolsDisabled[] = "developer-tools-disabled";
const char kFullscreenEnabled[] = "fullscreen-enabled";
// Other attributes.
const char kProxyType[] = "proxy-type";
const char kProxyType_Direct[] = "direct";
const char kProxyType_Named[] = "named";
const char kProxyType_Pac[] = "pac";
const char kProxyConfig[] = "proxy-config";
} // namespace cefclient

View File

@@ -0,0 +1,92 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
// Defines all of the command line switches used by cefclient.
#ifndef CEF_TESTS_CEFCLIENT_CEFCLIENT_SWITCHES_H_
#define CEF_TESTS_CEFCLIENT_CEFCLIENT_SWITCHES_H_
#pragma once
namespace cefclient {
// CefSettings attributes.
extern const char kMultiThreadedMessageLoop[];
extern const char kCachePath[];
extern const char kUserAgent[];
extern const char kProductVersion[];
extern const char kLocale[];
extern const char kLogFile[];
extern const char kLogSeverity[];
extern const char kLogSeverity_Verbose[];
extern const char kLogSeverity_Info[];
extern const char kLogSeverity_Warning[];
extern const char kLogSeverity_Error[];
extern const char kLogSeverity_ErrorReport[];
extern const char kLogSeverity_Disable[];
extern const char kGraphicsImpl[];
extern const char kGraphicsImpl_Angle[];
extern const char kGraphicsImpl_AngleCmdBuffer[];
extern const char kGraphicsImpl_Desktop[];
extern const char kGraphicsImpl_DesktopCmdBuffer[];
extern const char kLocalStorageQuota[];
extern const char kSessionStorageQuota[];
extern const char kJavascriptFlags[];
extern const char kPackFilePath[];
extern const char kLocalesDirPath[];
extern const char kPackLoadingDisabled[];
// CefBrowserSettings attributes.
extern const char kDragDropDisabled[];
extern const char kLoadDropsDisabled[];
extern const char kHistoryDisabled[];
extern const char kRemoteFontsDisabled[];
extern const char kDefaultEncoding[];
extern const char kEncodingDetectorEnabled[];
extern const char kJavascriptDisabled[];
extern const char kJavascriptOpenWindowsDisallowed[];
extern const char kJavascriptCloseWindowsDisallowed[];
extern const char kJavascriptAccessClipboardDisallowed[];
extern const char kDomPasteDisabled[];
extern const char kCaretBrowsingDisabled[];
extern const char kJavaDisabled[];
extern const char kPluginsDisabled[];
extern const char kUniversalAccessFromFileUrlsAllowed[];
extern const char kFileAccessFromFileUrlsAllowed[];
extern const char kWebSecurityDisabled[];
extern const char kXssAuditorEnabled[];
extern const char kImageLoadingDisabled[];
extern const char kShrinkStandaloneImagesToFit[];
extern const char kSiteSpecificQuirksDisabled[];
extern const char kTextAreaResizeDisabled[];
extern const char kPageCacheDisabled[];
extern const char kTabToLinksDisabled[];
extern const char kHyperlinkAuditingDisabled[];
extern const char kUserStyleSheetEnabled[];
extern const char kUserStyleSheetLocation[];
extern const char kAuthorAndUserStylesDisabled[];
extern const char kLocalStorageDisabled[];
extern const char kDatabasesDisabled[];
extern const char kApplicationCacheDisabled[];
extern const char kWebglDisabled[];
extern const char kAcceleratedCompositingEnabled[];
extern const char kThreadedCompositingEnabled[];
extern const char kAcceleratedLayersDisabled[];
extern const char kAcceleratedVideoDisabled[];
extern const char kAcceledated2dCanvasDisabled[];
extern const char kAcceleratedPaintingDisabled[];
extern const char kAcceleratedFiltersDisabled[];
extern const char kAcceleratedPluginsDisabled[];
extern const char kDeveloperToolsDisabled[];
extern const char kFullscreenEnabled[];
// Other attributes.
extern const char kProxyType[];
extern const char kProxyType_Direct[];
extern const char kProxyType_Named[];
extern const char kProxyType_Pac[];
extern const char kProxyConfig[];
} // namespace cefclient
#endif // CEF_TESTS_CEFCLIENT_CEFCLIENT_SWITCHES_H_

View File

@@ -0,0 +1,340 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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 "client_handler.h"
#include <stdio.h>
#include <sstream>
#include <string>
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "cefclient.h"
#include "string_util.h"
#include "native_handler.h"
ClientHandler::ClientHandler()
: m_MainHwnd(NULL),
m_BrowserHwnd(NULL),
m_EditHwnd(NULL),
m_BackHwnd(NULL),
m_ForwardHwnd(NULL),
m_StopHwnd(NULL),
m_ReloadHwnd(NULL),
m_bFormElementHasFocus(false) {
}
ClientHandler::~ClientHandler() {
}
void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
REQUIRE_UI_THREAD();
AutoLock lock_scope(this);
if (!m_Browser.get()) {
// We need to keep the main child window, but not popup windows
m_Browser = browser;
m_BrowserHwnd = browser->GetWindowHandle();
}
}
bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
REQUIRE_UI_THREAD();
if (m_BrowserHwnd == browser->GetWindowHandle()) {
// Since the main window contains the browser window, we need to close
// the parent window instead of the browser window.
CloseMainWindow();
// Return true here so that we can skip closing the browser window
// in this pass. (It will be destroyed due to the call to close
// the parent above.)
return true;
}
// A popup browser window is not contained in another window, so we can let
// these windows close by themselves.
return false;
}
void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
REQUIRE_UI_THREAD();
if (m_BrowserHwnd == browser->GetWindowHandle()) {
// Free the browser pointer so that the browser can be destroyed
m_Browser = NULL;
}
}
void ClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame) {
REQUIRE_UI_THREAD();
if (m_BrowserHwnd == browser->GetWindowHandle() && frame->IsMain()) {
// We've just started loading a page
SetLoading(true);
CefRefPtr<CefV8Context> context = frame->GetV8Context();
CefRefPtr<CefV8Value> global = context->GetGlobal();
context->Enter();
CefRefPtr<CefV8Value> windowNumber = CefV8Value::CreateInt(0);
global->SetValue("$windowNumber", windowNumber, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<NativeHandler> nativeHandler = new NativeHandler();
global->SetValue("$native", nativeHandler->object, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> atom = CefV8Value::CreateObject(NULL, NULL);
global->SetValue("atom", atom, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> loadPath = CefV8Value::CreateString("/home/kevin/repositories/atom");
atom->SetValue("loadPath", loadPath, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> bootstrapScript = CefV8Value::CreateString("window-bootstrap");
global->SetValue("$bootstrapScript", bootstrapScript, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> pathToOpen = CefV8Value::CreateString("/home/kevin/repositories/atom/index.html");
global->SetValue("$pathToOpen", pathToOpen, V8_PROPERTY_ATTRIBUTE_NONE);
context->Exit();
}
}
void ClientHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) {
REQUIRE_UI_THREAD();
if (m_BrowserHwnd == browser->GetWindowHandle() && frame->IsMain()) {
// We've just finished loading a page
SetLoading(false);
CefRefPtr<CefDOMVisitor> visitor = GetDOMVisitor(frame->GetURL());
if (visitor.get())
frame->VisitDOM(visitor);
}
}
bool ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& failedUrl,
CefString& errorText) {
REQUIRE_UI_THREAD();
if (errorCode == ERR_CACHE_MISS) {
// Usually caused by navigating to a page with POST data via back or
// forward buttons.
errorText = "<html><head><title>Expired Form Data</title></head>"
"<body><h1>Expired Form Data</h1>"
"<h2>Your form request has expired. "
"Click reload to re-submit the form data.</h2></body>"
"</html>";
} else {
// All other messages.
std::stringstream ss;
ss << "<html><head><title>Load Failed</title></head>"
"<body><h1>Load Failed</h1>"
"<h2>Load of URL " << std::string(failedUrl) <<
" failed with error code " << static_cast<int>(errorCode) <<
".</h2></body>"
"</html>";
errorText = ss.str();
}
return false;
}
void ClientHandler::OnNavStateChange(CefRefPtr<CefBrowser> browser,
bool canGoBack,
bool canGoForward) {
REQUIRE_UI_THREAD();
SetNavState(canGoBack, canGoForward);
}
bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
const CefString& message,
const CefString& source,
int line) {
REQUIRE_UI_THREAD();
bool first_message;
std::string logFile;
{
AutoLock lock_scope(this);
first_message = m_LogFile.empty();
if (first_message) {
std::stringstream ss;
ss << AppGetWorkingDirectory();
#if defined(OS_WIN)
ss << "\\";
#else
ss << "/";
#endif
ss << "console.log";
m_LogFile = ss.str();
}
logFile = m_LogFile;
}
FILE* file = fopen(logFile.c_str(), "a");
if (file) {
std::stringstream ss;
ss << "Message: " << std::string(message) << "\r\nSource: " <<
std::string(source) << "\r\nLine: " << line <<
"\r\n-----------------------\r\n";
fputs(ss.str().c_str(), file);
fclose(file);
if (first_message)
SendNotification(NOTIFY_CONSOLE_MESSAGE);
}
return false;
}
void ClientHandler::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefDOMNode> node) {
REQUIRE_UI_THREAD();
// Set to true if a form element has focus.
m_bFormElementHasFocus = (node.get() && node->IsFormControlElement());
}
bool ClientHandler::OnKeyEvent(CefRefPtr<CefBrowser> browser,
KeyEventType type,
int code,
int modifiers,
bool isSystemKey,
bool isAfterJavaScript) {
REQUIRE_UI_THREAD();
if (isAfterJavaScript && !m_bFormElementHasFocus && code == 0x20) {
// Special handling for the space character if a form element does not have
// focus.
if (type == KEYEVENT_RAWKEYDOWN) {
browser->GetMainFrame()->ExecuteJavaScript(
"alert('You pressed the space bar!');", "", 0);
}
return true;
}
return false;
}
bool ClientHandler::GetPrintHeaderFooter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefPrintInfo& printInfo,
const CefString& url,
const CefString& title,
int currentPage,
int maxPages,
CefString& topLeft,
CefString& topCenter,
CefString& topRight,
CefString& bottomLeft,
CefString& bottomCenter,
CefString& bottomRight) {
REQUIRE_UI_THREAD();
// Place the page title at top left
topLeft = title;
// Place the page URL at top right
topRight = url;
// Place "Page X of Y" at bottom center
std::stringstream strstream;
strstream << "Page " << currentPage << " of " << maxPages;
bottomCenter = strstream.str();
return false;
}
void ClientHandler::OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) {
REQUIRE_UI_THREAD();
}
bool ClientHandler::OnDragStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
DragOperationsMask mask) {
REQUIRE_UI_THREAD();
// Forbid dragging of image files.
if (dragData->IsFile()) {
std::string fileExt = dragData->GetFileExtension();
if (fileExt == ".png" || fileExt == ".jpg" || fileExt == ".gif")
return true;
}
return false;
}
bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
DragOperationsMask mask) {
REQUIRE_UI_THREAD();
// Forbid dragging of link URLs.
if (dragData->IsLink())
return true;
return false;
}
bool ClientHandler::OnBeforeScriptExtensionLoad(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& extensionName) {
return false;
}
void ClientHandler::SetMainHwnd(CefWindowHandle hwnd) {
AutoLock lock_scope(this);
m_MainHwnd = hwnd;
}
void ClientHandler::SetEditHwnd(CefWindowHandle hwnd) {
AutoLock lock_scope(this);
m_EditHwnd = hwnd;
}
void ClientHandler::SetButtonHwnds(CefWindowHandle backHwnd,
CefWindowHandle forwardHwnd,
CefWindowHandle reloadHwnd,
CefWindowHandle stopHwnd) {
AutoLock lock_scope(this);
m_BackHwnd = backHwnd;
m_ForwardHwnd = forwardHwnd;
m_ReloadHwnd = reloadHwnd;
m_StopHwnd = stopHwnd;
}
std::string ClientHandler::GetLogFile() {
AutoLock lock_scope(this);
return m_LogFile;
}
void ClientHandler::AddDOMVisitor(const std::string& path,
CefRefPtr<CefDOMVisitor> visitor) {
AutoLock lock_scope(this);
DOMVisitorMap::iterator it = m_DOMVisitors.find(path);
if (it == m_DOMVisitors.end())
m_DOMVisitors.insert(std::make_pair(path, visitor));
else
it->second = visitor;
}
CefRefPtr<CefDOMVisitor> ClientHandler::GetDOMVisitor(const std::string& path) {
AutoLock lock_scope(this);
DOMVisitorMap::iterator it = m_DOMVisitors.find(path);
if (it != m_DOMVisitors.end())
return it->second;
return NULL;
}

208
Atom-Linux/client_handler.h Normal file
View File

@@ -0,0 +1,208 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_
#define CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_
#pragma once
#include <map>
#include <string>
#include "include/cef_client.h"
#include "util.h"
// Define this value to redirect all popup URLs to the main application browser
// window.
// #define TEST_REDIRECT_POPUP_URLS
// ClientHandler implementation.
class ClientHandler : public CefClient,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefDisplayHandler,
public CefFocusHandler,
public CefKeyboardHandler,
public CefPrintHandler,
public CefV8ContextHandler,
public CefDragHandler,
public CefPermissionHandler {
public:
ClientHandler();
virtual ~ClientHandler();
// CefClient methods
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefFocusHandler> GetFocusHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefPrintHandler> GetPrintHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefV8ContextHandler> GetV8ContextHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefDragHandler> GetDragHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefPermissionHandler> GetPermissionHandler() OVERRIDE {
return this;
}
// CefLifeSpanHandler methods
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> parentBrowser,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
const CefString& url,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) OVERRIDE;
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefLoadHandler methods
virtual void OnLoadStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame) OVERRIDE;
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) OVERRIDE;
virtual bool OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& failedUrl,
CefString& errorText) OVERRIDE;
// CefDisplayHandler methods
virtual void OnNavStateChange(CefRefPtr<CefBrowser> browser,
bool canGoBack,
bool canGoForward) OVERRIDE;
virtual void OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& url) OVERRIDE;
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
const CefString& title) OVERRIDE;
virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
const CefString& message,
const CefString& source,
int line) OVERRIDE;
// CefFocusHandler methods.
virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefDOMNode> node) OVERRIDE;
// CefKeyboardHandler methods.
virtual bool OnKeyEvent(CefRefPtr<CefBrowser> browser,
KeyEventType type,
int code,
int modifiers,
bool isSystemKey,
bool isAfterJavaScript) OVERRIDE;
// CefPrintHandler methods.
virtual bool GetPrintHeaderFooter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefPrintInfo& printInfo,
const CefString& url,
const CefString& title,
int currentPage,
int maxPages,
CefString& topLeft,
CefString& topCenter,
CefString& topRight,
CefString& bottomLeft,
CefString& bottomCenter,
CefString& bottomRight) OVERRIDE;
// CefV8ContextHandler methods
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
// CefDragHandler methods.
virtual bool OnDragStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
DragOperationsMask mask) OVERRIDE;
virtual bool OnDragEnter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
DragOperationsMask mask) OVERRIDE;
// CefPermissionHandler methods.
virtual bool OnBeforeScriptExtensionLoad(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& extensionName) OVERRIDE;
void SetMainHwnd(CefWindowHandle hwnd);
CefWindowHandle GetMainHwnd() { return m_MainHwnd; }
void SetEditHwnd(CefWindowHandle hwnd);
void SetButtonHwnds(CefWindowHandle backHwnd,
CefWindowHandle forwardHwnd,
CefWindowHandle reloadHwnd,
CefWindowHandle stopHwnd);
CefRefPtr<CefBrowser> GetBrowser() { return m_Browser; }
CefWindowHandle GetBrowserHwnd() { return m_BrowserHwnd; }
std::string GetLogFile();
// DOM visitors will be called after the associated path is loaded.
void AddDOMVisitor(const std::string& path, CefRefPtr<CefDOMVisitor> visitor);
CefRefPtr<CefDOMVisitor> GetDOMVisitor(const std::string& path);
enum NotificationType {
NOTIFY_CONSOLE_MESSAGE
};
void SendNotification(NotificationType type);
void CloseMainWindow();
protected:
void SetLoading(bool isLoading);
void SetNavState(bool canGoBack, bool canGoForward);
// The child browser window
CefRefPtr<CefBrowser> m_Browser;
// The main frame window handle
CefWindowHandle m_MainHwnd;
// The child browser window handle
CefWindowHandle m_BrowserHwnd;
// The edit window handle
CefWindowHandle m_EditHwnd;
// The button window handles
CefWindowHandle m_BackHwnd;
CefWindowHandle m_ForwardHwnd;
CefWindowHandle m_StopHwnd;
CefWindowHandle m_ReloadHwnd;
// Support for logging.
std::string m_LogFile;
// Support for DOM visitors.
typedef std::map<std::string, CefRefPtr<CefDOMVisitor> > DOMVisitorMap;
DOMVisitorMap m_DOMVisitors;
// True if a form element currently has focus
bool m_bFormElementHasFocus;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(ClientHandler);
// Include the default locking implementation.
IMPLEMENT_LOCKING(ClientHandler);
};
#endif // CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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 <gtk/gtk.h>
#include <string>
#include "client_handler.h"
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "string_util.h"
// ClientHandler::ClientLifeSpanHandler implementation
bool ClientHandler::OnBeforePopup(CefRefPtr<CefBrowser> parentBrowser,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
const CefString& url,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
REQUIRE_UI_THREAD();
return false;
}
void ClientHandler::OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& url) {
REQUIRE_UI_THREAD();
if (m_BrowserHwnd == browser->GetWindowHandle() && frame->IsMain()) {
// Set the edit window text
std::string urlStr(url);
gtk_entry_set_text(GTK_ENTRY(m_EditHwnd), urlStr.c_str());
}
}
void ClientHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
const CefString& title) {
REQUIRE_UI_THREAD();
GtkWidget* window =
gtk_widget_get_ancestor(GTK_WIDGET(browser->GetWindowHandle()),
GTK_TYPE_WINDOW);
std::string titleStr(title);
gtk_window_set_title(GTK_WINDOW(window), titleStr.c_str());
}
void ClientHandler::SendNotification(NotificationType type) {
// TODO(port): Implement this method.
}
void ClientHandler::SetLoading(bool isLoading) {
if (isLoading)
gtk_widget_set_sensitive(GTK_WIDGET(m_StopHwnd), true);
else
gtk_widget_set_sensitive(GTK_WIDGET(m_StopHwnd), false);
}
void ClientHandler::SetNavState(bool canGoBack, bool canGoForward) {
if (canGoBack)
gtk_widget_set_sensitive(GTK_WIDGET(m_BackHwnd), true);
else
gtk_widget_set_sensitive(GTK_WIDGET(m_BackHwnd), false);
if (canGoForward)
gtk_widget_set_sensitive(GTK_WIDGET(m_ForwardHwnd), true);
else
gtk_widget_set_sensitive(GTK_WIDGET(m_ForwardHwnd), false);
}
void ClientHandler::CloseMainWindow() {
// TODO(port): Close main window.
}

View File

@@ -0,0 +1,138 @@
#include "native_handler.h"
#include "include/cef_base.h"
#include "client_handler.h"
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <vector>
using namespace std;
NativeHandler::NativeHandler() :
CefV8Handler() {
object = CefV8Value::CreateObject(NULL, NULL);
const char *functionNames[] = { "exists", "alert", "read", "write",
"absolute", "list", "isFile", "isDirectory", "remove", "asyncList",
"open", "openDialog", "quit", "writeToPasteboard",
"readFromPasteboard", "showDevTools", "newWindow", "saveDialog",
"exit", "watchPath", "unwatchPath", "makeDirectory", "move",
"moveToTrash" };
int arrayLength = sizeof(functionNames) / sizeof(const char *);
for (int i = 0; i < arrayLength; i++) {
const char *functionName = functionNames[i];
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(
functionName, this);
object->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
}
}
void Exists(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
struct stat sbuf;
int result = stat(path.c_str(), &sbuf);
retval = CefV8Value::CreateBool(result == 0);
}
void Read(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0)
return;
char buffer[8192];
int r;
string value;
while ((r = read(fd, buffer, sizeof buffer)) > 0)
value.append(buffer, 0, r);
close(fd);
retval = CefV8Value::CreateString(value);
}
void Absolute(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
if (path[0] == '~') {
string resolved = getenv("HOME");
resolved.append(path.substr(1));
retval = CefV8Value::CreateString(resolved);
} else
retval = CefV8Value::CreateString(path);
}
void List(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
DIR *dir;
if ((dir = opendir(path.c_str())) == NULL)
return;
vector < string > paths;
dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
paths.push_back(entry->d_name);
}
closedir(dir);
retval = CefV8Value::CreateArray();
for (uint i = 0; i < paths.size(); i++)
retval->SetValue(i, CefV8Value::CreateString(path + "/" + paths[i]));
}
void IsFile(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
struct stat sbuf;
int result = stat(path.c_str(), &sbuf);
retval = CefV8Value::CreateBool(result == 0 && S_ISREG(sbuf.st_mode));
}
void IsDirectory(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
struct stat sbuf;
int result = stat(path.c_str(), &sbuf);
retval = CefV8Value::CreateBool(result == 0 && S_ISDIR(sbuf.st_mode));
}
bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
if (name == "exists")
Exists(name, object, arguments, retval, exception);
else if (name == "read")
Read(name, object, arguments, retval, exception);
else if (name == "absolute")
Absolute(name, object, arguments, retval, exception);
else if (name == "list")
List(name, object, arguments, retval, exception);
else if (name == "isFile")
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
cout << "Unhandled -> " + name.ToString() << " : "
<< arguments[0]->GetStringValue().ToString() << endl;
return true;
}

View File

@@ -0,0 +1,22 @@
#ifndef CEF_TESTS_CEFCLIENT_NATIVE_HANDLER_H_
#define CEF_TESTS_CEFCLIENT_NATIVE_HANDLER_H_
#include "include/cef_base.h"
#include "include/cef_v8.h"
class NativeHandler : public CefV8Handler {
public:
NativeHandler();
CefRefPtr<CefV8Value> object;
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception);
IMPLEMENT_REFCOUNTING(NativeHandler);
};
#endif

BIN
Atom-Linux/obj/cef/libcef.so Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,74 @@
// Copyright (c) 2010 The Chromium Embedded Framework 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 "string_util.h"
#include <sstream>
#include <string>
#include "include/cef_request.h"
void DumpRequestContents(CefRefPtr<CefRequest> request, std::string& str) {
std::stringstream ss;
ss << "URL: " << std::string(request->GetURL());
ss << "\nMethod: " << std::string(request->GetMethod());
CefRequest::HeaderMap headerMap;
request->GetHeaderMap(headerMap);
if (headerMap.size() > 0) {
ss << "\nHeaders:";
CefRequest::HeaderMap::const_iterator it = headerMap.begin();
for (; it != headerMap.end(); ++it) {
ss << "\n\t" << std::string((*it).first) << ": " <<
std::string((*it).second);
}
}
CefRefPtr<CefPostData> postData = request->GetPostData();
if (postData.get()) {
CefPostData::ElementVector elements;
postData->GetElements(elements);
if (elements.size() > 0) {
ss << "\nPost Data:";
CefRefPtr<CefPostDataElement> element;
CefPostData::ElementVector::const_iterator it = elements.begin();
for (; it != elements.end(); ++it) {
element = (*it);
if (element->GetType() == PDE_TYPE_BYTES) {
// the element is composed of bytes
ss << "\n\tBytes: ";
if (element->GetBytesCount() == 0) {
ss << "(empty)";
} else {
// retrieve the data.
size_t size = element->GetBytesCount();
char* bytes = new char[size];
element->GetBytes(size, bytes);
ss << std::string(bytes, size);
delete [] bytes;
}
} else if (element->GetType() == PDE_TYPE_FILE) {
ss << "\n\tFile: " << std::string(element->GetFile());
}
}
}
}
str = ss.str();
}
std::string StringReplace(const std::string& str, const std::string& from,
const std::string& to) {
std::string result = str;
std::string::size_type pos = 0;
std::string::size_type from_len = from.length();
std::string::size_type to_len = to.length();
do {
pos = result.find(from, pos);
if (pos != std::string::npos) {
result.replace(pos, from_len, to);
pos += to_len;
}
} while (pos != std::string::npos);
return result;
}

21
Atom-Linux/string_util.h Normal file
View File

@@ -0,0 +1,21 @@
// Copyright (c) 2010 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_STRING_UTIL_H_
#define CEF_TESTS_CEFCLIENT_STRING_UTIL_H_
#pragma once
#include <string>
#include "include/cef_base.h"
class CefRequest;
// Dump the contents of the request into a string.
void DumpRequestContents(CefRefPtr<CefRequest> request, std::string& str);
// Replace all instances of |from| with |to| in |str|.
std::string StringReplace(const std::string& str, const std::string& from,
const std::string& to);
#endif // CEF_TESTS_CEFCLIENT_STRING_UTIL_H_

37
Atom-Linux/util.h Normal file
View File

@@ -0,0 +1,37 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_UTIL_H_
#define CEF_TESTS_CEFCLIENT_UTIL_H_
#pragma once
#include "include/cef_task.h"
#if defined(OS_WIN)
#include <windows.h> // NOLINT(build/include_order)
#ifndef NDEBUG
#define ASSERT(condition) if (!(condition)) { DebugBreak(); }
#else
#define ASSERT(condition) ((void)0)
#endif
#else // !OS_WIN
#include <assert.h> // NOLINT(build/include_order)
#ifndef NDEBUG
#define ASSERT(condition) if (!(condition)) { assert(false); }
#else
#define ASSERT(condition) ((void)0)
#endif
#endif // !OS_WIN
#define REQUIRE_UI_THREAD() ASSERT(CefCurrentlyOn(TID_UI));
#define REQUIRE_IO_THREAD() ASSERT(CefCurrentlyOn(TID_IO));
#define REQUIRE_FILE_THREAD() ASSERT(CefCurrentlyOn(TID_FILE));
#endif // CEF_TESTS_CEFCLIENT_UTIL_H_