qt-display.cpp 5.0 KB

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