mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 04:42:18 +02:00
b756c78f44
Fixes compatibility messages appearing when no window is selected in window capture properties.
201 lines
4.6 KiB
C
201 lines
4.6 KiB
C
#include <jansson.h>
|
|
|
|
#include <obs-module.h>
|
|
#include <util/dstr.h>
|
|
#include <util/platform.h>
|
|
#include <util/windows/window-helpers.h>
|
|
|
|
#include "compat-helpers.h"
|
|
#include "compat-format-ver.h"
|
|
|
|
enum match_flags {
|
|
MATCH_EXE = 1 << 0,
|
|
MATCH_TITLE = 1 << 1,
|
|
MATCH_CLASS = 1 << 2,
|
|
};
|
|
|
|
static inline const char *get_string_val(json_t *entry, const char *key)
|
|
{
|
|
json_t *str_val = json_object_get(entry, key);
|
|
if (!str_val || !json_is_string(str_val))
|
|
return NULL;
|
|
|
|
return json_string_value(str_val);
|
|
}
|
|
|
|
static inline int get_int_val(json_t *entry, const char *key)
|
|
{
|
|
json_t *integer_val = json_object_get(entry, key);
|
|
if (!integer_val || !json_is_integer(integer_val))
|
|
return 0;
|
|
|
|
return (int)json_integer_value(integer_val);
|
|
}
|
|
|
|
static inline bool get_bool_val(json_t *entry, const char *key)
|
|
{
|
|
json_t *bool_val = json_object_get(entry, key);
|
|
if (!bool_val || !json_is_boolean(bool_val))
|
|
return false;
|
|
|
|
return json_is_true(bool_val);
|
|
}
|
|
|
|
static json_t *open_json_file(const char *file)
|
|
{
|
|
char *file_data = os_quick_read_utf8_file(file);
|
|
json_error_t error;
|
|
json_t *root;
|
|
json_t *list;
|
|
int format_ver;
|
|
|
|
if (!file_data)
|
|
return NULL;
|
|
|
|
root = json_loads(file_data, JSON_REJECT_DUPLICATES, &error);
|
|
bfree(file_data);
|
|
|
|
if (!root) {
|
|
blog(LOG_WARNING,
|
|
"compat-helpers.c: [open_json_file] "
|
|
"Error reading JSON file (%d): %s",
|
|
error.line, error.text);
|
|
return NULL;
|
|
}
|
|
|
|
format_ver = get_int_val(root, "format_version");
|
|
|
|
if (format_ver != COMPAT_FORMAT_VERSION) {
|
|
blog(LOG_DEBUG,
|
|
"compat-helpers.c: [open_json_file] "
|
|
"Wrong format version (%d), expected %d",
|
|
format_ver, COMPAT_FORMAT_VERSION);
|
|
json_decref(root);
|
|
return NULL;
|
|
}
|
|
|
|
list = json_object_get(root, "entries");
|
|
if (list)
|
|
json_incref(list);
|
|
json_decref(root);
|
|
|
|
if (!list) {
|
|
blog(LOG_WARNING, "compat-helpers.c: [open_json_file] "
|
|
"No compatibility list");
|
|
return NULL;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
static json_t *open_compat_file(void)
|
|
{
|
|
char *file;
|
|
json_t *root = NULL;
|
|
|
|
file = obs_module_config_path("compatibility.json");
|
|
if (file) {
|
|
root = open_json_file(file);
|
|
bfree(file);
|
|
}
|
|
|
|
if (!root) {
|
|
file = obs_module_file("compatibility.json");
|
|
if (file) {
|
|
root = open_json_file(file);
|
|
bfree(file);
|
|
}
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
static json_t *compat_entries;
|
|
struct compat_result *check_compatibility(const char *win_title,
|
|
const char *win_class,
|
|
const char *exe,
|
|
enum source_type type)
|
|
{
|
|
if (!compat_entries) {
|
|
json_t *root = open_compat_file();
|
|
if (!root)
|
|
return NULL;
|
|
|
|
compat_entries = root;
|
|
}
|
|
|
|
struct dstr message;
|
|
struct compat_result *res = NULL;
|
|
json_t *entry;
|
|
size_t index;
|
|
|
|
json_array_foreach (compat_entries, index, entry) {
|
|
if (type == GAME_CAPTURE &&
|
|
!get_bool_val(entry, "game_capture"))
|
|
continue;
|
|
if (type == WINDOW_CAPTURE_WGC &&
|
|
!get_bool_val(entry, "window_capture_wgc"))
|
|
continue;
|
|
if (type == WINDOW_CAPTURE_BITBLT &&
|
|
!get_bool_val(entry, "window_capture"))
|
|
continue;
|
|
|
|
int match_flags = get_int_val(entry, "match_flags");
|
|
const char *j_exe = get_string_val(entry, "executable");
|
|
const char *j_title = get_string_val(entry, "window_title");
|
|
const char *j_class = get_string_val(entry, "window_class");
|
|
|
|
if ((match_flags & MATCH_CLASS) &&
|
|
(!win_class || strcmp(win_class, j_class) != 0))
|
|
continue;
|
|
if ((match_flags & MATCH_EXE) &&
|
|
(!exe || astrcmpi(exe, j_exe) != 0))
|
|
continue;
|
|
/* Title supports partial matches as some games append additional
|
|
* information after the title, e.g., "Minecraft 1.18". */
|
|
if ((match_flags & MATCH_TITLE) &&
|
|
(!win_title ||
|
|
astrcmpi_n(win_title, j_title, strlen(j_title)) != 0))
|
|
continue;
|
|
|
|
/* Attempt to translate and compile message */
|
|
const char *key = get_string_val(entry, "translation_key");
|
|
const char *msg = get_string_val(entry, "message");
|
|
obs_module_get_string(key, &msg);
|
|
|
|
dstr_init_copy(&message, msg);
|
|
|
|
const char *name = get_string_val(entry, "name");
|
|
/* Replace placeholders in generic messages */
|
|
if (name && dstr_find(&message, "%") != NULL) {
|
|
dstr_replace(&message, "%name%", name);
|
|
}
|
|
|
|
const char *url = get_string_val(entry, "url");
|
|
/* Append clickable URL in Qt rich text */
|
|
if (url && strncmp(url, "https://", 8) == 0) {
|
|
dstr_catf(&message, "<br>\n<a href=\"%s\">%s</a>", url,
|
|
url + 8);
|
|
}
|
|
|
|
res = bzalloc(sizeof(struct compat_result));
|
|
res->severity = get_int_val(entry, "severity");
|
|
res->message = message.array;
|
|
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void compat_result_free(struct compat_result *res)
|
|
{
|
|
bfree(res->message);
|
|
bfree(res);
|
|
}
|
|
|
|
void compat_json_free()
|
|
{
|
|
json_decref(compat_entries);
|
|
}
|