[video] fix selection after changing video or extra art
[xbmc.git] / xbmc / messaging / ApplicationMessenger.cpp
blobd9eab6147a14c66ea6f6f5038c97fa4aac7f6c00
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "ApplicationMessenger.h"
11 #include "guilib/GUIMessage.h"
12 #include "messaging/IMessageTarget.h"
13 #include "threads/SingleLock.h"
14 #include "utils/log.h"
15 #include "windowing/GraphicContext.h"
17 #include <memory>
18 #include <mutex>
19 #include <utility>
21 namespace KODI
23 namespace MESSAGING
26 class CDelayedMessage : public CThread
28 public:
29 CDelayedMessage(const ThreadMessage& msg, unsigned int delay);
30 void Process() override;
32 private:
33 unsigned int m_delay;
34 ThreadMessage m_msg;
37 CDelayedMessage::CDelayedMessage(const ThreadMessage& msg, unsigned int delay)
38 : CThread("DelayedMessage"), m_msg(msg)
40 m_delay = delay;
43 void CDelayedMessage::Process()
45 CThread::Sleep(std::chrono::milliseconds(m_delay));
47 if (!m_bStop)
48 CServiceBroker::GetAppMessenger()->PostMsg(m_msg.dwMessage, m_msg.param1, m_msg.param1,
49 m_msg.lpVoid, m_msg.strParam, m_msg.params);
52 CApplicationMessenger::CApplicationMessenger() = default;
54 CApplicationMessenger::~CApplicationMessenger()
56 Cleanup();
59 void CApplicationMessenger::Cleanup()
61 std::unique_lock<CCriticalSection> lock(m_critSection);
63 while (!m_vecMessages.empty())
65 ThreadMessage* pMsg = m_vecMessages.front();
67 if (pMsg->waitEvent)
68 pMsg->waitEvent->Set();
70 delete pMsg;
71 m_vecMessages.pop();
74 while (!m_vecWindowMessages.empty())
76 ThreadMessage* pMsg = m_vecWindowMessages.front();
78 if (pMsg->waitEvent)
79 pMsg->waitEvent->Set();
81 delete pMsg;
82 m_vecWindowMessages.pop();
86 int CApplicationMessenger::SendMsg(ThreadMessage&& message, bool wait)
88 std::shared_ptr<CEvent> waitEvent;
89 std::shared_ptr<int> result;
91 if (wait)
93 //Initialize result here as it's not needed for posted messages
94 message.result = std::make_shared<int>(-1);
95 // check that we're not being called from our application thread, else we'll be waiting
96 // forever!
97 if (m_guiThreadId != CThread::GetCurrentThreadId())
99 message.waitEvent = std::make_shared<CEvent>(true);
100 waitEvent = message.waitEvent;
101 result = message.result;
103 else
105 //OutputDebugString("Attempting to wait on a SendMessage() from our application thread will cause lockup!\n");
106 //OutputDebugString("Sending immediately\n");
107 ProcessMessage(&message);
108 return *message.result;
113 if (m_bStop)
114 return -1;
116 ThreadMessage* msg = new ThreadMessage(std::move(message));
118 std::unique_lock<CCriticalSection> lock(m_critSection);
120 if (msg->dwMessage == TMSG_GUI_MESSAGE)
121 m_vecWindowMessages.push(msg);
122 else
123 m_vecMessages.push(msg);
124 lock.unlock(); // this releases the lock on the vec of messages and
125 // allows the ProcessMessage to execute and therefore
126 // delete the message itself. Therefore any access
127 // of the message itself after this point constitutes
128 // a race condition (yarc - "yet another race condition")
130 if (waitEvent) // ... it just so happens we have a spare reference to the
131 // waitEvent ... just for such contingencies :)
133 // ensure the thread doesn't hold the graphics lock
134 CWinSystemBase* winSystem = CServiceBroker::GetWinSystem();
135 //! @todo This won't really help as winSystem can die every single
136 // moment on shutdown. A shared ptr would be a more valid solution
137 // depending on the design dependencies.
138 if (winSystem)
140 CSingleExit exit(winSystem->GetGfxContext());
141 waitEvent->Wait();
143 return *result;
146 return -1;
149 int CApplicationMessenger::SendMsg(uint32_t messageId)
151 return SendMsg(ThreadMessage{ messageId }, true);
154 int CApplicationMessenger::SendMsg(uint32_t messageId, int param1, int param2, void* payload)
156 return SendMsg(ThreadMessage{ messageId, param1, param2, payload }, true);
159 int CApplicationMessenger::SendMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam)
161 return SendMsg(ThreadMessage{messageId, param1, param2, payload, std::move(strParam),
162 std::vector<std::string>{}},
163 true);
166 int CApplicationMessenger::SendMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam, std::vector<std::string> params)
168 return SendMsg(
169 ThreadMessage{messageId, param1, param2, payload, std::move(strParam), std::move(params)},
170 true);
173 void CApplicationMessenger::PostMsg(uint32_t messageId)
175 SendMsg(ThreadMessage{ messageId }, false);
178 void CApplicationMessenger::PostMsg(uint32_t messageId, int64_t param3)
180 SendMsg(ThreadMessage{ messageId, param3 }, false);
183 void CApplicationMessenger::PostMsg(uint32_t messageId, int param1, int param2, void* payload)
185 SendMsg(ThreadMessage{ messageId, param1, param2, payload }, false);
188 void CApplicationMessenger::PostMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam)
190 SendMsg(ThreadMessage{messageId, param1, param2, payload, std::move(strParam),
191 std::vector<std::string>{}},
192 false);
195 void CApplicationMessenger::PostMsg(uint32_t messageId, int param1, int param2, void* payload, std::string strParam, std::vector<std::string> params)
197 SendMsg(ThreadMessage{messageId, param1, param2, payload, std::move(strParam), std::move(params)},
198 false);
201 void CApplicationMessenger::ProcessMessages()
203 // process threadmessages
204 std::unique_lock<CCriticalSection> lock(m_critSection);
205 while (!m_vecMessages.empty())
207 ThreadMessage* pMsg = m_vecMessages.front();
208 //first remove the message from the queue, else the message could be processed more then once
209 m_vecMessages.pop();
211 //Leave here as the message might make another
212 //thread call processmessages or sendmessage
214 std::shared_ptr<CEvent> waitEvent = pMsg->waitEvent;
215 lock.unlock(); // <- see the large comment in SendMessage ^
217 ProcessMessage(pMsg);
219 if (waitEvent)
220 waitEvent->Set();
221 delete pMsg;
223 lock.lock();
227 void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
229 //special case for this that we handle ourselves
230 if (pMsg->dwMessage == TMSG_CALLBACK)
232 ThreadMessageCallback *callback = static_cast<ThreadMessageCallback*>(pMsg->lpVoid);
233 callback->callback(callback->userptr);
234 return;
237 std::unique_lock<CCriticalSection> lock(m_critSection);
238 int mask = pMsg->dwMessage & TMSG_MASK_MESSAGE;
240 const auto it = m_mapTargets.find(mask);
241 if (it != m_mapTargets.end())
243 CSingleExit exit(m_critSection);
244 it->second->OnApplicationMessage(pMsg);
246 else
247 CLog::LogF(LOGERROR, "receiver {} is not defined", mask);
250 void CApplicationMessenger::ProcessWindowMessages()
252 std::unique_lock<CCriticalSection> lock(m_critSection);
253 //message type is window, process window messages
254 while (!m_vecWindowMessages.empty())
256 ThreadMessage* pMsg = m_vecWindowMessages.front();
257 //first remove the message from the queue, else the message could be processed more then once
258 m_vecWindowMessages.pop();
260 // leave here in case we make more thread messages from this one
262 std::shared_ptr<CEvent> waitEvent = pMsg->waitEvent;
263 lock.unlock(); // <- see the large comment in SendMessage ^
265 ProcessMessage(pMsg);
266 if (waitEvent)
267 waitEvent->Set();
268 delete pMsg;
270 lock.lock();
274 void CApplicationMessenger::SendGUIMessage(const CGUIMessage &message, int windowID, bool waitResult)
276 ThreadMessage tMsg(TMSG_GUI_MESSAGE);
277 tMsg.param1 = windowID == WINDOW_INVALID ? 0 : windowID;
278 tMsg.lpVoid = new CGUIMessage(message);
279 SendMsg(std::move(tMsg), waitResult);
282 void CApplicationMessenger::RegisterReceiver(IMessageTarget* target)
284 std::unique_lock<CCriticalSection> lock(m_critSection);
285 m_mapTargets.insert(std::make_pair(target->GetMessageMask(), target));
288 bool CApplicationMessenger::IsProcessThread() const
290 return m_processThreadId == CThread::GetCurrentThreadId();