Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2025 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <QTimer>
24 :
25 : #include "tickerprovider.h"
26 :
27 : using namespace muse;
28 :
29 : // heuristic value
30 : static const int ONE_TICK_INTERVAL_MS = 16;
31 :
32 46 : static uint32_t newTaskId()
33 : {
34 : static uint32_t lastId = 0;
35 46 : ++lastId;
36 46 : return lastId;
37 : }
38 :
39 46 : void TickerProvider::start()
40 : {
41 46 : m_ticks = 0;
42 46 : m_timer = std::make_shared<QTimer>();
43 46 : m_timer->setInterval(ONE_TICK_INTERVAL_MS);
44 46 : m_timer->setSingleShot(true);
45 46 : QObject::connect(m_timer.get(), &QTimer::timeout, [this]() {
46 185 : process();
47 185 : });
48 46 : m_timer->start();
49 46 : }
50 :
51 46 : void TickerProvider::stop()
52 : {
53 46 : if (m_timer) {
54 46 : m_timer->stop();
55 46 : m_timer = nullptr;
56 : }
57 46 : }
58 :
59 0 : void TickerProvider::forceSchedule()
60 : {
61 0 : if (!m_timer) {
62 0 : start();
63 0 : } else if (!m_timer->isActive()) {
64 0 : m_timer->start();
65 : }
66 0 : }
67 :
68 185 : void TickerProvider::addPending()
69 : {
70 189 : for (const auto& p : m_pendingToAdd) {
71 4 : m_tasks.insert({ p.first, p.second });
72 : }
73 185 : m_pendingToAdd.clear();
74 185 : }
75 :
76 370 : void TickerProvider::removePending()
77 : {
78 370 : for (uint32_t taskId : m_pendingToRemove) {
79 0 : auto it = m_tasks.find(taskId);
80 0 : if (it != m_tasks.end()) {
81 0 : m_tasks.erase(it);
82 : }
83 : }
84 370 : m_pendingToRemove.clear();
85 370 : }
86 :
87 185 : void TickerProvider::process()
88 : {
89 185 : addPending();
90 :
91 185 : removePending();
92 :
93 370 : for (auto& p : m_tasks) {
94 185 : Task& task = p.second;
95 185 : if (task.interval == 0 || m_ticks % task.interval == 0) {
96 185 : task.call();
97 :
98 185 : if (!task.repeat) {
99 0 : m_pendingToRemove.push_back(p.first);
100 : }
101 : }
102 : }
103 :
104 185 : removePending();
105 :
106 185 : ++m_ticks;
107 :
108 : // next iteration
109 185 : m_timer->start();
110 185 : }
111 :
112 46 : uint32_t TickerProvider::addTask(const Task& task)
113 : {
114 46 : uint32_t taskId = newTaskId();
115 46 : m_pendingToAdd.insert({ taskId, task });
116 46 : return taskId;
117 : }
118 :
119 46 : void TickerProvider::removeTask(const uint32_t& taskId)
120 : {
121 46 : m_pendingToRemove.push_back(taskId);
122 46 : }
|