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)
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
21 #include "wx/msw/private/timer.h"
29 #include "wx/hashmap.h"
30 #include "wx/module.h"
33 #include "wx/msw/private.h"
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
39 // define a hash containing all the timers: it is indexed by timer id and
40 // contains the corresponding timer
41 WX_DECLARE_HASH_MAP(WPARAM
, wxMSWTimerImpl
*, wxIntegerHash
, wxIntegerEqual
,
44 // instead of using a global here, wrap it in a static function as otherwise it
45 // could have been used before being initialized if a timer object were created
47 static wxTimerMap
& TimerMap()
49 static wxTimerMap s_timerMap
;
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 LRESULT APIENTRY _EXPORT
wxTimerWndProc(HWND hWnd
, UINT message
,
59 WPARAM wParam
, LPARAM lParam
);
61 // implemented in utils.cpp
62 extern "C" WXDLLIMPEXP_BASE HWND
63 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
66 // ----------------------------------------------------------------------------
67 // wxTimerHiddenWindowModule: used to manage the hidden window used for
68 // catching timer messages (we need a module to ensure that the window is
70 // ----------------------------------------------------------------------------
72 class wxTimerHiddenWindowModule
: public wxModule
75 // module init/finalize
76 virtual bool OnInit();
77 virtual void OnExit();
79 // get the hidden window (creates on demand)
80 static HWND
GetHWND();
83 // the HWND of the hidden window
86 // the class used to create it
87 static const wxChar
*ms_className
;
89 DECLARE_DYNAMIC_CLASS(wxTimerHiddenWindowModule
)
92 IMPLEMENT_DYNAMIC_CLASS(wxTimerHiddenWindowModule
, wxModule
)
94 // ============================================================================
96 // ============================================================================
99 // ----------------------------------------------------------------------------
100 // wxMSWTimerImpl class
101 // ----------------------------------------------------------------------------
103 bool wxMSWTimerImpl::Start(int milliseconds
, bool oneShot
)
105 if ( !wxTimerImpl::Start(milliseconds
, oneShot
) )
108 // SetTimer() doesn't accept 0 timer id so use something else if the timer
109 // id at wx level is 0: as -1 (wxID_ANY) can't be used, we can safely
110 // replace 0 with it at MSW level
111 UINT idTimer
= GetId();
115 // SetTimer() normally returns just idTimer but this might change in the
116 // future so use its return value to be safe
119 wxTimerHiddenWindowModule::GetHWND(), // window for WM_TIMER
120 idTimer
, // timer ID to create
121 (UINT
)m_milli
, // delay
122 NULL
// timer proc (unused)
127 wxLogSysError(_("Couldn't create a timer"));
132 // check that SetTimer() didn't reuse an existing id: according to the MSDN
133 // this can happen and this would be catastrophic to us as we rely on ids
134 // uniquely identifying the timers because we use them as keys in the hash
136 // notice that this also happens if the same id is reused for multiple
137 // timers: this used to work in previous versions but was never supported
138 // and absolutely shouldn't be done, use wxID_ANY to assign an id to the
139 // timer automatically or ensure that all your timers have unique ids
140 if ( TimerMap().find(m_id
) != TimerMap().end() )
142 wxLogError(_("Timer creation failed."));
144 ::KillTimer(wxTimerHiddenWindowModule::GetHWND(), m_id
);
150 TimerMap()[m_id
] = this;
155 void wxMSWTimerImpl::Stop()
157 wxASSERT_MSG( m_id
, wxT("should be running") );
159 ::KillTimer(wxTimerHiddenWindowModule::GetHWND(), m_id
);
161 TimerMap().erase(m_id
);
166 // ----------------------------------------------------------------------------
168 // ----------------------------------------------------------------------------
170 void wxProcessTimer(wxMSWTimerImpl
& timer
)
172 wxASSERT_MSG( timer
.IsRunning(), wxT("bogus timer id") );
174 if ( timer
.IsOneShot() )
181 LRESULT APIENTRY _EXPORT
wxTimerWndProc(HWND hWnd
, UINT message
,
182 WPARAM wParam
, LPARAM lParam
)
184 if ( message
== WM_TIMER
)
186 wxTimerMap::iterator node
= TimerMap().find(wParam
);
188 wxCHECK_MSG( node
!= TimerMap().end(), 0, wxT("bogus timer id in wxTimerProc") );
190 wxProcessTimer(*(node
->second
));
194 return ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
199 // ----------------------------------------------------------------------------
200 // wxTimerHiddenWindowModule functions
201 // ----------------------------------------------------------------------------
204 HWND
wxTimerHiddenWindowModule::ms_hwnd
= NULL
;
206 const wxChar
*wxTimerHiddenWindowModule::ms_className
= NULL
;
208 bool wxTimerHiddenWindowModule::OnInit()
210 // do not initialize ms_hwnd to ms_className to NULL here: it may happen
211 // that our GetHWND() is called before the modules are initialized if a
212 // timer is created from wxApp-derived class ctor and in this case we
213 // shouldn't overwrite it
218 void wxTimerHiddenWindowModule::OnExit()
222 if ( !::DestroyWindow(ms_hwnd
) )
224 wxLogLastError(wxT("DestroyWindow(wxTimerHiddenWindow)"));
232 if ( !::UnregisterClass(ms_className
, wxGetInstance()) )
234 wxLogLastError(wxT("UnregisterClass(\"wxTimerHiddenWindow\")"));
242 HWND
wxTimerHiddenWindowModule::GetHWND()
244 static const wxChar
*HIDDEN_WINDOW_CLASS
= wxT("wxTimerHiddenWindow");
247 ms_hwnd
= wxCreateHiddenWindow(&ms_className
, HIDDEN_WINDOW_CLASS
,
254 #endif // wxUSE_TIMER