1
0

qt-display.cpp 4.2 KB

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