/****************************************************************************** Copyright (C) 2014 by John R. Bradley Copyright (C) 2018 by Hugh Bailey ("Jim") This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ******************************************************************************/ #include "browser-app.hpp" #include "browser-version.h" #include #ifdef _WIN32 #include #endif #ifdef USE_QT_LOOP #include #include #include #include #endif #define UNUSED_PARAMETER(x) \ { \ (void)x; \ } using namespace json11; CefRefPtr BrowserApp::GetRenderProcessHandler() { return this; } CefRefPtr BrowserApp::GetBrowserProcessHandler() { return this; } void BrowserApp::OnRegisterCustomSchemes(CefRawPtr registrar) { #if CHROME_VERSION_BUILD >= 3683 registrar->AddCustomScheme("http", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED); #elif CHROME_VERSION_BUILD >= 3029 registrar->AddCustomScheme("http", true, false, false, false, true, false); #else registrar->AddCustomScheme("http", true, false, false, false, true); #endif } void BrowserApp::OnBeforeChildProcessLaunch( CefRefPtr command_line) { #ifdef _WIN32 std::string pid = std::to_string(GetCurrentProcessId()); command_line->AppendSwitchWithValue("parent_pid", pid); #else (void)command_line; #endif } void BrowserApp::OnBeforeCommandLineProcessing( const CefString &, CefRefPtr command_line) { if (!shared_texture_available) { bool enableGPU = command_line->HasSwitch("enable-gpu"); CefString type = command_line->GetSwitchValue("type"); if (!enableGPU && type.empty()) { command_line->AppendSwitch("disable-gpu-compositing"); } } if (command_line->HasSwitch("disable-features")) { // Don't override existing, as this can break OSR std::string disableFeatures = command_line->GetSwitchValue("disable-features"); disableFeatures += ",HardwareMediaKeyHandling"; command_line->AppendSwitchWithValue("disable-features", disableFeatures); } else { command_line->AppendSwitchWithValue("disable-features", "HardwareMediaKeyHandling"); } command_line->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required"); #ifdef __APPLE__ command_line->AppendSwitch("use-mock-keychain"); #endif } void BrowserApp::OnContextCreated(CefRefPtr browser, CefRefPtr, CefRefPtr context) { CefRefPtr globalObj = context->GetGlobal(); CefRefPtr obsStudioObj = CefV8Value::CreateObject(0, 0); globalObj->SetValue("obsstudio", obsStudioObj, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr pluginVersion = CefV8Value::CreateString(OBS_BROWSER_VERSION_STRING); obsStudioObj->SetValue("pluginVersion", pluginVersion, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr getCurrentScene = CefV8Value::CreateFunction("getCurrentScene", this); obsStudioObj->SetValue("getCurrentScene", getCurrentScene, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr getStatus = CefV8Value::CreateFunction("getStatus", this); obsStudioObj->SetValue("getStatus", getStatus, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr saveReplayBuffer = CefV8Value::CreateFunction("saveReplayBuffer", this); obsStudioObj->SetValue("saveReplayBuffer", saveReplayBuffer, V8_PROPERTY_ATTRIBUTE_NONE); #if !ENABLE_WASHIDDEN int id = browser->GetIdentifier(); if (browserVis.find(id) != browserVis.end()) { SetDocumentVisibility(browser, browserVis[id]); } #endif } void BrowserApp::ExecuteJSFunction(CefRefPtr browser, const char *functionName, CefV8ValueList arguments) { CefRefPtr context = browser->GetMainFrame()->GetV8Context(); context->Enter(); CefRefPtr globalObj = context->GetGlobal(); CefRefPtr obsStudioObj = globalObj->GetValue("obsstudio"); CefRefPtr jsFunction = obsStudioObj->GetValue(functionName); if (jsFunction && jsFunction->IsFunction()) jsFunction->ExecuteFunction(NULL, arguments); context->Exit(); } #if !ENABLE_WASHIDDEN void BrowserApp::SetFrameDocumentVisibility(CefRefPtr browser, CefRefPtr frame, bool isVisible) { UNUSED_PARAMETER(browser); CefRefPtr context = frame->GetV8Context(); context->Enter(); CefRefPtr globalObj = context->GetGlobal(); CefRefPtr documentObject = globalObj->GetValue("document"); if (!!documentObject) { documentObject->SetValue("hidden", CefV8Value::CreateBool(!isVisible), V8_PROPERTY_ATTRIBUTE_READONLY); documentObject->SetValue( "visibilityState", CefV8Value::CreateString(isVisible ? "visible" : "hidden"), V8_PROPERTY_ATTRIBUTE_READONLY); std::string script = "new CustomEvent('visibilitychange', {});"; CefRefPtr returnValue; CefRefPtr exception; /* Create the CustomEvent object * We have to use eval to invoke the new operator */ bool success = context->Eval(script, frame->GetURL(), 0, returnValue, exception); if (success) { CefV8ValueList arguments; arguments.push_back(returnValue); CefRefPtr dispatchEvent = documentObject->GetValue("dispatchEvent"); /* Dispatch visibilitychange event on the document * object */ dispatchEvent->ExecuteFunction(documentObject, arguments); } } context->Exit(); } void BrowserApp::SetDocumentVisibility(CefRefPtr browser, bool isVisible) { /* This method might be called before OnContextCreated * call is made. We'll save the requested visibility * state here, and use it later in OnContextCreated to * set initial page visibility state. */ browserVis[browser->GetIdentifier()] = isVisible; std::vector frameIdentifiers; /* Set visibility state for every frame in the browser * * According to the Page Visibility API documentation: * https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API * * "Visibility states of an