Add scale support

This commit is contained in:
2026-07-20 10:23:57 +05:00
parent 53161f3f2c
commit 07bd12ee9a
13 changed files with 88 additions and 22 deletions

View File

@@ -29,6 +29,7 @@
#include <QSet>
#include <QShowEvent>
#include <QSocketNotifier>
#include <QSpinBox>
#include <QTableWidget>
#include <QTimer>
#include <QUuid>
@@ -108,11 +109,13 @@ struct DockDefinition {
QString id;
QString title;
QString url;
int zoomPercent = 100;
};
class WebPanel final : public QWidget {
public:
explicit WebPanel(QString url, QWidget *parent = nullptr) : QWidget(parent), url_(std::move(url))
explicit WebPanel(QString url, int zoomPercent, QWidget *parent = nullptr)
: QWidget(parent), url_(std::move(url)), zoomPercent_(zoomPercent)
{
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
@@ -127,11 +130,13 @@ public:
~WebPanel() override { stopRenderer(); }
void setUrl(const QString &url)
void setConfiguration(const QString &url, int zoomPercent)
{
if (url_ == url)
zoomPercent = std::clamp(zoomPercent, 25, 500);
if (url_ == url && zoomPercent_ == zoomPercent)
return;
url_ = url;
zoomPercent_ = zoomPercent;
if (isVisible())
restartRenderer();
}
@@ -343,6 +348,7 @@ private:
header.width = static_cast<uint32_t>(renderWidth_);
header.height = static_cast<uint32_t>(renderHeight_);
header.fps = 30;
header.zoom_percent = static_cast<uint32_t>(zoomPercent_);
header.transparent = 0;
header.hardware_acceleration = 1;
header.url_length = static_cast<uint32_t>(url.size());
@@ -569,6 +575,7 @@ private:
}
QString url_;
int zoomPercent_ = 100;
QString status_;
QImage frame_;
QTimer resizeTimer_;
@@ -732,6 +739,7 @@ private:
obs_data_set_string(item, "id", definition.id.toUtf8().constData());
obs_data_set_string(item, "title", definition.title.toUtf8().constData());
obs_data_set_string(item, "url", definition.url.toUtf8().constData());
obs_data_set_int(item, "zoom", definition.zoomPercent);
obs_data_array_push_back(array, item);
obs_data_release(item);
}
@@ -750,7 +758,11 @@ private:
QString::fromUtf8(obs_data_get_string(item, "id")),
QString::fromUtf8(obs_data_get_string(item, "title")),
QString::fromUtf8(obs_data_get_string(item, "url")),
static_cast<int>(obs_data_get_int(item, "zoom")),
};
if (definition.zoomPercent == 0)
definition.zoomPercent = 100;
definition.zoomPercent = std::clamp(definition.zoomPercent, 25, 500);
if (definition.id.isEmpty())
definition.id = QUuid::createUuid().toString(QUuid::WithoutBraces);
if (!definition.title.trimmed().isEmpty() && !definition.url.trimmed().isEmpty())
@@ -780,11 +792,12 @@ private:
}
for (const DockDefinition &definition : definitions_) {
if (panels_.contains(definition.id) && panels_[definition.id]) {
panels_[definition.id]->setUrl(definition.url);
panels_[definition.id]->setConfiguration(definition.url,
definition.zoomPercent);
panels_[definition.id]->setDockTitle(definition.title);
continue;
}
auto *panel = new WebPanel(definition.url);
auto *panel = new WebPanel(definition.url, definition.zoomPercent);
QByteArray id = dockId(definition.id).toUtf8();
QByteArray title = definition.title.toUtf8();
if (obs_frontend_add_dock_by_id(id.constData(), title.constData(), panel))
@@ -802,10 +815,11 @@ private:
dialog.resize(720, 360);
auto *layout = new QVBoxLayout(&dialog);
layout->addWidget(new QLabel(text("CustomBrowserDocksDescription"), &dialog));
auto *table = new QTableWidget(0, 2, &dialog);
table->setHorizontalHeaderLabels({text("PanelName"), text("URL")});
auto *table = new QTableWidget(0, 3, &dialog);
table->setHorizontalHeaderLabels({text("PanelName"), text("URL"), text("PageZoom")});
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
table->setSelectionBehavior(QAbstractItemView::SelectRows);
table->setSelectionMode(QAbstractItemView::ExtendedSelection);
layout->addWidget(table);
@@ -817,6 +831,12 @@ private:
title->setData(Qt::UserRole, definition.id);
table->setItem(row, 0, title);
table->setItem(row, 1, new QTableWidgetItem(definition.url));
auto *zoom = new QSpinBox(table);
zoom->setRange(25, 500);
zoom->setSingleStep(5);
zoom->setSuffix("%");
zoom->setValue(definition.zoomPercent);
table->setCellWidget(row, 2, zoom);
};
for (const DockDefinition &definition : definitions_)
appendRow(definition);
@@ -829,7 +849,7 @@ private:
rowButtons->addStretch();
layout->addLayout(rowButtons);
QObject::connect(add, &QPushButton::clicked, table, [table, appendRow] {
appendRow({QUuid::createUuid().toString(QUuid::WithoutBraces), QString(), "https://"});
appendRow({QUuid::createUuid().toString(QUuid::WithoutBraces), QString(), "https://", 100});
int row = table->rowCount() - 1;
table->setCurrentCell(row, 0);
table->editItem(table->item(row, 0));
@@ -856,6 +876,7 @@ private:
for (int row = 0; row < table->rowCount(); ++row) {
QString title = table->item(row, 0) ? table->item(row, 0)->text().trimmed() : QString();
QString url = table->item(row, 1) ? table->item(row, 1)->text().trimmed() : QString();
auto *zoom = qobject_cast<QSpinBox *>(table->cellWidget(row, 2));
if (title.isEmpty() || url.isEmpty()) {
QMessageBox::warning(&dialog, text("CustomBrowserDocks"), text("PanelFieldsRequired"));
return;
@@ -868,7 +889,7 @@ private:
QString id = table->item(row, 0)->data(Qt::UserRole).toString();
if (id.isEmpty())
id = QUuid::createUuid().toString(QUuid::WithoutBraces);
updated.push_back({id, title, url});
updated.push_back({id, title, url, zoom ? zoom->value() : 100});
}
definitions_ = std::move(updated);
reconcile();

View File

@@ -68,6 +68,7 @@ struct browser_source {
uint32_t width;
uint32_t height;
uint32_t fps;
uint32_t zoom_percent;
bool transparent;
bool shutdown_when_hidden;
bool visible;
@@ -255,6 +256,7 @@ static bool send_initial_config(struct browser_source *browser, struct renderer_
.width = browser->width,
.height = browser->height,
.fps = browser->fps,
.zoom_percent = browser->zoom_percent,
.transparent = browser->transparent,
.hardware_acceleration = true,
.url_length = (uint32_t)url_length,
@@ -434,6 +436,7 @@ static void browser_update(void *data, obs_data_t *settings)
browser->width = setting_u32(settings, "width", 2, 8192);
browser->height = setting_u32(settings, "height", 2, 8192);
browser->fps = setting_u32(settings, "fps", 1, 60);
browser->zoom_percent = setting_u32(settings, "zoom", 25, 500);
browser->transparent = obs_data_get_bool(settings, "transparent");
browser->shutdown_when_hidden = obs_data_get_bool(settings, "shutdown_when_hidden");
stop_renderer_locked(browser);
@@ -479,6 +482,7 @@ static void browser_defaults(obs_data_t *settings)
obs_data_set_default_int(settings, "width", 1280);
obs_data_set_default_int(settings, "height", 720);
obs_data_set_default_int(settings, "fps", 30);
obs_data_set_default_int(settings, "zoom", 100);
obs_data_set_default_bool(settings, "transparent", true);
obs_data_set_default_bool(settings, "shutdown_when_hidden", false);
}
@@ -498,6 +502,7 @@ static obs_properties_t *browser_properties(void *data)
obs_properties_add_int(props, "width", obs_module_text("Width"), 2, 8192, 1);
obs_properties_add_int(props, "height", obs_module_text("Height"), 2, 8192, 1);
obs_properties_add_int(props, "fps", obs_module_text("FPS"), 1, 60, 1);
obs_properties_add_int_slider(props, "zoom", obs_module_text("PageZoom"), 25, 500, 5);
obs_properties_add_bool(props, "transparent", obs_module_text("Transparent"));
obs_properties_add_text(props, "css", obs_module_text("CustomCSS"), OBS_TEXT_MULTILINE);
obs_properties_add_bool(props, "shutdown_when_hidden", obs_module_text("ShutdownWhenHidden"));

View File

@@ -5,7 +5,7 @@
#define OWB_CONFIG_MAGIC 0x4f574243u /* OWBC */
#define OWB_COMMAND_MAGIC 0x4f574245u /* OWBE */
#define OWB_PROTOCOL_VERSION 2u
#define OWB_PROTOCOL_VERSION 3u
#define OWB_MAX_STRING (16u * 1024u * 1024u)
#define OWB_SHARED_MAGIC 0x4f574246u /* OWBF */
#define OWB_SHARED_FRAME_FD 198
@@ -17,6 +17,7 @@ struct owb_config_header {
uint32_t width;
uint32_t height;
uint32_t fps;
uint32_t zoom_percent;
uint32_t transparent;
uint32_t hardware_acceleration;
uint32_t url_length;

View File

@@ -35,6 +35,7 @@ struct config {
uint32_t width;
uint32_t height;
uint32_t fps;
uint32_t zoom_percent;
bool transparent;
char *url;
char *css;
@@ -107,13 +108,15 @@ static bool read_config(int fd, struct config *config)
if (!read_exact(fd, &header, sizeof(header)) || header.magic != OWB_CONFIG_MAGIC ||
header.version != OWB_PROTOCOL_VERSION || header.width < 2 || header.height < 2 ||
header.width > 8192 || header.height > 8192 || header.fps < 1 || header.fps > 60 ||
header.zoom_percent < 25 || header.zoom_percent > 500 ||
header.url_length > OWB_MAX_STRING || header.css_length > OWB_MAX_STRING)
return false;
config->width = header.width;
config->height = header.height;
config->fps = header.fps;
config->zoom_percent = header.zoom_percent;
config->transparent = header.transparent != 0;
/* Protocol v2 retains this legacy flag, but this renderer always enables the
/* The protocol retains this legacy flag, but this renderer always enables the
* WebKit compositor. */
(void)header.hardware_acceleration;
config->url = calloc((size_t)header.url_length + 1, 1);
@@ -709,6 +712,8 @@ static struct renderer *create_renderer(int client_fd, const int descriptors[4])
webkit_settings_set_media_playback_requires_user_gesture(settings, FALSE);
webkit_settings_set_hardware_acceleration_policy(settings,
WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
webkit_web_view_set_zoom_level(renderer->web_view,
(double)renderer->config.zoom_percent / 100.0);
webkit_web_view_set_is_muted(renderer->web_view, TRUE);
GdkRGBA background = renderer->config.transparent ? (GdkRGBA){0, 0, 0, 0} : (GdkRGBA){1, 1, 1, 1};
webkit_web_view_set_background_color(renderer->web_view, &background);
@@ -776,10 +781,10 @@ static struct renderer *create_renderer(int client_fd, const int descriptors[4])
g_source_remove(idle_source);
idle_source = 0;
}
renderer_log(renderer, "Ready: WebKitGTK %u.%u.%u, %ux%u@%u, shared profile, GPU DMA-BUF, XComposite/XShm capture\n",
renderer_log(renderer, "Ready: WebKitGTK %u.%u.%u, %ux%u@%u, zoom %u%%, shared profile, GPU DMA-BUF, XComposite/XShm capture\n",
webkit_get_major_version(),
webkit_get_minor_version(), webkit_get_micro_version(), renderer->config.width,
renderer->config.height, renderer->config.fps);
renderer->config.height, renderer->config.fps, renderer->config.zoom_percent);
return renderer;
fail: