From: Vadim Zeitlin Date: Tue, 23 Sep 2003 23:57:32 +0000 (+0000) Subject: refactored code to create hidden window in one place only; use it from wxTimer; unreg... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/eccd1992237c9b8bbe02a9eda66b709fd7ecea73 refactored code to create hidden window in one place only; use it from wxTimer; unregister class used by wxExecute (modified patch 782947) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23868 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index f44fd0cefb..2051e5d57c 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -63,6 +63,7 @@ wxMSW: - wxRadioButtons are now checked when they get focus (standard behaviour) - several fixes to owner drawn menu items (Christian Sturmlechner) - wxGauge now supports full 32 bit range (Miroslav Rajcic) +- use proper window with wxTimer (Jaakko Salli) wxGTK: diff --git a/include/wx/msw/timer.h b/include/wx/msw/timer.h index 116e02e303..7cca85b1fa 100644 --- a/include/wx/msw/timer.h +++ b/include/wx/msw/timer.h @@ -35,6 +35,7 @@ protected: void Init(); long m_id; + WXHWND m_hwnd; private: DECLARE_DYNAMIC_CLASS_NO_COPY(wxTimer) diff --git a/src/msw/gsockmsw.c b/src/msw/gsockmsw.c index 7bc845bed0..96b237f104 100644 --- a/src/msw/gsockmsw.c +++ b/src/msw/gsockmsw.c @@ -84,7 +84,10 @@ HINSTANCE wxGetInstance(void); #endif #define CLASSNAME TEXT("_GSocket_Internal_Window_Class") -#define WINDOWNAME TEXT("_GSocket_Internal_Window_Name") + +/* implemented in utils.cpp */ +extern HWND +wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc); /* Maximum number of different GSocket objects at a given time. * This value can be modified at will, but it CANNOT be greater @@ -109,28 +112,13 @@ static int firstAvailable; int _GSocket_GUI_Init(void) { - WNDCLASS winClass; + LPCTSTR pclassname; int i; /* Create internal window for event notifications */ - winClass.style = 0; - winClass.lpfnWndProc = _GSocket_Internal_WinProc; - winClass.cbClsExtra = 0; - winClass.cbWndExtra = 0; - winClass.hInstance = INSTANCE; - winClass.hIcon = (HICON) NULL; - winClass.hCursor = (HCURSOR) NULL; - winClass.hbrBackground = (HBRUSH) NULL; - winClass.lpszMenuName = (LPCTSTR) NULL; - winClass.lpszClassName = CLASSNAME; - - RegisterClass(&winClass); - hWin = CreateWindow(CLASSNAME, - WINDOWNAME, - 0, 0, 0, 0, 0, - (HWND) NULL, (HMENU) NULL, INSTANCE, (LPVOID) NULL); - - if (!hWin) return FALSE; + hWin = wxCreateHiddenWindow(&pclassname, CLASSNAME, _GSocket_Internal_WinProc); + if (!hWin) + return FALSE; /* Initialize socket list */ InitializeCriticalSection(&critical); @@ -141,7 +129,7 @@ int _GSocket_GUI_Init(void) } firstAvailable = 0; - return 1; + return TRUE; } void _GSocket_GUI_Cleanup(void) diff --git a/src/msw/timer.cpp b/src/msw/timer.cpp index cccb8ed09f..09f830cd95 100644 --- a/src/msw/timer.cpp +++ b/src/msw/timer.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: timer.cpp +// Name: msw/timer.cpp // Purpose: wxTimer implementation // Author: Julian Smart // Modified by: @@ -32,11 +32,16 @@ #endif #include "wx/hashmap.h" +#include "wx/module.h" #include "wx/timer.h" #include "wx/msw/private.h" +// from utils.cpp +extern "C" HWND +wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc); + // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -55,13 +60,45 @@ void WINAPI wxTimerProc(HWND hwnd, WORD, int idTimer, DWORD); // macros // ---------------------------------------------------------------------------- -// should probably be in wx/msw/missing.h -#ifdef __WXMICROWIN__ - #define MakeProcInstance(proc, hinst) proc -#endif - IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxObject) +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +// these variables are for timer shared hwnd management +static const wxChar *wxMSWTIMER_WNDCLASSNAME = wxT("_wxTimer_Internal_Class"); +static LPCTSTR s_classnameTimerWnd = NULL; +static HWND s_hwndTimer = NULL; + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxTimerModule : public wxModule +{ +public: + virtual bool OnInit() { return true; } + virtual void OnExit() + { + if ( s_hwndTimer ) + { + ::DestroyWindow(s_hwndTimer); + s_hwndTimer = NULL; + + if ( !::UnregisterClass(wxMSWTIMER_WNDCLASSNAME, wxGetInstance()) ) + { + wxLogLastError(_T("UnregisterClass(wxTimerClass)")); + } + + s_classnameTimerWnd = NULL; + } + } + +private: + DECLARE_DYNAMIC_CLASS(wxTimerModule) +}; + // ============================================================================ // implementation // ============================================================================ @@ -73,10 +110,12 @@ IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxObject) void wxTimer::Init() { m_id = 0; + m_hwnd = NULL; } wxTimer::~wxTimer() { + // save id as Stop() changes it long id = m_id; wxTimer::Stop(); @@ -86,40 +125,74 @@ wxTimer::~wxTimer() bool wxTimer::Start(int milliseconds, bool oneShot) { - (void)wxTimerBase::Start(milliseconds, oneShot); - wxCHECK_MSG( m_milli > 0, false, wxT("invalid value for timer timeour") ); -#ifdef __WXWINCE__ - m_id = ::SetTimer(NULL, (UINT)(m_id ? m_id : 1), - (UINT)m_milli, (TIMERPROC) wxTimerProc); -#else - TIMERPROC wxTimerProcInst = (TIMERPROC) - MakeProcInstance((FARPROC)wxTimerProc, wxGetInstance()); + (void)wxTimerBase::Start(milliseconds, oneShot); - m_id = ::SetTimer(NULL, (UINT)(m_id ? m_id : 1), - (UINT)m_milli, wxTimerProcInst); -#endif + // find a window for SetTimer(): it should be a valid HWND owned by this + // thread (even if we had a non NULL m_hwnd before, reset it in case the + // owner has changed) + m_hwnd = NULL; - if ( m_id > 0 ) + // first try the owner window + if ( m_owner ) { - wxTimerList[m_id] = this; + wxWindow *win = wxDynamicCast(m_owner, wxWindow); + if ( win ) + { + m_hwnd = win->GetHWND(); + } + } + + // if not, use a shared hidden window + if ( !m_hwnd ) + { + if ( !s_hwndTimer ) + { + s_hwndTimer = wxCreateHiddenWindow + ( + &s_classnameTimerWnd, + wxMSWTIMER_WNDCLASSNAME, + ::DefWindowProc + ); + + if ( !s_hwndTimer ) + { + wxASSERT_MSG( s_hwndTimer, wxT("can't create a HWND for wxTimer") ); + return false; + } + } + + m_hwnd = (WXHWND)s_hwndTimer; - return true; } - else + + m_id = ::SetTimer + ( + (HWND)m_hwnd, + (UINT)(m_id ? m_id : 1), + (UINT)m_milli, + (TIMERPROC)wxTimerProc + ); + + if ( !m_id ) { wxLogSysError(_("Couldn't create a timer")); return false; } + + wxTimerList[m_id] = this; + + return true; } void wxTimer::Stop() { if ( m_id ) { - ::KillTimer(NULL, (UINT)m_id); + ::KillTimer((HWND)m_hwnd, (UINT)m_id); + m_hwnd = NULL; wxTimerList.erase(m_id); } @@ -145,7 +218,6 @@ void wxProcessTimer(wxTimer& timer) void WINAPI wxTimerProc(HWND WXUNUSED(hwnd), WORD, int idTimer, DWORD) { - wxTimerMap::iterator node = wxTimerList.find((long)idTimer); wxASSERT_MSG( node != wxTimerList.end(), wxT("bogus timer id in wxTimerProc") ); diff --git a/src/msw/utils.cpp b/src/msw/utils.cpp index 97f1369e3c..8e5fab3265 100644 --- a/src/msw/utils.cpp +++ b/src/msw/utils.cpp @@ -1052,12 +1052,12 @@ wxToolkitInfo& wxAppTraits::GetToolkitInfo() case VER_PLATFORM_WIN32_CE: s_ver = wxWINDOWS_CE; break; -#endif +#endif } } } - static wxToolkitInfo info; + static wxToolkitInfo info; info.versionMajor = s_major; info.versionMinor = s_minor; info.os = s_ver; @@ -1232,3 +1232,62 @@ extern long wxCharsetToCodepage(const wxChar *name) #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP +/* + Creates a hidden window with supplied window proc registering the class for + it if necesssary (i.e. the first time only). Caller is responsible for + destroying the window and unregistering the class (note that this must be + done because wxWindows may be used as a DLL and so may be loaded/unloaded + multiple times into/from the same process so we cna't rely on automatic + Windows class unregistration). + + pclassname is a pointer to a caller stored classname, which must initially be + NULL. classname is the desired wndclass classname. If function succesfully + registers the class, pclassname will be set to classname. + */ +extern "C" HWND +wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc) +{ + wxCHECK_MSG( classname && pclassname && wndproc, NULL, + _T("NULL parameter in wxCreateHiddenWindow") ); + + // register the class fi we need to first + if ( *pclassname == NULL ) + { + WNDCLASS wndclass; + wxZeroMemory(wndclass); + + wndclass.lpfnWndProc = wndproc; + wndclass.hInstance = wxGetInstance(); + wndclass.lpszClassName = classname; + + if ( !::RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass() in wxCreateHiddenWindow")); + + return NULL; + } + + *pclassname = classname; + } + + // next create the window + HWND hwnd = ::CreateWindow + ( + *pclassname, + NULL, + 0, 0, 0, 0, + 0, + (HWND) NULL, + (HMENU)NULL, + wxGetInstance(), + (LPVOID) NULL + ); + + if ( !hwnd ) + { + wxLogLastError(wxT("CreateWindow() in wxCreateHiddenWindow")); + } + + return hwnd; +} + diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 7046329ee5..b2fbf1d060 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -35,13 +35,13 @@ #include "wx/log.h" #endif -#ifdef __WIN32__ - #include "wx/stream.h" - #include "wx/process.h" -#endif +#include "wx/stream.h" +#include "wx/process.h" #include "wx/apptrait.h" +#include "wx/module.h" + #include "wx/msw/private.h" #include @@ -58,14 +58,14 @@ #include #endif -#if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) -#ifndef __UNIX__ - #include -#endif +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + #ifndef __UNIX__ + #include + #endif -#ifndef __GNUWIN32__ -#include -#endif + #ifndef __GNUWIN32__ + #include + #endif #endif #include @@ -82,6 +82,10 @@ #include "wx/dde.h" // for WX_DDE hack in wxExecute #endif // wxUSE_IPC +// implemented in utils.cpp +extern "C" HWND +wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc); + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -96,6 +100,7 @@ // we need to create a hidden window to receive the process termination // notifications and for this we need a (Win) class name for it which we will // register the first time it's needed +static const wxChar *wxMSWEXEC_WNDCLASSNAME = wxT("_wxExecute_Internal_Class"); static const wxChar *gs_classForHiddenWindow = NULL; // ---------------------------------------------------------------------------- @@ -124,7 +129,28 @@ public: bool state; // set to FALSE when the process finishes }; -#if defined(__WIN32__) && wxUSE_STREAMS && !defined(__WXWINCE__) +class wxExecuteModule : public wxModule +{ +public: + virtual bool OnInit() { return true; } + virtual void OnExit() + { + if ( *gs_classForHiddenWindow ) + { + if ( !::UnregisterClass(wxMSWEXEC_WNDCLASSNAME, wxGetInstance()) ) + { + wxLogLastError(_T("UnregisterClass(wxExecClass)")); + } + + gs_classForHiddenWindow = NULL; + } + } + +private: + DECLARE_DYNAMIC_CLASS(wxExecuteModule) +}; + +#if wxUSE_STREAMS && !defined(__WXWINCE__) // ---------------------------------------------------------------------------- // wxPipeStreams @@ -258,8 +284,6 @@ private: // implementation // ============================================================================ -#ifdef __WIN32__ - // ---------------------------------------------------------------------------- // process termination detecting support // ---------------------------------------------------------------------------- @@ -438,8 +462,6 @@ size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len) #endif // wxUSE_STREAMS -#endif // Win32 - // ============================================================================ // wxExecute functions family // ============================================================================ @@ -738,36 +760,15 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler) } #endif // wxUSE_STREAMS - // register the class for the hidden window used for the notifications - if ( !gs_classForHiddenWindow ) - { - gs_classForHiddenWindow = _T("wxHiddenWindow"); - - WNDCLASS wndclass; - wxZeroMemory(wndclass); - wndclass.lpfnWndProc = (WNDPROC)wxExecuteWindowCbk; - wndclass.hInstance = wxGetInstance(); - wndclass.lpszClassName = gs_classForHiddenWindow; - - if ( !::RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(hidden window)")); - } - } - // create a hidden window to receive notification about process // termination -#ifdef __WXWINCE__ - HWND hwnd = ::CreateWindow(gs_classForHiddenWindow, NULL, - WS_OVERLAPPED, - 0, 0, 0, 0, NULL, - (HMENU)NULL, wxGetInstance(), 0); -#else - HWND hwnd = ::CreateWindow(gs_classForHiddenWindow, NULL, - WS_OVERLAPPEDWINDOW, - 0, 0, 0, 0, NULL, - (HMENU)NULL, wxGetInstance(), 0); -#endif + HWND hwnd = wxCreateHiddenWindow + ( + &gs_classForHiddenWindow, + wxMSWEXEC_WNDCLASSNAME, + (WNDPROC)wxExecuteWindowCbk + ); + wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") ); // Alloc data