1
0

qt-display.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include "qt-display.hpp"
  2. #include "qt-wrappers.hpp"
  3. #include "display-helpers.hpp"
  4. #include <QWindow>
  5. #include <QScreen>
  6. #include <QResizeEvent>
  7. #include <QShowEvent>
  8. #include <obs-config.h>
  9. #ifdef _WIN32
  10. #define WIN32_LEAN_AND_MEAN
  11. #include <Windows.h>
  12. #endif
  13. #ifdef ENABLE_WAYLAND
  14. #include <obs-nix-platform.h>
  15. class SurfaceEventFilter : public QObject {
  16. OBSQTDisplay *display;
  17. int mTimerId;
  18. public:
  19. SurfaceEventFilter(OBSQTDisplay *src) : display(src), mTimerId(0) {}
  20. protected:
  21. bool eventFilter(QObject *obj, QEvent *event) override
  22. {
  23. bool result = QObject::eventFilter(obj, event);
  24. QPlatformSurfaceEvent *surfaceEvent;
  25. switch (event->type()) {
  26. case QEvent::PlatformSurface:
  27. surfaceEvent =
  28. static_cast<QPlatformSurfaceEvent *>(event);
  29. if (surfaceEvent->surfaceEventType() !=
  30. QPlatformSurfaceEvent::SurfaceCreated)
  31. return result;
  32. if (display->windowHandle()->isExposed())
  33. createOBSDisplay();
  34. else
  35. mTimerId = startTimer(67); // Arbitrary
  36. break;
  37. case QEvent::Expose:
  38. createOBSDisplay();
  39. break;
  40. default:
  41. break;
  42. }
  43. return result;
  44. }
  45. void timerEvent(QTimerEvent *) { createOBSDisplay(true); }
  46. private:
  47. void createOBSDisplay(bool force = false)
  48. {
  49. display->CreateDisplay(force);
  50. if (mTimerId > 0) {
  51. killTimer(mTimerId);
  52. mTimerId = 0;
  53. }
  54. }
  55. };
  56. #endif
  57. static inline long long color_to_int(const QColor &color)
  58. {
  59. auto shift = [&](unsigned val, int shift) {
  60. return ((val & 0xff) << shift);
  61. };
  62. return shift(color.red(), 0) | shift(color.green(), 8) |
  63. shift(color.blue(), 16) | shift(color.alpha(), 24);
  64. }
  65. static inline QColor rgba_to_color(uint32_t rgba)
  66. {
  67. return QColor::fromRgb(rgba & 0xFF, (rgba >> 8) & 0xFF,
  68. (rgba >> 16) & 0xFF, (rgba >> 24) & 0xFF);
  69. }
  70. OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
  71. : QWidget(parent, flags)
  72. {
  73. setAttribute(Qt::WA_PaintOnScreen);
  74. setAttribute(Qt::WA_StaticContents);
  75. setAttribute(Qt::WA_NoSystemBackground);
  76. setAttribute(Qt::WA_OpaquePaintEvent);
  77. setAttribute(Qt::WA_DontCreateNativeAncestors);
  78. setAttribute(Qt::WA_NativeWindow);
  79. auto windowVisible = [this](bool visible) {
  80. if (!visible) {
  81. #if !defined(_WIN32) && !defined(__APPLE__)
  82. display = nullptr;
  83. #endif
  84. return;
  85. }
  86. if (!display) {
  87. CreateDisplay();
  88. } else {
  89. QSize size = GetPixelSize(this);
  90. obs_display_resize(display, size.width(),
  91. size.height());
  92. }
  93. };
  94. auto screenChanged = [this](QScreen *) {
  95. CreateDisplay();
  96. QSize size = GetPixelSize(this);
  97. obs_display_resize(display, size.width(), size.height());
  98. };
  99. connect(windowHandle(), &QWindow::visibleChanged, windowVisible);
  100. connect(windowHandle(), &QWindow::screenChanged, screenChanged);
  101. #ifdef ENABLE_WAYLAND
  102. if (obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND)
  103. windowHandle()->installEventFilter(
  104. new SurfaceEventFilter(this));
  105. #endif
  106. }
  107. QColor OBSQTDisplay::GetDisplayBackgroundColor() const
  108. {
  109. return rgba_to_color(backgroundColor);
  110. }
  111. void OBSQTDisplay::SetDisplayBackgroundColor(const QColor &color)
  112. {
  113. uint32_t newBackgroundColor = (uint32_t)color_to_int(color);
  114. if (newBackgroundColor != backgroundColor) {
  115. backgroundColor = newBackgroundColor;
  116. UpdateDisplayBackgroundColor();
  117. }
  118. }
  119. void OBSQTDisplay::UpdateDisplayBackgroundColor()
  120. {
  121. obs_display_set_background_color(display, backgroundColor);
  122. }
  123. void OBSQTDisplay::CreateDisplay(bool force)
  124. {
  125. if (display)
  126. return;
  127. if (!windowHandle()->isExposed() && !force)
  128. return;
  129. QSize size = GetPixelSize(this);
  130. gs_init_data info = {};
  131. info.cx = size.width();
  132. info.cy = size.height();
  133. info.format = GS_BGRA;
  134. info.zsformat = GS_ZS_NONE;
  135. if (!QTToGSWindow(windowHandle(), info.window))
  136. return;
  137. display = obs_display_create(&info, backgroundColor);
  138. emit DisplayCreated(this);
  139. }
  140. void OBSQTDisplay::paintEvent(QPaintEvent *event)
  141. {
  142. CreateDisplay();
  143. QWidget::paintEvent(event);
  144. }
  145. void OBSQTDisplay::moveEvent(QMoveEvent *event)
  146. {
  147. QWidget::moveEvent(event);
  148. OnMove();
  149. }
  150. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  151. bool OBSQTDisplay::nativeEvent(const QByteArray &, void *message, qintptr *)
  152. #else
  153. bool OBSQTDisplay::nativeEvent(const QByteArray &, void *message, long *)
  154. #endif
  155. {
  156. #ifdef _WIN32
  157. const MSG &msg = *static_cast<MSG *>(message);
  158. switch (msg.message) {
  159. case WM_DISPLAYCHANGE:
  160. OnDisplayChange();
  161. }
  162. #endif
  163. return false;
  164. }
  165. void OBSQTDisplay::resizeEvent(QResizeEvent *event)
  166. {
  167. QWidget::resizeEvent(event);
  168. CreateDisplay();
  169. if (isVisible() && display) {
  170. QSize size = GetPixelSize(this);
  171. obs_display_resize(display, size.width(), size.height());
  172. }
  173. emit DisplayResized();
  174. }
  175. QPaintEngine *OBSQTDisplay::paintEngine() const
  176. {
  177. return nullptr;
  178. }
  179. void OBSQTDisplay::OnMove() {}
  180. void OBSQTDisplay::OnDisplayChange() {}