Skip to content

Commit

Permalink
fontend: Make OBSProject a parent window
Browse files Browse the repository at this point in the history
This window was previously a parent of OBSQTDisplay, however
OBSQTDisplay is supposed to be completely rendered by OBS. On linux this
causes issues like not having window decorations and weird rendering
artifacts during resize. For wayland systems that negotiate explicit
sync it also triggers protocol violations (crashes) due to QT and OBS
thinking they should be rendering this window.

Instead make the project a parent window owned by Qt that only contains
one widget, the OBSQTDisplay. This makes the window behave like the
main OBS window and preview.

fixes obsproject#6283

Co-authored-by: cg2121 <[email protected]>
  • Loading branch information
kkartaltepe and cg2121 committed Jan 26, 2025
1 parent ecb0381 commit a327f74
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 35 deletions.
85 changes: 51 additions & 34 deletions frontend/widgets/OBSProjector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,26 @@ static QList<OBSProjector *> multiviewProjectors;
static bool updatingMultiview = false, mouseSwitching, transitionOnDoubleClick;

OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, ProjectorType type_)
: OBSQTDisplay(widget, Qt::Window),
: QWidget(widget, Qt::Window),
display(this),
weakSource(OBSGetWeakRef(source_))
{
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(&display);
layout->setContentsMargins(0, 0, 0, 0);
this->setLayout(layout);

// Whether the compositor and qt are able to agree on the current state
// of a native window after transitioning between windowed and
// fullscreen. If not, then we should not allow users to modify existing
// projectors to switch between fullscreen/windowed.
qtFullscreenNativeWorks = true;
#if !defined(_WIN32) && !defined(__APPLE__)
const char *desktop = getenv("XDG_CURRENT_DESKTOP");
if (desktop && strstr(desktop, "GNOME") != nullptr && QApplication::platformName().contains("wayland"))
qtFullscreenNativeWorks = false;
#endif

OBSSource source = GetSource();
if (source) {
sigs.emplace_back(obs_source_get_signal_handler(source), "rename", OBSSourceRenamed, this);
Expand All @@ -34,12 +51,7 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,

// Mark the window as a projector so SetDisplayAffinity
// can skip it
windowHandle()->setProperty("isOBSProjectorWindow", true);

#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
// Prevents resizing of projector windows
setAttribute(Qt::WA_PaintOnScreen, false);
#endif
this->setProperty("isOBSProjectorWindow", true);

type = type_;
#ifdef __APPLE__
Expand All @@ -48,10 +60,7 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
setWindowIcon(QIcon::fromTheme("obs", QIcon(":/res/images/obs.png")));
#endif

if (monitor == -1)
resize(480, 270);
else
SetMonitor(monitor);
resize(480, 270);

if (source)
UpdateProjectorTitle(QT_UTF8(obs_source_get_name(source)));
Expand All @@ -72,11 +81,11 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,

auto addDrawCallback = [this]() {
bool isMultiview = type == ProjectorType::Multiview;
obs_display_add_draw_callback(GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
obs_display_set_background_color(GetDisplay(), 0x000000);
obs_display_add_draw_callback(display.GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
obs_display_set_background_color(display.GetDisplay(), 0x000000);
};

connect(this, &OBSQTDisplay::DisplayCreated, addDrawCallback);
connect(&display, &OBSQTDisplay::DisplayCreated, addDrawCallback);
connect(App(), &QGuiApplication::screenRemoved, this, &OBSProjector::ScreenRemoved);

if (type == ProjectorType::Multiview) {
Expand All @@ -94,6 +103,8 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,

ready = true;

if (monitor != -1)
SetMonitor(monitor);
show();

// We need it here to allow keyboard input in X11 to listen to Escape
Expand All @@ -105,7 +116,7 @@ OBSProjector::~OBSProjector()
sigs.clear();

bool isMultiview = type == ProjectorType::Multiview;
obs_display_remove_draw_callback(GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
obs_display_remove_draw_callback(display.GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);

OBSSource source = GetSource();
if (source)
Expand All @@ -125,9 +136,9 @@ void OBSProjector::SetMonitor(int monitor)
{
savedMonitor = monitor;
screen = QGuiApplication::screens()[monitor];
setGeometry(screen->geometry());
showFullScreen();
SetHideCursor();
update();
}

void OBSProjector::SetHideCursor()
Expand Down Expand Up @@ -224,7 +235,7 @@ void OBSProjector::OBSSourceDestroyed(void *data, calldata_t *)

void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event)
{
OBSQTDisplay::mouseDoubleClickEvent(event);
QWidget::mouseDoubleClickEvent(event);

if (!mouseSwitching)
return;
Expand Down Expand Up @@ -253,19 +264,20 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event)

void OBSProjector::mousePressEvent(QMouseEvent *event)
{
OBSQTDisplay::mousePressEvent(event);
QWidget::mousePressEvent(event);

if (event->button() == Qt::RightButton) {
QMenu *projectorMenu = new QMenu(QTStr("Fullscreen"));
OBSBasic::AddProjectorMenuMonitors(projectorMenu, this, &OBSProjector::OpenFullScreenProjector);

QMenu popup(this);
popup.addMenu(projectorMenu);

if (GetMonitor() > -1) {
popup.addAction(QTStr("Windowed"), this, &OBSProjector::OpenWindowedProjector);

} else if (!this->isMaximized()) {
if (qtFullscreenNativeWorks) {
QMenu *projectorMenu = new QMenu(QTStr("Fullscreen"));
OBSBasic::AddProjectorMenuMonitors(projectorMenu, this, &OBSProjector::OpenFullScreenProjector);
popup.addMenu(projectorMenu);

if (GetMonitor() > -1) {
popup.addAction(QTStr("Windowed"), this, &OBSProjector::OpenWindowedProjector);
}
}
if (!this->isMaximized() && GetMonitor() == -1) {
popup.addAction(QTStr("ResizeProjectorWindowToContent"), this, &OBSProjector::ResizeToContent);
}

Expand Down Expand Up @@ -415,20 +427,20 @@ void OBSProjector::OpenFullScreenProjector()

void OBSProjector::OpenWindowedProjector()
{
showFullScreen();

if (!prevGeometry.isNull()) {
display.setGeometry(prevGeometry);
} else
display.resize(480, 270);
showNormal();
setCursor(Qt::ArrowCursor);

if (!prevGeometry.isNull())
setGeometry(prevGeometry);
else
resize(480, 270);
update();

savedMonitor = -1;
screen = nullptr;

OBSSource source = GetSource();
UpdateProjectorTitle(QT_UTF8(obs_source_get_name(source)));
screen = nullptr;
}

void OBSProjector::ResizeToContent()
Expand Down Expand Up @@ -478,6 +490,11 @@ bool OBSProjector::IsAlwaysOnTopOverridden() const
return isAlwaysOnTopOverridden;
}

bool OBSProjector::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
{
return display.nativeEvent(eventType, message, result);
}

void OBSProjector::SetIsAlwaysOnTop(bool isAlwaysOnTop, bool isOverridden)
{
this->isAlwaysOnTop = isAlwaysOnTop;
Expand Down
7 changes: 6 additions & 1 deletion frontend/widgets/OBSProjector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ enum class ProjectorType {
Multiview,
};

class OBSProjector : public OBSQTDisplay {
class QMouseEvent;

class OBSProjector : public QWidget {
Q_OBJECT

private:
OBSQTDisplay display;
OBSWeakSourceAutoRelease weakSource;
std::vector<OBSSignal> sigs;
bool qtFullscreenNativeWorks;

static void OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy);
static void OBSRender(void *data, uint32_t cx, uint32_t cy);
Expand All @@ -27,6 +31,7 @@ class OBSProjector : public OBSQTDisplay {
void mousePressEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void closeEvent(QCloseEvent *event) override;
virtual bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;

bool isAlwaysOnTop;
bool isAlwaysOnTopOverridden = false;
Expand Down
2 changes: 2 additions & 0 deletions frontend/widgets/OBSQTDisplay.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class OBSQTDisplay : public QWidget {
Q_PROPERTY(QColor displayBackgroundColor MEMBER backgroundColor READ GetDisplayBackgroundColor WRITE
SetDisplayBackgroundColor)

friend class OBSProjector;

OBSDisplay display;
bool destroying = false;

Expand Down

0 comments on commit a327f74

Please sign in to comment.