]> git.saurik.com Git - wxWidgets.git/blob - src/msw/timer.cpp
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / msw / timer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/timer.cpp
3 // Purpose: wxTimer implementation
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin (use hash map instead of list, global rewrite)
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_TIMER
20
21 #include "wx/msw/private/timer.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/list.h"
25 #include "wx/event.h"
26 #include "wx/app.h"
27 #include "wx/intl.h"
28 #include "wx/log.h"
29 #include "wx/hashmap.h"
30 #include "wx/module.h"
31 #endif
32
33 #include "wx/msw/private.h"
34 #include "wx/msw/private/hiddenwin.h"
35
36 // ----------------------------------------------------------------------------
37 // private globals
38 // ----------------------------------------------------------------------------
39
40 // define a hash containing all the timers: it is indexed by timer id and
41 // contains the corresponding timer
42 WX_DECLARE_HASH_MAP(WPARAM, wxMSWTimerImpl *, wxIntegerHash, wxIntegerEqual,
43 wxTimerMap);
44
45 // instead of using a global here, wrap it in a static function as otherwise it
46 // could have been used before being initialized if a timer object were created
47 // globally
48 static wxTimerMap& TimerMap()
49 {
50 static wxTimerMap s_timerMap;
51
52 return s_timerMap;
53 }
54
55 // This gets a unique, non-zero timer ID and creates an entry in the TimerMap
56 UINT_PTR GetNewTimerId(wxMSWTimerImpl *t)
57 {
58 static UINT_PTR lastTimerId = 0;
59
60 while (lastTimerId == 0 ||
61 TimerMap().find(lastTimerId) != TimerMap().end())
62 {
63 lastTimerId = lastTimerId + 1;
64 }
65
66 TimerMap()[lastTimerId] = t;
67
68 return lastTimerId;
69 }
70
71
72
73 // ----------------------------------------------------------------------------
74 // private functions
75 // ----------------------------------------------------------------------------
76
77 LRESULT APIENTRY _EXPORT wxTimerWndProc(HWND hWnd, UINT message,
78 WPARAM wParam, LPARAM lParam);
79
80 // ----------------------------------------------------------------------------
81 // wxTimerHiddenWindowModule: used to manage the hidden window used for
82 // catching timer messages (we need a module to ensure that the window is
83 // always deleted)
84 // ----------------------------------------------------------------------------
85
86 class wxTimerHiddenWindowModule : public wxModule
87 {
88 public:
89 // module init/finalize
90 virtual bool OnInit();
91 virtual void OnExit();
92
93 // get the hidden window (creates on demand)
94 static HWND GetHWND();
95
96 private:
97 // the HWND of the hidden window
98 static HWND ms_hwnd;
99
100 // the class used to create it
101 static const wxChar *ms_className;
102
103 DECLARE_DYNAMIC_CLASS(wxTimerHiddenWindowModule)
104 };
105
106 IMPLEMENT_DYNAMIC_CLASS(wxTimerHiddenWindowModule, wxModule)
107
108 // ============================================================================
109 // implementation
110 // ============================================================================
111
112
113 // ----------------------------------------------------------------------------
114 // wxMSWTimerImpl class
115 // ----------------------------------------------------------------------------
116
117 bool wxMSWTimerImpl::Start(int milliseconds, bool oneShot)
118 {
119 if ( !wxTimerImpl::Start(milliseconds, oneShot) )
120 return false;
121
122 m_id = GetNewTimerId(this);
123 // SetTimer() normally returns just idTimer but this might change in the
124 // future so use its return value to be safe
125 UINT_PTR ret = ::SetTimer
126 (
127 wxTimerHiddenWindowModule::GetHWND(), // window for WM_TIMER
128 m_id, // timer ID to create
129 (UINT)m_milli, // delay
130 NULL // timer proc (unused)
131 );
132
133 if ( ret == 0 )
134 {
135 wxLogSysError(_("Couldn't create a timer"));
136
137 return false;
138 }
139
140 return true;
141 }
142
143 void wxMSWTimerImpl::Stop()
144 {
145 ::KillTimer(wxTimerHiddenWindowModule::GetHWND(), m_id);
146 TimerMap().erase(m_id);
147 m_id = 0;
148 }
149
150 // ----------------------------------------------------------------------------
151 // private functions
152 // ----------------------------------------------------------------------------
153
154 void wxProcessTimer(wxMSWTimerImpl& timer)
155 {
156 wxASSERT_MSG( timer.IsRunning(), wxT("bogus timer id") );
157
158 if ( timer.IsOneShot() )
159 timer.Stop();
160
161 timer.Notify();
162 }
163
164
165 LRESULT APIENTRY _EXPORT wxTimerWndProc(HWND hWnd, UINT message,
166 WPARAM wParam, LPARAM lParam)
167 {
168 if ( message == WM_TIMER )
169 {
170 wxTimerMap::iterator node = TimerMap().find(wParam);
171
172 if ( node != TimerMap().end() )
173 {
174 wxProcessTimer(*(node->second));
175
176 return 0;
177 }
178 //else: Unknown timer, probably one of our timers that had fired just
179 // before being removed from the timers map by Stop().
180 }
181
182 return ::DefWindowProc(hWnd, message, wParam, lParam);
183 }
184
185 // ----------------------------------------------------------------------------
186 // wxTimerHiddenWindowModule functions
187 // ----------------------------------------------------------------------------
188
189
190 HWND wxTimerHiddenWindowModule::ms_hwnd = NULL;
191
192 const wxChar *wxTimerHiddenWindowModule::ms_className = NULL;
193
194 bool wxTimerHiddenWindowModule::OnInit()
195 {
196 // do not initialize ms_hwnd to ms_className to NULL here: it may happen
197 // that our GetHWND() is called before the modules are initialized if a
198 // timer is created from wxApp-derived class ctor and in this case we
199 // shouldn't overwrite it
200
201 return true;
202 }
203
204 void wxTimerHiddenWindowModule::OnExit()
205 {
206 if ( ms_hwnd )
207 {
208 if ( !::DestroyWindow(ms_hwnd) )
209 {
210 wxLogLastError(wxT("DestroyWindow(wxTimerHiddenWindow)"));
211 }
212
213 ms_hwnd = NULL;
214 }
215
216 if ( ms_className )
217 {
218 if ( !::UnregisterClass(ms_className, wxGetInstance()) )
219 {
220 wxLogLastError(wxT("UnregisterClass(\"wxTimerHiddenWindow\")"));
221 }
222
223 ms_className = NULL;
224 }
225 }
226
227 /* static */
228 HWND wxTimerHiddenWindowModule::GetHWND()
229 {
230 static const wxChar *HIDDEN_WINDOW_CLASS = wxT("wxTimerHiddenWindow");
231 if ( !ms_hwnd )
232 {
233 ms_hwnd = wxCreateHiddenWindow(&ms_className, HIDDEN_WINDOW_CLASS,
234 wxTimerWndProc);
235 }
236
237 return ms_hwnd;
238 }
239
240 #endif // wxUSE_TIMER