File indexing completed on 2025-02-16 05:09:07
0001 /**************************************************************************** 0002 ** 0003 ** Copyright (C) 2018 The Qt Company Ltd. 0004 ** Contact: https://www.qt.io/licensing/ 0005 ** 0006 ** This file is part of the test suite of the Qt Toolkit. 0007 ** 0008 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ 0009 ** Commercial License Usage 0010 ** Licensees holding valid commercial Qt licenses may use this file in 0011 ** accordance with the commercial license agreement provided with the 0012 ** Software or, alternatively, in accordance with the terms contained in 0013 ** a written agreement between you and The Qt Company. For licensing terms 0014 ** and conditions see https://www.qt.io/terms-conditions. For further 0015 ** information use the contact form at https://www.qt.io/contact-us. 0016 ** 0017 ** GNU General Public License Usage 0018 ** Alternatively, this file may be used under the terms of the GNU 0019 ** General Public License version 3 as published by the Free Software 0020 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 0021 ** included in the packaging of this file. Please review the following 0022 ** information to ensure the GNU General Public License requirements will 0023 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 0024 ** 0025 ** $QT_END_LICENSE$ 0026 ** 0027 ****************************************************************************/ 0028 0029 #include "corecompositor.h" 0030 #include <thread> 0031 0032 namespace MockCompositor 0033 { 0034 CoreCompositor::CoreCompositor() 0035 : m_display(wl_display_create()) 0036 , m_socketName(wl_display_add_socket_auto(m_display)) 0037 , m_eventLoop(wl_display_get_event_loop(m_display)) 0038 0039 // Start dispatching 0040 , m_dispatchThread([this]() { 0041 while (m_running) { 0042 std::this_thread::sleep_for(std::chrono::milliseconds(20)); 0043 dispatch(); 0044 } 0045 }) 0046 { 0047 qputenv("WAYLAND_DISPLAY", m_socketName); 0048 m_timer.start(); 0049 Q_ASSERT(isClean()); 0050 } 0051 0052 CoreCompositor::~CoreCompositor() 0053 { 0054 auto global = m_globals.begin(); 0055 while (global != m_globals.end()) { 0056 delete *global; 0057 global = m_globals.erase(global); 0058 } 0059 0060 wl_display_destroy_clients(m_display); 0061 0062 m_running = false; 0063 m_dispatchThread.join(); 0064 wl_display_destroy(m_display); 0065 } 0066 0067 bool CoreCompositor::isClean() 0068 { 0069 Lock lock(this); 0070 for (auto *global : std::as_const(m_globals)) { 0071 if (!global->isClean()) 0072 return false; 0073 } 0074 return true; 0075 } 0076 0077 QString CoreCompositor::dirtyMessage() 0078 { 0079 Lock lock(this); 0080 QStringList messages; 0081 for (auto *global : std::as_const(m_globals)) { 0082 if (!global->isClean()) 0083 messages << (global->metaObject()->className() % QLatin1String(": ") % global->dirtyMessage()); 0084 } 0085 return messages.join(", "); 0086 } 0087 0088 void CoreCompositor::dispatch() 0089 { 0090 Lock lock(this); 0091 wl_display_flush_clients(m_display); 0092 constexpr int timeout = 0; // immediate return 0093 wl_event_loop_dispatch(m_eventLoop, timeout); 0094 } 0095 0096 /*! 0097 * \brief Adds a new global interface for the compositor 0098 * 0099 * Takes ownership of \a global 0100 */ 0101 void CoreCompositor::add(Global *global) 0102 { 0103 warnIfNotLockedByThread(Q_FUNC_INFO); 0104 m_globals.append(global); 0105 } 0106 0107 void CoreCompositor::remove(Global *global) 0108 { 0109 warnIfNotLockedByThread(Q_FUNC_INFO); 0110 m_globals.removeAll(global); 0111 delete global; 0112 } 0113 0114 uint CoreCompositor::nextSerial() 0115 { 0116 warnIfNotLockedByThread(Q_FUNC_INFO); 0117 return wl_display_next_serial(m_display); 0118 } 0119 0120 uint CoreCompositor::currentTimeMilliseconds() 0121 { 0122 warnIfNotLockedByThread(Q_FUNC_INFO); 0123 return uint(m_timer.elapsed()); 0124 } 0125 0126 wl_client *CoreCompositor::client(int index) 0127 { 0128 warnIfNotLockedByThread(Q_FUNC_INFO); 0129 wl_list *clients = wl_display_get_client_list(m_display); 0130 wl_client *client = nullptr; 0131 int i = 0; 0132 wl_client_for_each(client, clients) 0133 { 0134 if (i++ == index) 0135 return client; 0136 } 0137 return nullptr; 0138 } 0139 0140 void CoreCompositor::warnIfNotLockedByThread(const char *caller) 0141 { 0142 if (!m_lock || !m_lock->isOwnedByCurrentThread()) { 0143 qWarning() << caller << "called without locking the compositor to the current thread." 0144 << "This means the compositor can start dispatching at any moment," 0145 << "potentially leading to threading issues." 0146 << "Unless you know what you are doing you should probably fix the test" 0147 << "by locking the compositor before accessing it (see mutex())."; 0148 } 0149 } 0150 0151 } // namespace MockCompositor