attempt to fix timers when creating them with a valid HWND
[wxWidgets.git] / src / msw / timer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/timer.cpp
3 // Purpose: wxTimer implementation
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "timer.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_TIMER
24
25 #ifndef WX_PRECOMP
26 #include "wx/window.h"
27 #include "wx/list.h"
28 #include "wx/event.h"
29 #include "wx/app.h"
30 #include "wx/intl.h"
31 #include "wx/log.h"
32 #endif
33
34 #include "wx/hashmap.h"
35 #include "wx/module.h"
36
37 #include "wx/timer.h"
38
39 #include "wx/msw/private.h"
40
41 // from utils.cpp
42 extern "C" HWND
43 wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
44
45 // ----------------------------------------------------------------------------
46 // private functions
47 // ----------------------------------------------------------------------------
48
49 // define a hash containing all the timers: it is indexed by HWND and timer id
50 struct wxTimerKey
51 {
52 wxTimerKey(WXHWND hwnd, int id) : m_hwnd(hwnd), m_id(id) { }
53 wxTimerKey(HWND hwnd, int id) : m_hwnd((WXHWND)hwnd), m_id(id) { }
54
55 WXHWND m_hwnd;
56 int m_id;
57 };
58
59 static inline bool operator==(const wxTimerKey& tk1, const wxTimerKey& tk2)
60 {
61 return tk1.m_hwnd == tk2.m_hwnd && tk1.m_id == tk2.m_id;
62 }
63
64 struct wxTimerKeyHash
65 {
66 wxTimerKeyHash() { }
67 unsigned long operator()(const wxTimerKey& tk) const
68 { return (unsigned long)tk.m_hwnd + tk.m_id; }
69
70 wxTimerKeyHash& operator=(const wxTimerKeyHash&) { return *this; }
71 };
72
73 struct wxTimerKeyEqual
74 {
75 wxTimerKeyEqual() { }
76 bool operator()(const wxTimerKey& tk1, const wxTimerKey& tk2) const
77 { return tk1 == tk2; }
78
79 wxTimerKeyEqual& operator=(const wxTimerKeyEqual&) { return *this; }
80 };
81
82 WX_DECLARE_HASH_MAP(wxTimerKey, wxTimer *, wxTimerKeyHash, wxTimerKeyEqual,
83 wxTimerMap);
84
85 static wxTimerMap g_timerMap;
86
87 void WINAPI wxTimerProc(HWND hwnd, WORD, int idTimer, DWORD);
88
89 // ----------------------------------------------------------------------------
90 // macros
91 // ----------------------------------------------------------------------------
92
93 IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxObject)
94
95 // ----------------------------------------------------------------------------
96 // globals
97 // ----------------------------------------------------------------------------
98
99 // these variables are for timer shared hwnd management
100 static const wxChar *wxMSWTIMER_WNDCLASSNAME = wxT("_wxTimer_Internal_Class");
101 static LPCTSTR s_classnameTimerWnd = NULL;
102 static HWND s_hwndTimer = NULL;
103
104 // ----------------------------------------------------------------------------
105 // private classes
106 // ----------------------------------------------------------------------------
107
108 class wxTimerModule : public wxModule
109 {
110 public:
111 virtual bool OnInit() { return true; }
112 virtual void OnExit()
113 {
114 if ( s_hwndTimer )
115 {
116 ::DestroyWindow(s_hwndTimer);
117 s_hwndTimer = NULL;
118
119 if ( !::UnregisterClass(wxMSWTIMER_WNDCLASSNAME, wxGetInstance()) )
120 {
121 wxLogLastError(_T("UnregisterClass(wxTimerClass)"));
122 }
123
124 s_classnameTimerWnd = NULL;
125 }
126 }
127
128 private:
129 DECLARE_DYNAMIC_CLASS(wxTimerModule)
130 };
131
132 // ============================================================================
133 // implementation
134 // ============================================================================
135
136 // ----------------------------------------------------------------------------
137 // wxTimer class
138 // ----------------------------------------------------------------------------
139
140 void wxTimer::Init()
141 {
142 m_id = 0;
143 m_hwnd = NULL;
144 }
145
146 wxTimer::~wxTimer()
147 {
148 wxTimer::Stop();
149 }
150
151 bool wxTimer::Start(int milliseconds, bool oneShot)
152 {
153 (void)wxTimerBase::Start(milliseconds, oneShot);
154
155 wxCHECK_MSG( m_milli > 0, false, wxT("invalid value for timer timeour") );
156
157 // find a window for SetTimer(): it should be a valid HWND owned by this
158 // thread (even if we had a non NULL m_hwnd before, reset it in case the
159 // owner has changed)
160 m_hwnd = NULL;
161
162 // first try the owner window
163 if ( m_owner )
164 {
165 wxWindow *win = wxDynamicCast(m_owner, wxWindow);
166 if ( win )
167 {
168 m_hwnd = win->GetHWND();
169 }
170 }
171
172 // if not, use a shared hidden window
173 if ( !m_hwnd )
174 {
175 if ( !s_hwndTimer )
176 {
177 s_hwndTimer = wxCreateHiddenWindow
178 (
179 &s_classnameTimerWnd,
180 wxMSWTIMER_WNDCLASSNAME,
181 ::DefWindowProc
182 );
183
184 if ( !s_hwndTimer )
185 {
186 wxASSERT_MSG( s_hwndTimer, wxT("can't create a HWND for wxTimer") );
187 return false;
188 }
189 }
190
191 m_hwnd = (WXHWND)s_hwndTimer;
192
193 }
194
195 m_id = ::SetTimer
196 (
197 (HWND)m_hwnd,
198 (UINT)(m_id ? m_id : 1),
199 (UINT)m_milli,
200 (TIMERPROC)wxTimerProc
201 );
202
203 if ( !m_id )
204 {
205 wxLogSysError(_("Couldn't create a timer"));
206
207 return false;
208 }
209
210 g_timerMap[wxTimerKey(m_hwnd, m_id)] = this;
211
212 return true;
213 }
214
215 void wxTimer::Stop()
216 {
217 if ( m_id )
218 {
219 ::KillTimer((HWND)m_hwnd, (UINT)m_id);
220 m_hwnd = NULL;
221
222 g_timerMap.erase(wxTimerKey(m_hwnd, m_id));
223 }
224
225 m_id = 0;
226 }
227
228 // ----------------------------------------------------------------------------
229 // private functions
230 // ----------------------------------------------------------------------------
231
232 void wxProcessTimer(wxTimer& timer)
233 {
234 wxASSERT_MSG( timer.m_id != 0, _T("bogus timer id") );
235
236 if ( timer.IsOneShot() )
237 timer.Stop();
238
239 timer.Notify();
240 }
241
242 void WINAPI wxTimerProc(HWND hwnd, WORD, int idTimer, DWORD)
243 {
244 wxTimerMap::iterator node = g_timerMap.find(wxTimerKey(hwnd, idTimer));
245
246 wxCHECK_RET( node != g_timerMap.end(), wxT("bogus timer id in wxTimerProc") );
247
248 wxProcessTimer(*(node->second));
249 }
250
251 #endif // wxUSE_TIMER
252