bool ClientApp::OnProcessMessageReceived( CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { ASSERT(source_process == PID_BROWSER); bool handled = false; RenderDelegateSet::iterator it = render_delegates_.begin(); for (; it != render_delegates_.end() && !handled; ++it) { handled = (*it)->OnProcessMessageReceived(this, browser, source_process, message); } if (handled) return true; // Execute the registered JavaScript callback if any. if (!callback_map_.empty()) { CefString message_name = message->GetName(); CallbackMap::const_iterator it = callback_map_.find( std::make_pair(message_name.ToString(), browser->GetIdentifier())); if (it != callback_map_.end()) { // Keep a local reference to the objects. The callback may remove itself // from the callback map. CefRefPtr<CefV8Context> context = it->second.first; CefRefPtr<CefV8Value> callback = it->second.second; // Enter the context. context->Enter(); CefV8ValueList arguments; // First argument is the message name. arguments.push_back(CefV8Value::CreateString(message_name)); // Second argument is the list of message arguments. CefRefPtr<CefListValue> list = message->GetArgumentList(); CefRefPtr<CefV8Value> args = CefV8Value::CreateArray(static_cast<int>(list->GetSize())); SetList(list, args); arguments.push_back(args); // Execute the callback. CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(NULL, arguments); if (retval.get()) { if (retval->IsBool()) handled = retval->GetBoolValue(); } // Exit the context. context->Exit(); } } return handled; }
// Simple function for formatted output of a V8 value. void PrintValue(CefRefPtr<CefV8Value> value, std::stringstream &stream, int indent) { std::stringstream indent_stream; for(int i = 0; i < indent; ++i) indent_stream << " "; std::string indent_str = indent_stream.str(); if(value->IsUndefined()) stream << "(undefined)"; else if(value->IsNull()) stream << "(null)"; else if(value->IsBool()) stream << "(bool) " << (value->GetBoolValue() ? "true" : "false"); else if(value->IsInt()) stream << "(int) " << value->GetIntValue(); else if(value->IsDouble()) stream << "(double) " << value->GetDoubleValue(); else if(value->IsString()) stream << "(string) " << std::string(value->GetStringValue()); else if(value->IsFunction()) stream << "(function) " << std::string(value->GetFunctionName()); else if(value->IsArray()) { stream << "(array) ["; int len = value->GetArrayLength(); for(int i = 0; i < len; ++i) { stream << "\n " << indent_str.c_str() << i << " = "; PrintValue(value->GetValue(i), stream, indent+1); } stream << "\n" << indent_str.c_str() << "]"; } else if(value->IsObject()) { stream << "(object) ["; std::vector<CefString> keys; if(value->GetKeys(keys)) { for(size_t i = 0; i < keys.size(); ++i) { stream << "\n " << indent_str.c_str() << keys[i].c_str() << " = "; PrintValue(value->GetValue(keys[i]), stream, indent+1); } } stream << "\n" << indent_str.c_str() << "]"; } }
bool ClientApp::OnProcessMessageReceived( CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { ASSERT(source_process == PID_BROWSER); bool handled = false; // Execute delegate callbacks. RenderDelegateSet::iterator it = render_delegates_.begin(); for (; it != render_delegates_.end() && !handled; ++it) { handled = (*it)->OnProcessMessageReceived(this, browser, source_process, message); } if (!handled) { if (message->GetName() == "invokeCallback") { // This is called by the appshell extension handler to invoke the asynchronous // callback function CefRefPtr<CefListValue> messageArgs = message->GetArgumentList(); int32 callbackId = messageArgs->GetInt(0); CefRefPtr<CefV8Context> context = callback_map_[callbackId].first; CefRefPtr<CefV8Value> callbackFunction = callback_map_[callbackId].second; CefV8ValueList arguments; context->Enter(); // Sanity check to make sure the context is still attched to a browser. // Async callbacks could be initiated after a browser instance has been deleted, // which can lead to bad things. If the browser instance has been deleted, don't // invoke this callback. if (context->GetBrowser()) { for (size_t i = 1; i < messageArgs->GetSize(); i++) { arguments.push_back(ListValueToV8Value(messageArgs, i)); } callbackFunction->ExecuteFunction(NULL, arguments); } context->Exit(); callback_map_.erase(callbackId); } else if (message->GetName() == "executeCommand") { // This is called by the browser process to execute a command via JavaScript // // The first argument is the command name. This is required. // The second argument is a message id. This is optional. If set, a response // message will be sent back to the browser process. CefRefPtr<CefListValue> messageArgs = message->GetArgumentList(); CefString commandName = messageArgs->GetString(0); int messageId = messageArgs->GetSize() > 1 ? messageArgs->GetInt(1) : -1; bool handled = false; StContextScope ctx(browser->GetMainFrame()->GetV8Context()); CefRefPtr<CefV8Value> global = ctx.GetContext()->GetGlobal(); if (global->HasValue("brackets")) { CefRefPtr<CefV8Value> brackets = global->GetValue("brackets"); if (brackets->HasValue("shellAPI")) { CefRefPtr<CefV8Value> shellAPI = brackets->GetValue("shellAPI"); if (shellAPI->HasValue("executeCommand")) { CefRefPtr<CefV8Value> executeCommand = shellAPI->GetValue("executeCommand"); if (executeCommand->IsFunction()) { CefRefPtr<CefV8Value> retval; CefV8ValueList args; args.push_back(CefV8Value::CreateString(commandName)); retval = executeCommand->ExecuteFunction(global, args); if (retval) { handled = retval->GetBoolValue(); } } } } } // Return a message saying whether or not the command was handled if (messageId != -1) { CefRefPtr<CefProcessMessage> result = CefProcessMessage::Create("executeCommandCallback"); result->GetArgumentList()->SetInt(0, messageId); result->GetArgumentList()->SetBool(1, handled); browser->SendProcessMessage(PID_BROWSER, result); } } } return handled; }
void V8ValueAppendToCefListValue(CefRefPtr<CefV8Value> v8Value, CefRefPtr<CefListValue> listValue, int nestingLevel) { if (!v8Value->IsValid()) { DebugLog("V8ValueAppendToCefListValue(): IsValid() FAILED"); return; } if (nestingLevel > 8) { DebugLog("V8ValueAppendToCefListValue(): WARNING: max nesting level (8) " \ "exceeded"); return; } if (v8Value->IsUndefined() || v8Value->IsNull()) { listValue->SetNull((int)listValue->GetSize()); } else if (v8Value->IsBool()) { listValue->SetBool((int)listValue->GetSize(), v8Value->GetBoolValue()); } else if (v8Value->IsInt()) { listValue->SetInt((int)listValue->GetSize(), v8Value->GetIntValue()); } else if (v8Value->IsUInt()) { uint32 uint32_value = v8Value->GetUIntValue(); CefRefPtr<CefBinaryValue> binaryValue = CefBinaryValue::Create( &uint32_value, sizeof(uint32_value)); listValue->SetBinary((int)listValue->GetSize(), binaryValue); } else if (v8Value->IsDouble()) { listValue->SetDouble((int)listValue->GetSize(), v8Value->GetDoubleValue()); } else if (v8Value->IsDate()) { // TODO: in time_utils.pyx there are already functions for // converting cef_time_t to python DateTime, we could easily // add a new function for converting the python DateTime to // string and then to CefString and expose the function using // the "public" keyword. But how do we get the cef_time_t // structure from the CefTime class? GetDateValue() returns // CefTime class. listValue->SetNull((int)listValue->GetSize()); } else if (v8Value->IsString()) { listValue->SetString((int)listValue->GetSize(), v8Value->GetStringValue()); } else if (v8Value->IsArray()) { // Check for IsArray() must happen before the IsObject() check. int length = v8Value->GetArrayLength(); CefRefPtr<CefListValue> newListValue = CefListValue::Create(); for (int i = 0; i < length; ++i) { V8ValueAppendToCefListValue(v8Value->GetValue(i), newListValue, nestingLevel + 1); } listValue->SetList((int)listValue->GetSize(), newListValue); } else if (v8Value->IsFunction()) { // Check for IsFunction() must happen before the IsObject() check. if (CefV8Context::InContext()) { CefRefPtr<CefV8Context> context = \ CefV8Context::GetCurrentContext(); CefRefPtr<CefFrame> frame = context->GetFrame(); std::string strCallbackId = PutJavascriptCallback(frame, v8Value); /* strCallbackId = '####cefpython####' \ '{"what"=>"javascript-callback", ..}' */ listValue->SetString((int)listValue->GetSize(), strCallbackId); } else { listValue->SetNull((int)listValue->GetSize()); DebugLog("V8ValueAppendToCefListValue() FAILED: not in V8 context" " , FATAL ERROR!"); } } else if (v8Value->IsObject()) { // Check for IsObject() must happen after the IsArray() // and IsFunction() checks. listValue->SetDictionary((int)listValue->GetSize(), V8ObjectToCefDictionaryValue(v8Value, nestingLevel + 1)); } else { listValue->SetNull((int)listValue->GetSize()); DebugLog("V8ValueAppendToCefListValue() FAILED: unknown V8 type"); } }
bool CSJsUi::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) { if (name == "startMove") { mWindow->StartMove(); retval = CefV8Value::CreateNull(); return true; } else if (name == "stopMove") { mWindow->StopMove(); retval = CefV8Value::CreateNull(); return true; } else if (name == "startResize") { mWindow->StartResize(); retval = CefV8Value::CreateNull(); return true; } else if (name == "stopResize") { mWindow->StopResize(); retval = CefV8Value::CreateNull(); return true; } else if (name == "show") { if (arguments.size() == 1) { CefRefPtr<CefV8Value> showWindow = arguments[0]; bool show = showWindow->GetBoolValue(); mWindow->Show(show); } retval = CefV8Value::CreateNull(); return true; } else if (name == "close") { mWindow->Close(); retval = CefV8Value::CreateNull(); return true; } else if (name == "setSize") { if (arguments.size() == 2) { int width = arguments[0]->GetIntValue(); int height = arguments[1]->GetIntValue(); mWindow->SetSize(width, height); retval = CefV8Value::CreateNull(); return true; } } else if (name == "move") { if (arguments.size() == 2) { int x = arguments[0]->GetIntValue(); int y = arguments[1]->GetIntValue(); mWindow->SetPos(x, y); retval = CefV8Value::CreateNull(); return true; } } else if (name == "screenSize") { int width, height; mWindow->GetScreenSize(width, height); CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(NULL, NULL); obj->SetValue("width", CefV8Value::CreateInt(width), V8_PROPERTY_ATTRIBUTE_READONLY); obj->SetValue("height", CefV8Value::CreateInt(height), V8_PROPERTY_ATTRIBUTE_READONLY); retval = obj; return true; } else if (name == "createWindow") { if (arguments.size() == 1) { std::string url = arguments[0]->GetStringValue().ToString(); CSLogDebug("createWindow(%s)", url.c_str()); CSWindow *window = new CSWindow(url.c_str()); window->Show(false); retval = CefV8Value::CreateNull(); return true; } } else if (name == "menu") { if (arguments.size() == 1) { retval = CSJsMenu::CreateMenu(arguments[0]->GetStringValue()); return true; } } else if (name == "mainMenu") { retval = CSJsMenu::GetMainMenu(); return true; } return false; }