Skip to content

Commit

Permalink
UI: Make projectors somewhat work on Wayland
Browse files Browse the repository at this point in the history
This makes the projectors work on Wayland. The ability to set a fullscreen
projector windowed and vice-versa is disabled, as Wayland doesn't really
support resizing windows from code.
  • Loading branch information
cg2121 committed Nov 24, 2024
1 parent dfc3a69 commit 93f5c40
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 26 deletions.
89 changes: 64 additions & 25 deletions UI/window-projector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,35 @@
#include "platform.hpp"
#include "multiview.hpp"

#ifdef ENABLE_WAYLAND
#include <obs-nix-platform.h>
#endif

#ifdef _WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#endif

static QList<OBSProjector *> multiviewProjectors;

static bool updatingMultiview = false, mouseSwitching, transitionOnDoubleClick;

static bool IsWayland()
{
return QApplication::platformName().contains("wayland");
}

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(this);
layout->addWidget(&display);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);

OBSSource source = GetSource();
if (source) {
sigs.emplace_back(obs_source_get_signal_handler(source), "rename", OBSSourceRenamed, this);
Expand All @@ -32,7 +53,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);
display.windowHandle()->setProperty("isOBSProjectorWindow", true);

#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
// Prevents resizing of projector windows
Expand Down Expand Up @@ -70,11 +91,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 @@ -93,17 +114,14 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
ready = true;

show();

// We need it here to allow keyboard input in X11 to listen to Escape
activateWindow();
}

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 Down Expand Up @@ -222,7 +240,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 @@ -251,29 +269,33 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event)

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

QMenu popup(this);

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

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

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

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

QAction *alwaysOnTopButton = new QAction(QTStr("Basic.MainMenu.View.AlwaysOnTop"), this);
alwaysOnTopButton->setCheckable(true);
alwaysOnTopButton->setChecked(isAlwaysOnTop);
if (!IsWayland()) {
QAction *alwaysOnTopButton = new QAction(QTStr("Basic.MainMenu.AlwaysOnTop"), this);
alwaysOnTopButton->setCheckable(true);
alwaysOnTopButton->setChecked(isAlwaysOnTop);

connect(alwaysOnTopButton, &QAction::toggled, this, &OBSProjector::AlwaysOnTopToggled);
connect(alwaysOnTopButton, &QAction::toggled, this, &OBSProjector::AlwaysOnTopToggled);

popup.addAction(alwaysOnTopButton);
popup.addAction(alwaysOnTopButton);
}

popup.addAction(QTStr("Close"), this, &OBSProjector::EscapeTriggered);
popup.exec(QCursor::pos());
Expand Down Expand Up @@ -413,7 +435,6 @@ void OBSProjector::OpenFullScreenProjector()

void OBSProjector::OpenWindowedProjector()
{
showFullScreen();
showNormal();
setCursor(Qt::ArrowCursor);

Expand Down Expand Up @@ -466,6 +487,24 @@ void OBSProjector::closeEvent(QCloseEvent *event)
event->accept();
}

bool OBSProjector::nativeEvent(const QByteArray &, void *message, qintptr *)
{
#ifdef _WIN32
const MSG &msg = *static_cast<MSG *>(message);
switch (msg.message) {
case WM_MOVE:
display.OnMove();
break;
case WM_DISPLAYCHANGE:
display.OnDisplayChange();
}
#else
UNUSED_PARAMETER(message);
#endif

return false;
}

bool OBSProjector::IsAlwaysOnTop() const
{
return isAlwaysOnTop;
Expand Down
4 changes: 3 additions & 1 deletion UI/window-projector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ enum class ProjectorType {

class QMouseEvent;

class OBSProjector : public OBSQTDisplay {
class OBSProjector : public QWidget {
Q_OBJECT

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

static void OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy);
static void OBSRender(void *data, uint32_t cx, uint32_t cy);
Expand All @@ -29,6 +30,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

0 comments on commit 93f5c40

Please sign in to comment.