test_main.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "tests/test_main.h"
  8. #include "base/invoke_queued.h"
  9. #include "base/integration.h"
  10. #include "ui/effects/animations.h"
  11. #include "ui/widgets/rp_window.h"
  12. #include "ui/emoji_config.h"
  13. #include "ui/painter.h"
  14. #include <QApplication>
  15. #include <QAbstractNativeEventFilter>
  16. #include <QScreen>
  17. #include <QThread>
  18. #include <QDir>
  19. #include <qpa/qplatformscreen.h>
  20. namespace Test {
  21. bool App::notifyOrInvoke(QObject *receiver, QEvent *e) {
  22. if (e->type() == base::InvokeQueuedEvent::Type()) {
  23. static_cast<base::InvokeQueuedEvent*>(e)->invoke();
  24. return true;
  25. }
  26. return QApplication::notify(receiver, e);
  27. }
  28. bool App::nativeEventFilter(
  29. const QByteArray &eventType,
  30. void *message,
  31. native_event_filter_result *result) {
  32. registerEnterFromEventLoop();
  33. return false;
  34. }
  35. void App::checkForEmptyLoopNestingLevel() {
  36. // _loopNestingLevel == _eventNestingLevel means that we had a
  37. // native event in a nesting loop that didn't get a notify() call
  38. // after. That means we already have exited the nesting loop and
  39. // there must not be any postponed calls with that nesting level.
  40. if (_loopNestingLevel == _eventNestingLevel) {
  41. Assert(_postponedCalls.empty()
  42. || _postponedCalls.back().loopNestingLevel < _loopNestingLevel);
  43. Assert(!_previousLoopNestingLevels.empty());
  44. _loopNestingLevel = _previousLoopNestingLevels.back();
  45. _previousLoopNestingLevels.pop_back();
  46. }
  47. }
  48. void App::postponeCall(FnMut<void()> &&callable) {
  49. Expects(callable != nullptr);
  50. Expects(_eventNestingLevel >= _loopNestingLevel);
  51. checkForEmptyLoopNestingLevel();
  52. _postponedCalls.push_back({
  53. _loopNestingLevel,
  54. std::move(callable)
  55. });
  56. }
  57. void App::processPostponedCalls(int level) {
  58. while (!_postponedCalls.empty()) {
  59. auto &last = _postponedCalls.back();
  60. if (last.loopNestingLevel != level) {
  61. break;
  62. }
  63. auto taken = std::move(last);
  64. _postponedCalls.pop_back();
  65. taken.callable();
  66. }
  67. }
  68. void App::incrementEventNestingLevel() {
  69. ++_eventNestingLevel;
  70. }
  71. void App::decrementEventNestingLevel() {
  72. Expects(_eventNestingLevel >= _loopNestingLevel);
  73. if (_eventNestingLevel == _loopNestingLevel) {
  74. _loopNestingLevel = _previousLoopNestingLevels.back();
  75. _previousLoopNestingLevels.pop_back();
  76. }
  77. const auto processTillLevel = _eventNestingLevel - 1;
  78. processPostponedCalls(processTillLevel);
  79. checkForEmptyLoopNestingLevel();
  80. _eventNestingLevel = processTillLevel;
  81. Ensures(_eventNestingLevel >= _loopNestingLevel);
  82. }
  83. void App::registerEnterFromEventLoop() {
  84. Expects(_eventNestingLevel >= _loopNestingLevel);
  85. if (_eventNestingLevel > _loopNestingLevel) {
  86. _previousLoopNestingLevels.push_back(_loopNestingLevel);
  87. _loopNestingLevel = _eventNestingLevel;
  88. }
  89. }
  90. bool App::notify(QObject *receiver, QEvent *e) {
  91. if (QThread::currentThreadId() != _mainThreadId) {
  92. return notifyOrInvoke(receiver, e);
  93. }
  94. const auto wrap = createEventNestingLevel();
  95. if (e->type() == QEvent::UpdateRequest) {
  96. const auto weak = QPointer<QObject>(receiver);
  97. _widgetUpdateRequests.fire({});
  98. if (!weak) {
  99. return true;
  100. }
  101. }
  102. return notifyOrInvoke(receiver, e);
  103. }
  104. rpl::producer<> App::widgetUpdateRequests() const {
  105. return _widgetUpdateRequests.events();
  106. }
  107. void BaseIntegration::enterFromEventLoop(FnMut<void()> &&method) {
  108. app().customEnterFromEventLoop(std::move(method));
  109. }
  110. bool BaseIntegration::logSkipDebug() {
  111. return true;
  112. }
  113. void BaseIntegration::logMessageDebug(const QString &message) {
  114. }
  115. void BaseIntegration::logMessage(const QString &message) {
  116. }
  117. void UiIntegration::postponeCall(FnMut<void()> &&callable) {
  118. app().postponeCall(std::move(callable));
  119. }
  120. void UiIntegration::registerLeaveSubscription(not_null<QWidget*> widget) {
  121. }
  122. void UiIntegration::unregisterLeaveSubscription(not_null<QWidget*> widget) {
  123. }
  124. QString UiIntegration::emojiCacheFolder() {
  125. return QDir().currentPath() + "/tests/" + name() + "/emoji";
  126. }
  127. QString UiIntegration::openglCheckFilePath() {
  128. return QDir().currentPath() + "/tests/" + name() + "/opengl";
  129. }
  130. QString UiIntegration::angleBackendFilePath() {
  131. return QDir().currentPath() + "/test/" + name() + "/angle";
  132. }
  133. } // namespace Test
  134. int main(int argc, char *argv[]) {
  135. using namespace Test;
  136. auto app = App(argc, argv);
  137. app.installNativeEventFilter(&app);
  138. const auto ratio = app.devicePixelRatio();
  139. const auto useRatio = std::clamp(qCeil(ratio), 1, 3);
  140. style::SetDevicePixelRatio(useRatio);
  141. const auto screen = App::primaryScreen();
  142. const auto dpi = screen->logicalDotsPerInch();
  143. const auto basePair = screen->handle()->logicalBaseDpi();
  144. const auto baseMiddle = (basePair.first + basePair.second) * 0.5;
  145. const auto screenExact = dpi / baseMiddle;
  146. const auto screenScale = int(base::SafeRound(screenExact * 20)) * 5;
  147. const auto chosen = std::clamp(
  148. screenScale,
  149. style::kScaleMin,
  150. style::MaxScaleForRatio(useRatio));
  151. BaseIntegration base(argc, argv);
  152. base::Integration::Set(&base);
  153. UiIntegration ui;
  154. Ui::Integration::Set(&ui);
  155. InvokeQueued(&app, [=] {
  156. new Ui::Animations::Manager();
  157. style::StartManager(chosen);
  158. Ui::Emoji::Init();
  159. const auto window = new Ui::RpWindow();
  160. window->setGeometry(
  161. { scale(100), scale(100), scale(800), scale(600) });
  162. window->show();
  163. window->setMinimumSize({ scale(240), scale(320) });
  164. test(window, window->body());
  165. });
  166. return app.exec();
  167. }
  168. namespace crl {
  169. rpl::producer<> on_main_update_requests() {
  170. return Test::app().widgetUpdateRequests();
  171. }
  172. } // namespace crl