Skip to content

Commit e468044

Browse files
committed
UI: Make projectors somewhat work on Wayland
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.
1 parent ecb0381 commit e468044

File tree

2 files changed

+69
-26
lines changed

2 files changed

+69
-26
lines changed

frontend/widgets/OBSProjector.cpp

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,35 @@
1313

1414
#include "moc_OBSProjector.cpp"
1515

16+
#ifdef ENABLE_WAYLAND
17+
#include <obs-nix-platform.h>
18+
#endif
19+
20+
#ifdef _WIN32
21+
#define NOMINMAX
22+
#define WIN32_LEAN_AND_MEAN 1
23+
#include <Windows.h>
24+
#endif
25+
1626
static QList<OBSProjector *> multiviewProjectors;
1727

1828
static bool updatingMultiview = false, mouseSwitching, transitionOnDoubleClick;
1929

30+
static bool IsWayland()
31+
{
32+
return QApplication::platformName().contains("wayland");
33+
}
34+
2035
OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, ProjectorType type_)
21-
: OBSQTDisplay(widget, Qt::Window),
36+
: QWidget(widget, Qt::Window),
37+
display(this),
2238
weakSource(OBSGetWeakRef(source_))
2339
{
40+
QVBoxLayout *layout = new QVBoxLayout(this);
41+
layout->addWidget(&display);
42+
layout->setContentsMargins(0, 0, 0, 0);
43+
setLayout(layout);
44+
2445
OBSSource source = GetSource();
2546
if (source) {
2647
sigs.emplace_back(obs_source_get_signal_handler(source), "rename", OBSSourceRenamed, this);
@@ -34,7 +55,7 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
3455

3556
// Mark the window as a projector so SetDisplayAffinity
3657
// can skip it
37-
windowHandle()->setProperty("isOBSProjectorWindow", true);
58+
display.windowHandle()->setProperty("isOBSProjectorWindow", true);
3859

3960
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
4061
// Prevents resizing of projector windows
@@ -72,11 +93,11 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
7293

7394
auto addDrawCallback = [this]() {
7495
bool isMultiview = type == ProjectorType::Multiview;
75-
obs_display_add_draw_callback(GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
76-
obs_display_set_background_color(GetDisplay(), 0x000000);
96+
obs_display_add_draw_callback(display.GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
97+
obs_display_set_background_color(display.GetDisplay(), 0x000000);
7798
};
7899

79-
connect(this, &OBSQTDisplay::DisplayCreated, addDrawCallback);
100+
connect(&display, &OBSQTDisplay::DisplayCreated, addDrawCallback);
80101
connect(App(), &QGuiApplication::screenRemoved, this, &OBSProjector::ScreenRemoved);
81102

82103
if (type == ProjectorType::Multiview) {
@@ -95,17 +116,14 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
95116
ready = true;
96117

97118
show();
98-
99-
// We need it here to allow keyboard input in X11 to listen to Escape
100-
activateWindow();
101119
}
102120

103121
OBSProjector::~OBSProjector()
104122
{
105123
sigs.clear();
106124

107125
bool isMultiview = type == ProjectorType::Multiview;
108-
obs_display_remove_draw_callback(GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
126+
obs_display_remove_draw_callback(display.GetDisplay(), isMultiview ? OBSRenderMultiview : OBSRender, this);
109127

110128
OBSSource source = GetSource();
111129
if (source)
@@ -224,7 +242,7 @@ void OBSProjector::OBSSourceDestroyed(void *data, calldata_t *)
224242

225243
void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event)
226244
{
227-
OBSQTDisplay::mouseDoubleClickEvent(event);
245+
QWidget::mouseDoubleClickEvent(event);
228246

229247
if (!mouseSwitching)
230248
return;
@@ -253,29 +271,33 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event)
253271

254272
void OBSProjector::mousePressEvent(QMouseEvent *event)
255273
{
256-
OBSQTDisplay::mousePressEvent(event);
274+
QWidget::mousePressEvent(event);
275+
276+
QMenu popup(this);
257277

258278
if (event->button() == Qt::RightButton) {
259-
QMenu *projectorMenu = new QMenu(QTStr("Fullscreen"));
260-
OBSBasic::AddProjectorMenuMonitors(projectorMenu, this, &OBSProjector::OpenFullScreenProjector);
279+
if (!IsWayland()) {
280+
QMenu *projectorMenu = new QMenu(QTStr("Fullscreen"));
281+
OBSBasic::AddProjectorMenuMonitors(projectorMenu, this, &OBSProjector::OpenFullScreenProjector);
261282

262-
QMenu popup(this);
263-
popup.addMenu(projectorMenu);
283+
popup.addMenu(projectorMenu);
264284

265-
if (GetMonitor() > -1) {
266-
popup.addAction(QTStr("Windowed"), this, &OBSProjector::OpenWindowedProjector);
285+
if (GetMonitor() > -1)
286+
popup.addAction(QTStr("Windowed"), this, &OBSProjector::OpenWindowedProjector);
287+
}
267288

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

272-
QAction *alwaysOnTopButton = new QAction(QTStr("Basic.MainMenu.View.AlwaysOnTop"), this);
273-
alwaysOnTopButton->setCheckable(true);
274-
alwaysOnTopButton->setChecked(isAlwaysOnTop);
292+
if (!IsWayland()) {
293+
QAction *alwaysOnTopButton = new QAction(QTStr("Basic.MainMenu.AlwaysOnTop"), this);
294+
alwaysOnTopButton->setCheckable(true);
295+
alwaysOnTopButton->setChecked(isAlwaysOnTop);
275296

276-
connect(alwaysOnTopButton, &QAction::toggled, this, &OBSProjector::AlwaysOnTopToggled);
297+
connect(alwaysOnTopButton, &QAction::toggled, this, &OBSProjector::AlwaysOnTopToggled);
277298

278-
popup.addAction(alwaysOnTopButton);
299+
popup.addAction(alwaysOnTopButton);
300+
}
279301

280302
popup.addAction(QTStr("Close"), this, &OBSProjector::EscapeTriggered);
281303
popup.exec(QCursor::pos());
@@ -415,7 +437,6 @@ void OBSProjector::OpenFullScreenProjector()
415437

416438
void OBSProjector::OpenWindowedProjector()
417439
{
418-
showFullScreen();
419440
showNormal();
420441
setCursor(Qt::ArrowCursor);
421442

@@ -468,6 +489,24 @@ void OBSProjector::closeEvent(QCloseEvent *event)
468489
event->accept();
469490
}
470491

492+
bool OBSProjector::nativeEvent(const QByteArray &, void *message, qintptr *)
493+
{
494+
#ifdef _WIN32
495+
const MSG &msg = *static_cast<MSG *>(message);
496+
switch (msg.message) {
497+
case WM_MOVE:
498+
display.OnMove();
499+
break;
500+
case WM_DISPLAYCHANGE:
501+
display.OnDisplayChange();
502+
}
503+
#else
504+
UNUSED_PARAMETER(message);
505+
#endif
506+
507+
return false;
508+
}
509+
471510
bool OBSProjector::IsAlwaysOnTop() const
472511
{
473512
return isAlwaysOnTop;

frontend/widgets/OBSProjector.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ enum class ProjectorType {
1212
Multiview,
1313
};
1414

15-
class OBSProjector : public OBSQTDisplay {
15+
class QMouseEvent;
16+
17+
class OBSProjector : public QWidget {
1618
Q_OBJECT
1719

1820
private:
1921
OBSWeakSourceAutoRelease weakSource;
2022
std::vector<OBSSignal> sigs;
23+
OBSQTDisplay display;
2124

2225
static void OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy);
2326
static void OBSRender(void *data, uint32_t cx, uint32_t cy);
@@ -27,6 +30,7 @@ class OBSProjector : public OBSQTDisplay {
2730
void mousePressEvent(QMouseEvent *event) override;
2831
void mouseDoubleClickEvent(QMouseEvent *event) override;
2932
void closeEvent(QCloseEvent *event) override;
33+
virtual bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;
3034

3135
bool isAlwaysOnTop;
3236
bool isAlwaysOnTopOverridden = false;

0 commit comments

Comments
 (0)