GitHub Viewer
// Copyright (c) 2012-2014 The CEF Python authors. All rights reserved.
// License: New BSD License.
// Website: http://code.google.com/p/cefpython/
// NOTE: clienthandler code is running only in the BROWSER PROCESS.
// cefpythonapp code is running in both BROWSER PROCESS and subprocess
// (see the subprocess/ directory).
#include "client_handler.h"
#include "cefpython_public_api.h"
#include "DebugLog.h"
#include "LOG_DEBUG.h"
#if defined(OS_WIN)
#include
#pragma comment(lib, "Shell32.lib")
#include "dpi_aware.h"
#elif defined(OS_LINUX)
#include
#include
#endif
// ----------------------------------------------------------------------------
// Linux equivalent of ShellExecute
// ----------------------------------------------------------------------------
#if defined(OS_LINUX)
void OpenInExternalBrowser(const std::string& url)
{
if (url.empty()) {
DebugLog("Browser: OpenInExternalBrowser() FAILED: url is empty");
return;
}
std::string msg = "Browser: OpenInExternalBrowser(): url=";
msg.append(url.c_str());
DebugLog(msg.c_str());
// xdg-open is a desktop-independent tool for running
// default applications. Installed by default on Ubuntu.
// xdg-open process is running in the backround until
// cefpython app closes.
std::string prog = "xdg-open";
// Using system() opens up for bugs and exploits, not
// recommended.
// Fork yourself and run in parallel, do not block the
// current proces.
char *args[3];
args[0] = (char*) prog.c_str();
args[1] = (char*) url.c_str();
args[2] = 0;
pid_t pid = fork();
if (!pid) {
execvp(prog.c_str(), args);
}
}
#endif
// ----------------------------------------------------------------------------
// CefClient
// ----------------------------------------------------------------------------
bool ClientHandler::OnProcessMessageReceived(CefRefPtr browser,
CefProcessId source_process,
CefRefPtr message) {
if (source_process != PID_RENDERER) {
return false;
}
std::string messageName = message->GetName().ToString();
std::string logMessage = "Browser: OnProcessMessageReceived(): ";
logMessage.append(messageName.c_str());
DebugLog(logMessage.c_str());
if (messageName == "OnContextCreated") {
CefRefPtr arguments = message->GetArgumentList();
if (arguments->GetSize() == 1 && arguments->GetType(0) == VTYPE_INT) {
int64 frameId = arguments->GetInt(0);
CefRefPtr frame = browser->GetFrame(frameId);
V8ContextHandler_OnContextCreated(browser, frame);
return true;
} else {
DebugLog("Browser: OnProcessMessageReceived(): invalid arguments" \
", messageName = OnContextCreated");
return false;
}
} else if (messageName == "OnContextReleased") {
CefRefPtr arguments = message->GetArgumentList();
if (arguments->GetSize() == 2 \
&& arguments->GetType(0) == VTYPE_INT \
&& arguments->GetType(1) == VTYPE_INT) {
int browserId = arguments->GetInt(0);
int64 frameId = arguments->GetInt(1);
V8ContextHandler_OnContextReleased(browserId, frameId);
return true;
} else {
DebugLog("Browser: OnProcessMessageReceived(): invalid arguments" \
", messageName = OnContextReleased");
return false;
}
} else if (messageName == "V8FunctionHandler::Execute") {
CefRefPtr arguments = message->GetArgumentList();
if (arguments->GetSize() == 3
&& arguments->GetType(0) == VTYPE_INT // frameId
&& arguments->GetType(1) == VTYPE_STRING // functionName
&& arguments->GetType(2) == VTYPE_LIST) { // functionArguments
int64 frameId = arguments->GetInt(0);
CefString functionName = arguments->GetString(1);
CefRefPtr functionArguments = arguments->GetList(2);
CefRefPtr frame = browser->GetFrame(frameId);
V8FunctionHandler_Execute(browser, frame, functionName, functionArguments);
return true;
} else {
DebugLog("Browser: OnProcessMessageReceived(): invalid arguments" \
", messageName = V8FunctionHandler::Execute");
return false;
}
} else if (messageName == "ExecutePythonCallback") {
CefRefPtr arguments = message->GetArgumentList();
if (arguments->GetSize() == 2
&& arguments->GetType(0) == VTYPE_INT // callbackId
&& arguments->GetType(1) == VTYPE_LIST) { // functionArguments
int callbackId = arguments->GetInt(0);
CefRefPtr functionArguments = arguments->GetList(1);
ExecutePythonCallback(browser, callbackId, functionArguments);
return true;
} else {
DebugLog("Browser: OnProcessMessageReceived(): invalid arguments" \
", messageName = ExecutePythonCallback");
return false;
}
} else if (messageName == "RemovePythonCallbacksForFrame") {
CefRefPtr arguments = message->GetArgumentList();
if (arguments->GetSize() == 1 && arguments->GetType(0) == VTYPE_INT) {
int frameId = arguments->GetInt(0);
RemovePythonCallbacksForFrame(frameId);
return true;
} else {
DebugLog("Browser: OnProcessMessageReceived(): invalid arguments" \
", messageName = ExecutePythonCallback");
return false;
}
}
return false;
}
// ----------------------------------------------------------------------------
// CefLifeSpanHandler
// ----------------------------------------------------------------------------
bool ClientHandler::OnBeforePopup(CefRefPtr browser,
CefRefPtr frame,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr& client,
CefBrowserSettings& settings,
bool* no_javascript_access) {
REQUIRE_IO_THREAD();
// Note: passing popupFeatures is not yet supported.
const int popupFeaturesNotImpl = 0;
return LifespanHandler_OnBeforePopup(browser, frame, target_url,
target_frame_name, target_disposition, user_gesture,
popupFeaturesNotImpl, windowInfo, client, settings,
no_javascript_access);
}
void ClientHandler::OnAfterCreated(CefRefPtr browser) {
REQUIRE_UI_THREAD();
#if defined(OS_WIN)
// High DPI support.
CefString auto_zooming = ApplicationSettings_GetString("auto_zooming");
if (!auto_zooming.empty()) {
LOG_DEBUG Continue(suggested_name, true);
} else {
DebugLog("Browser: Tried to download file, but downloads are disabled");
}
}
void ClientHandler::OnDownloadUpdated(
CefRefPtr browser,
CefRefPtr download_item,
CefRefPtr callback) {
REQUIRE_UI_THREAD();
if (download_item->IsComplete()) {
std::string msg = "Browser: Download completed, saved to: ";
msg.append(download_item->GetFullPath().ToString().c_str());
DebugLog(msg.c_str());
} else if (download_item->IsCanceled()) {
DebugLog("Browser: Download was cancelled");
}
}
// ----------------------------------------------------------------------------
// CefContextMenuHandler
// ----------------------------------------------------------------------------
#define _MENU_ID_DEVTOOLS MENU_ID_USER_FIRST + 1
#define _MENU_ID_RELOAD_PAGE MENU_ID_USER_FIRST + 2
#define _MENU_ID_OPEN_PAGE_IN_EXTERNAL_BROWSER MENU_ID_USER_FIRST + 3
#define _MENU_ID_OPEN_FRAME_IN_EXTERNAL_BROWSER MENU_ID_USER_FIRST + 4
void ClientHandler::OnBeforeContextMenu(CefRefPtr browser,
CefRefPtr frame,
CefRefPtr params,
CefRefPtr model) {
bool enabled = ApplicationSettings_GetBoolFromDict(\
"context_menu", "enabled");
bool navigation = ApplicationSettings_GetBoolFromDict(\
"context_menu", "navigation");
bool print = ApplicationSettings_GetBoolFromDict(\
"context_menu", "print");
bool view_source = ApplicationSettings_GetBoolFromDict(\
"context_menu", "view_source");
bool external_browser = ApplicationSettings_GetBoolFromDict(\
"context_menu", "external_browser");
bool devtools = ApplicationSettings_GetBoolFromDict(\
"context_menu", "devtools");
if (!enabled) {
model->Clear();
return;
}
if (!navigation) {
model->Remove(MENU_ID_BACK);
model->Remove(MENU_ID_FORWARD);
// Remove separator
model->RemoveAt(0);
}
if (!print) {
model->Remove(MENU_ID_PRINT);
}
if (!view_source) {
model->Remove(MENU_ID_VIEW_SOURCE);
}
if (!params->IsEditable() && params->GetSelectionText().empty()
&& (params->GetPageUrl().length()
|| params->GetFrameUrl().length())) {
if (external_browser) {
model->AddItem(_MENU_ID_OPEN_PAGE_IN_EXTERNAL_BROWSER,
"Open in external browser");
if (params->GetFrameUrl().length()
&& params->GetPageUrl() != params->GetFrameUrl()) {
model->AddItem(_MENU_ID_OPEN_FRAME_IN_EXTERNAL_BROWSER,
"Open frame in external browser");
}
}
if (navigation) {
model->InsertItemAt(2, _MENU_ID_RELOAD_PAGE, "Reload");
}
if (devtools) {
model->AddSeparator();
model->AddItem(_MENU_ID_DEVTOOLS, "Developer Tools");
}
}
}
bool ClientHandler::OnContextMenuCommand(CefRefPtr browser,
CefRefPtr frame,
CefRefPtr params,
int command_id,
EventFlags event_flags) {
if (command_id == _MENU_ID_OPEN_PAGE_IN_EXTERNAL_BROWSER) {
#if defined(OS_WIN)
ShellExecuteA(0, "open", params->GetPageUrl().ToString().c_str(),
0, 0, SW_SHOWNORMAL);
#elif defined(OS_LINUX)
OpenInExternalBrowser(params->GetPageUrl().ToString());
#endif
return true;
} else if (command_id == _MENU_ID_OPEN_FRAME_IN_EXTERNAL_BROWSER) {
#if defined(OS_WIN)
ShellExecuteA(0, "open", params->GetFrameUrl().ToString().c_str(),
0, 0, SW_SHOWNORMAL);
#elif defined(OS_LINUX)
OpenInExternalBrowser(params->GetFrameUrl().ToString());
#endif
return true;
} else if (command_id == _MENU_ID_RELOAD_PAGE) {
browser->ReloadIgnoreCache();
return true;
} else if (command_id == _MENU_ID_DEVTOOLS) {
PyBrowser_ShowDevTools(browser);
return true;
}
return false;
}
void ClientHandler::OnContextMenuDismissed(CefRefPtr browser,
CefRefPtr frame) {
}