mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-15 07:44:10 +00:00
UI: Add intro startup page (windows)
Allows the ability to show a web page via CEF to the users on startup to present and announce new features.
This commit is contained in:
parent
28e3604a56
commit
a032bcc798
|
@ -55,6 +55,8 @@ include_directories(${FFMPEG_INCLUDE_DIRS})
|
|||
include_directories(SYSTEM "obs-frontend-api")
|
||||
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
|
||||
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/deps/libff")
|
||||
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/deps/json11")
|
||||
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/plugins/obs-browser/panel")
|
||||
|
||||
find_package(Libcurl REQUIRED)
|
||||
include_directories(${LIBCURL_INCLUDE_DIRS})
|
||||
|
@ -127,6 +129,7 @@ endif()
|
|||
set(obs_SOURCES
|
||||
${obs_PLATFORM_SOURCES}
|
||||
${obs_libffutil_SOURCES}
|
||||
../deps/json11/json11.cpp
|
||||
obs-app.cpp
|
||||
api-interface.cpp
|
||||
window-basic-main.cpp
|
||||
|
@ -178,6 +181,7 @@ set(obs_SOURCES
|
|||
set(obs_HEADERS
|
||||
${obs_PLATFORM_HEADERS}
|
||||
${obs_libffutil_HEADERS}
|
||||
../deps/json11/json11.hpp
|
||||
obs-app.hpp
|
||||
platform.hpp
|
||||
window-main.hpp
|
||||
|
|
|
@ -367,6 +367,7 @@ bool OBSApp::InitGlobalConfigDefaults()
|
|||
config_set_default_string(globalConfig, "General", "Language",
|
||||
DEFAULT_LANG);
|
||||
config_set_default_uint(globalConfig, "General", "MaxLogs", 10);
|
||||
config_set_default_int(globalConfig, "General", "InfoIncrement", -1);
|
||||
config_set_default_string(globalConfig, "General", "ProcessPriority",
|
||||
"Normal");
|
||||
config_set_default_bool(globalConfig, "General", "EnableAutoUpdates",
|
||||
|
|
|
@ -27,11 +27,15 @@ using namespace std;
|
|||
#define WIN_MANIFEST_URL "https://obsproject.com/update_studio/manifest.json"
|
||||
#endif
|
||||
|
||||
#ifndef WIN_WHATSNEW_URL
|
||||
#define WIN_WHATSNEW_URL "https://obsproject.com/update_studio/whatsnew.json"
|
||||
#endif
|
||||
|
||||
#ifndef WIN_UPDATER_URL
|
||||
#define WIN_UPDATER_URL "https://obsproject.com/update_studio/updater.exe"
|
||||
#endif
|
||||
|
||||
static HCRYPTPROV provider = 0;
|
||||
static __declspec(thread) HCRYPTPROV provider = 0;
|
||||
|
||||
#pragma pack(push, r1, 1)
|
||||
|
||||
|
@ -780,3 +784,114 @@ try {
|
|||
} catch (string text) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
void WhatsNewInfoThread::run()
|
||||
try {
|
||||
long responseCode;
|
||||
vector<string> extraHeaders;
|
||||
string text;
|
||||
string error;
|
||||
string signature;
|
||||
CryptProvider localProvider;
|
||||
BYTE whatsnewHash[BLAKE2_HASH_LENGTH];
|
||||
bool success;
|
||||
|
||||
BPtr<char> whatsnewPath = GetConfigPathPtr(
|
||||
"obs-studio\\updates\\whatsnew.json");
|
||||
|
||||
/* ----------------------------------- *
|
||||
* create signature provider */
|
||||
|
||||
if (!CryptAcquireContext(&localProvider,
|
||||
nullptr,
|
||||
MS_ENH_RSA_AES_PROV,
|
||||
PROV_RSA_AES,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
throw strprintf("CryptAcquireContext failed: %lu",
|
||||
GetLastError());
|
||||
|
||||
provider = localProvider;
|
||||
|
||||
/* ----------------------------------- *
|
||||
* avoid downloading json again */
|
||||
|
||||
if (CalculateFileHash(whatsnewPath, whatsnewHash)) {
|
||||
char hashString[BLAKE2_HASH_STR_LENGTH];
|
||||
HashToString(whatsnewHash, hashString);
|
||||
|
||||
string header = "If-None-Match: ";
|
||||
header += hashString;
|
||||
extraHeaders.push_back(move(header));
|
||||
}
|
||||
|
||||
/* ----------------------------------- *
|
||||
* get current install GUID */
|
||||
|
||||
const char *pguid = config_get_string(GetGlobalConfig(),
|
||||
"General", "InstallGUID");
|
||||
string guid;
|
||||
if (pguid)
|
||||
guid = pguid;
|
||||
|
||||
if (guid.empty()) {
|
||||
GenerateGUID(guid);
|
||||
|
||||
if (!guid.empty())
|
||||
config_set_string(GetGlobalConfig(),
|
||||
"General", "InstallGUID",
|
||||
guid.c_str());
|
||||
}
|
||||
|
||||
if (!guid.empty()) {
|
||||
string header = "X-OBS2-GUID: ";
|
||||
header += guid;
|
||||
extraHeaders.push_back(move(header));
|
||||
}
|
||||
|
||||
/* ----------------------------------- *
|
||||
* get json from server */
|
||||
|
||||
success = GetRemoteFile(WIN_WHATSNEW_URL, text, error, &responseCode,
|
||||
nullptr, nullptr, extraHeaders, &signature);
|
||||
|
||||
if (!success || (responseCode != 200 && responseCode != 304)) {
|
||||
if (responseCode == 404)
|
||||
return;
|
||||
|
||||
throw strprintf("Failed to fetch whatsnew file: %s",
|
||||
error.c_str());
|
||||
}
|
||||
|
||||
/* ----------------------------------- *
|
||||
* verify file signature */
|
||||
|
||||
if (responseCode == 200) {
|
||||
success = CheckDataSignature(text, "whatsnew",
|
||||
signature.data(), signature.size());
|
||||
if (!success)
|
||||
throw string("Invalid whatsnew signature");
|
||||
}
|
||||
|
||||
/* ----------------------------------- *
|
||||
* write or load json */
|
||||
|
||||
if (responseCode == 200) {
|
||||
if (!QuickWriteFile(whatsnewPath, text.data(), text.size()))
|
||||
throw strprintf("Could not write file '%s'",
|
||||
whatsnewPath.Get());
|
||||
} else {
|
||||
if (!QuickReadFile(whatsnewPath, text))
|
||||
throw strprintf("Could not read file '%s'",
|
||||
whatsnewPath.Get());
|
||||
}
|
||||
|
||||
/* ----------------------------------- *
|
||||
* success */
|
||||
|
||||
emit Result(QString::fromUtf8(text.c_str()));
|
||||
|
||||
} catch (string text) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
|
||||
}
|
||||
|
|
|
@ -21,3 +21,15 @@ private slots:
|
|||
public:
|
||||
AutoUpdateThread(bool manualUpdate_) : manualUpdate(manualUpdate_) {}
|
||||
};
|
||||
|
||||
class WhatsNewInfoThread : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
virtual void run() override;
|
||||
|
||||
signals:
|
||||
void Result(const QString &text);
|
||||
|
||||
public:
|
||||
inline WhatsNewInfoThread() {}
|
||||
};
|
||||
|
|
|
@ -68,8 +68,19 @@
|
|||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <browser-panel.hpp>
|
||||
#endif
|
||||
|
||||
#include <json11.hpp>
|
||||
|
||||
using namespace json11;
|
||||
using namespace std;
|
||||
|
||||
#ifdef _WIN32
|
||||
static CREATE_BROWSER_WIDGET_PROC create_browser_widget = nullptr;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename OBSRef>
|
||||
|
@ -1429,6 +1440,10 @@ void OBSBasic::OBSInit()
|
|||
blog(LOG_INFO, "---------------------------------");
|
||||
obs_post_load_modules();
|
||||
|
||||
#ifdef _WIN32
|
||||
create_browser_widget = obs_browser_init_panel();
|
||||
#endif
|
||||
|
||||
CheckForSimpleModeX264Fallback();
|
||||
|
||||
blog(LOG_INFO, STARTUP_SEPARATOR);
|
||||
|
@ -1649,6 +1664,21 @@ void OBSBasic::OnFirstLoad()
|
|||
{
|
||||
if (api)
|
||||
api->on_event(OBS_FRONTEND_EVENT_FINISHED_LOADING);
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Attempt to load init screen if available */
|
||||
if (create_browser_widget) {
|
||||
WhatsNewInfoThread *wnit = new WhatsNewInfoThread();
|
||||
if (wnit) {
|
||||
connect(wnit, &WhatsNewInfoThread::Result,
|
||||
this, &OBSBasic::ReceivedIntroJson);
|
||||
}
|
||||
if (wnit) {
|
||||
introCheckThread = wnit;
|
||||
introCheckThread->start();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OBSBasic::DeferredLoad(const QString &file, int requeueCount)
|
||||
|
@ -1666,6 +1696,93 @@ void OBSBasic::DeferredLoad(const QString &file, int requeueCount)
|
|||
OnFirstLoad();
|
||||
}
|
||||
|
||||
/* shows a "what's new" page on startup of new versions using CEF */
|
||||
void OBSBasic::ReceivedIntroJson(const QString &text)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string err;
|
||||
Json json = Json::parse(QT_TO_UTF8(text), err);
|
||||
if (!err.empty())
|
||||
return;
|
||||
|
||||
std::string info_url;
|
||||
int info_increment = -1;
|
||||
|
||||
/* check to see if there's an info page for this version */
|
||||
const Json::array &items = json.array_items();
|
||||
for (const Json &item : items) {
|
||||
const std::string &version = item["version"].string_value();
|
||||
const std::string &url = item["url"].string_value();
|
||||
int increment = item["increment"].int_value();
|
||||
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
|
||||
sscanf(version.c_str(), "%d.%d", &major, &minor);
|
||||
if (major == LIBOBS_API_MAJOR_VER &&
|
||||
minor == LIBOBS_API_MINOR_VER) {
|
||||
info_url = url;
|
||||
info_increment = increment;
|
||||
}
|
||||
}
|
||||
|
||||
/* this version was not found, or no info for this version */
|
||||
if (info_increment == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t lastVersion = config_get_int(App()->GlobalConfig(), "General",
|
||||
"LastVersion");
|
||||
|
||||
int current_version_increment = -1;
|
||||
|
||||
if (lastVersion < LIBOBS_API_VER) {
|
||||
config_set_int(App()->GlobalConfig(), "General",
|
||||
"InfoIncrement", -1);
|
||||
} else {
|
||||
current_version_increment = config_get_int(
|
||||
App()->GlobalConfig(), "General",
|
||||
"InfoIncrement");
|
||||
}
|
||||
|
||||
if (info_increment <= current_version_increment) {
|
||||
return;
|
||||
}
|
||||
|
||||
config_set_int(App()->GlobalConfig(), "General",
|
||||
"InfoIncrement", info_increment);
|
||||
|
||||
QDialog dlg(this);
|
||||
dlg.setWindowTitle("What's New");
|
||||
dlg.resize(600, 600);
|
||||
|
||||
QCefWidget *cefWidget = create_browser_widget(nullptr, info_url);
|
||||
if (!cefWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect(cefWidget, SIGNAL(titleChanged(const QString &)),
|
||||
&dlg, SLOT(setWindowTitle(const QString &)));
|
||||
|
||||
QPushButton *close = new QPushButton(QTStr("Close"));
|
||||
connect(close, &QAbstractButton::clicked,
|
||||
&dlg, &QDialog::accept);
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout();
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(close);
|
||||
bottomLayout->addStretch();
|
||||
|
||||
QVBoxLayout *topLayout = new QVBoxLayout(&dlg);
|
||||
topLayout->addWidget(cefWidget);
|
||||
topLayout->addLayout(bottomLayout);
|
||||
|
||||
dlg.exec();
|
||||
#else
|
||||
UNUSED_PARAMETER(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OBSBasic::UpdateMultiviewProjectorMenu()
|
||||
{
|
||||
multiviewProjectorMenu->clear();
|
||||
|
@ -3389,6 +3506,8 @@ void OBSBasic::closeEvent(QCloseEvent *event)
|
|||
|
||||
blog(LOG_INFO, SHUTDOWN_SEPARATOR);
|
||||
|
||||
if (introCheckThread)
|
||||
introCheckThread->wait();
|
||||
if (updateCheckThread)
|
||||
updateCheckThread->wait();
|
||||
if (logUploadThread)
|
||||
|
|
|
@ -139,6 +139,7 @@ private:
|
|||
bool copyVisible = true;
|
||||
|
||||
QPointer<QThread> updateCheckThread;
|
||||
QPointer<QThread> introCheckThread;
|
||||
QPointer<QThread> logUploadThread;
|
||||
|
||||
QPointer<OBSBasicInteraction> interaction;
|
||||
|
@ -369,6 +370,8 @@ private:
|
|||
obs_data_array_t *SaveProjectors();
|
||||
void LoadSavedProjectors(obs_data_array_t *savedProjectors);
|
||||
|
||||
void ReceivedIntroJson(const QString &text);
|
||||
|
||||
public slots:
|
||||
void DeferSaveBegin();
|
||||
void DeferSaveEnd();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f5083a1cc4294b540e9df94663eae88ab42a86fa
|
||||
Subproject commit 89aa4ee8b6c7ae12acbd90158feca1fe61dedf7d
|
Loading…
Reference in a new issue