qt-display.cpp 4.1 KB

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