soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SMsgLoop.cpp
1#include "souistd.h"
2#include "core/SMsgLoop.h"
3
4#ifndef WM_SYSTIMER
5#define WM_SYSTIMER 0x0118 //(caret blink)
6#endif // WM_SYSTIMER
7
8SNSBEGIN
9
10template <class T>
11BOOL RemoveElementFromArray(SArray<T> &arr, T ele)
12{
13 int idx = arr.Find(ele);
14 if (idx == -1)
15 return FALSE;
16 arr.RemoveAt(idx);
17 return TRUE;
18}
19
20class SMessageLoopPriv {
21 public:
22 SMessageLoopPriv(IMessageLoop *pParentLoop = NULL)
23 : m_parentLoop(pParentLoop)
24 {
25 }
26 SArray<IMsgFilter *> m_aMsgFilter;
27 SArray<IIdleHandler *> m_aIdleHandler;
28 SList<IRunnable *> m_runnables;
29 SList<IRunnable *> m_runningQueue;
30 SAutoRefPtr<IMessageLoop> m_parentLoop;
31};
32
34 : m_bRunning(FALSE)
35 , m_tid(0)
36 , m_bQuit(FALSE)
37 , m_bDoIdle(FALSE)
38 , m_nIdleCount(0)
39{
40 m_priv = new SMessageLoopPriv(pParentLoop);
41}
42
44{
45 delete m_priv;
46}
47
48void SMessageLoop::OnMsg(LPMSG pMsg)
49{
50 if (!PreTranslateMessage(pMsg))
51 {
52 ::TranslateMessage(pMsg);
53 ::DispatchMessage(pMsg);
54 }
55}
56
57void SMessageLoop::Quit(int exitCode)
58{
59 if (!m_bRunning)
60 return;
61 PostThreadMessage(m_tid, WM_QUIT, (WPARAM)exitCode, 0);
62}
63
65{
66 m_bRunning = TRUE;
67 m_bDoIdle = TRUE;
68 m_nIdleCount = 0;
69 m_tid = GetCurrentThreadId();
70 m_bQuit = FALSE;
71 int nRet = 0;
72 do
73 {
74 BOOL bGetMsg = WaitMsg();
75 if (m_bQuit)
76 break;
77 if (!bGetMsg)
78 {
79 SSLOGD() << "WaitMsg returned FALSE (error)";
80 continue; // error, don't process
81 }
82 nRet = HandleMsg();
83 } while (!m_bQuit);
84
85 {
86 SAutoLock lock(m_cs);
87 SPOSITION pos = m_priv->m_runnables.GetHeadPosition();
88 while (pos)
89 {
90 IRunnable *pRunnable = m_priv->m_runnables.GetNext(pos);
91 pRunnable->Release();
92 }
93 m_priv->m_runnables.RemoveAll();
94 }
95 m_bRunning = FALSE;
96 return nRet;
97}
98
99BOOL SMessageLoop::OnIdle(int nIdleCount)
100{
101 BOOL bContinue = !m_priv->m_aIdleHandler.IsEmpty();
102
103 for (size_t i = 0; i < m_priv->m_aIdleHandler.GetCount(); i++)
104 {
105 IIdleHandler *pIdleHandler = m_priv->m_aIdleHandler[i];
106 if (!pIdleHandler->OnIdle())
107 bContinue = FALSE;
108 }
109 if (m_priv->m_parentLoop)
110 {
111 if (!m_priv->m_parentLoop->OnIdle(nIdleCount))
112 bContinue = FALSE;
113 }
114 return bContinue;
115}
116
118{
119 // loop backwards
120 for (int i = (int)m_priv->m_aMsgFilter.GetCount() - 1; i >= 0; i--)
121 {
122 IMsgFilter *pMessageFilter = m_priv->m_aMsgFilter[i];
123 if (pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg))
124 return TRUE;
125 }
126 if (m_priv->m_parentLoop)
127 {
128 m_priv->m_parentLoop->PreTranslateMessage(pMsg);
129 }
130 return FALSE; // not translated
131}
132
134{
135 // These messages should NOT cause idle processing
136 switch (pMsg->message)
137 {
138 case WM_MOUSEMOVE:
139 case WM_NCMOUSEMOVE:
140 case WM_PAINT:
141 case WM_SYSTIMER: // WM_SYSTIMER (caret blink)
142 return FALSE;
143 }
144
145 return TRUE;
146}
147
149{
150 if (!pIdleHandler)
151 return FALSE;
152 return RemoveElementFromArray(m_priv->m_aIdleHandler, pIdleHandler);
153}
154
156{
157 if (!pIdleHandler)
158 return FALSE;
159 m_priv->m_aIdleHandler.Add(pIdleHandler);
160 return TRUE;
161}
162
164{
165 return RemoveElementFromArray(m_priv->m_aMsgFilter, pMessageFilter);
166}
167
169{
170 m_priv->m_aMsgFilter.Add(pMessageFilter);
171 return TRUE;
172}
173
174BOOL SMessageLoop::PostTask(IRunnable *runable)
175{
176 SAutoLock lock(m_cs);
177 if (m_tid == 0)
178 {
179 SSLOGW() << "msg loop not running now! pending task size:" << m_priv->m_runnables.GetCount();
180 }
181 m_priv->m_runnables.AddTail(runable->clone());
182 if (m_priv->m_runnables.GetCount() > 5)
183 {
184 PostThreadMessage(m_tid, WM_NULL, 0, 0);
185 }
186 return TRUE;
187}
188
190{
191 int nRet = 0;
192 SAutoLock lock(m_cs);
193 SPOSITION pos = m_priv->m_runnables.GetHeadPosition();
194 while (pos)
195 {
196 SPOSITION pos2 = pos;
197 IRunnable *p = m_priv->m_runnables.GetNext(pos);
198 if (p->getObject() == pObj)
199 {
200 p->Release();
201 m_priv->m_runnables.RemoveAt(pos2);
202 nRet++;
203 }
204 }
205 SAutoLock lock2(m_csRunningQueue);
206 pos = m_priv->m_runningQueue.GetHeadPosition();
207 while (pos)
208 {
209 SPOSITION pos2 = pos;
210 IRunnable *p = m_priv->m_runningQueue.GetNext(pos);
211 if (p->getObject() == pObj)
212 {
213 p->Release();
214 m_priv->m_runningQueue.RemoveAt(pos2);
215 nRet++;
216 }
217 }
218 return nRet;
219}
220
222{
223 return m_bRunning;
224}
225
227{
228 m_cs.Enter();
229 m_priv->m_runningQueue.Swap(m_priv->m_runnables);
230 m_cs.Leave();
231 for (;;)
232 {
233 SAutoLock lock(m_csRunningQueue);
234 if (m_priv->m_runningQueue.IsEmpty())
235 break;
236 IRunnable *pRunnable = m_priv->m_runningQueue.GetHead();
237 m_priv->m_runningQueue.RemoveHead();
238 pRunnable->run();
239 pRunnable->Release();
240 }
241 if (m_priv->m_parentLoop)
242 {
243 m_priv->m_parentLoop->ExecutePendingTask();
244 }
245}
246
247BOOL SMessageLoop::PeekMsg(THIS_ LPMSG pMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, BOOL bRemove)
248{
249 return ::PeekMessage(pMsg, 0, wMsgFilterMin, wMsgFilterMax, bRemove ? PM_REMOVE : PM_NOREMOVE);
250}
251
253{
254 MSG msg;
255 while (!m_bQuit && m_bDoIdle && !PeekMsg(&msg, 0, 0, FALSE))
256 {
257 m_bDoIdle = OnIdle(m_nIdleCount++);
258 }
259}
260
262{
263 RunIdle();
264 if (m_bQuit)
265 return FALSE;
266 return ::WaitMessage();
267}
268
270{
271 MSG msg = { 0 };
272 while (PeekMsg(&msg, 0, 0, TRUE) && !m_bQuit)
273 {
274 if (msg.message == WM_QUIT)
275 {
276 m_bQuit = TRUE;
277 break;
278 }
280 OnMsg(&msg);
281 m_bDoIdle = IsIdleMessage(&msg);
282 if (m_bDoIdle)
283 {
284 m_nIdleCount = 0;
285 }
286 }
287 return (int)msg.wParam;
288}
289
290SNSEND
Auto-lock class for managing critical sections.
BOOL PostTask(IRunnable *runable) OVERRIDE
Posts a task to the message loop.
Definition SMsgLoop.cpp:174
int HandleMsg() OVERRIDE
Handles a message from the message queue.
Definition SMsgLoop.cpp:269
static BOOL IsIdleMessage(MSG *pMsg)
Checks if a message is an idle message.
Definition SMsgLoop.cpp:133
BOOL PeekMsg(LPMSG pMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, BOOL bRemove) OVERRIDE
Peeks at a message in the message queue without removing it.
Definition SMsgLoop.cpp:247
void ExecutePendingTask() OVERRIDE
Executes all pending tasks.
Definition SMsgLoop.cpp:226
void OnMsg(LPMSG pMsg) OVERRIDE
Processes a single message.
Definition SMsgLoop.cpp:48
BOOL RemoveMessageFilter(IMsgFilter *pMessageFilter) OVERRIDE
Removes a message filter from the message loop.
Definition SMsgLoop.cpp:163
virtual ~SMessageLoop()
Destructor for SMessageLoop.
Definition SMsgLoop.cpp:43
BOOL PreTranslateMessage(MSG *pMsg) OVERRIDE
Pre-translates a message before it is dispatched.
Definition SMsgLoop.cpp:117
BOOL RemoveIdleHandler(IIdleHandler *pIdleHandler) OVERRIDE
Removes an idle handler from the message loop.
Definition SMsgLoop.cpp:148
BOOL OnIdle(int nIdleCount) OVERRIDE
Handles idle processing.
Definition SMsgLoop.cpp:99
void RunIdle()
Runs idle processing.
Definition SMsgLoop.cpp:252
int Run() OVERRIDE
Runs the message loop.
Definition SMsgLoop.cpp:64
BOOL AddIdleHandler(IIdleHandler *pIdleHandler) OVERRIDE
Adds an idle handler to the message loop.
Definition SMsgLoop.cpp:155
BOOL IsRunning() const OVERRIDE
Checks if the message loop is running.
Definition SMsgLoop.cpp:221
BOOL AddMessageFilter(IMsgFilter *pMessageFilter) OVERRIDE
Adds a message filter to the message loop.
Definition SMsgLoop.cpp:168
BOOL WaitMsg() OVERRIDE
Waits for a message in the message queue.
Definition SMsgLoop.cpp:261
int RemoveTasksForObject(void *pObj) OVERRIDE
Removes all tasks associated with a specific object.
Definition SMsgLoop.cpp:189
void Quit(int exitCode) OVERRIDE
Quits the message loop.
Definition SMsgLoop.cpp:57
SMessageLoop(IMessageLoop *pParentLoop)
Constructor for SMessageLoop.
Definition SMsgLoop.cpp:33
Interface for handling idle time.
Definition SMsgLoop-i.h:29
BOOL OnIdle() PURE
Handles idle time.
Interface for message loops.
Definition SMsgLoop-i.h:42
Interface for message filtering.
Definition SMsgLoop-i.h:15
BOOL PreTranslateMessage(MSG *pMsg) PURE
Preprocesses a message.