added a generic mechanism for registering global handlers for custom windows messages and use it in wxFindReplaceDialog instead of subclassing the parent window, this solves the problem with having 2 find dialogs with the same parent (replaces patch 1447739)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45196 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2007-04-01 12:07:00 +00:00
parent 9cea4218b1
commit 5acec11245
3 changed files with 160 additions and 131 deletions

View File

@ -148,6 +148,29 @@ public:
// does this window have deferred position and/or size? // does this window have deferred position and/or size?
bool IsSizeDeferred() const; bool IsSizeDeferred() const;
// these functions allow to register a global handler for the given Windows
// message: it will be called from MSWWindowProc() of any window which gets
// this event if it's not processed before (i.e. unlike a hook procedure it
// does not override the normal processing)
//
// notice that if you want to process a message for a given window only you
// should override its MSWWindowProc() instead
// type of the handler: it is called with the message parameters (except
// that the window object is passed instead of window handle) and should
// return true if it handled the message or false if it should be passed to
// DefWindowProc()
typedef bool (*MSWMessageHandler)(wxWindow *win,
WXUINT nMsg,
WXWPARAM wParam,
WXLPARAM lParam);
// install a handler, shouldn't be called more than one for the same message
static bool MSWRegisterMessageHandler(int msg, MSWMessageHandler handler);
// unregister a previously registered handler
static void MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler);
// implementation from now on // implementation from now on
// ========================== // ==========================

View File

@ -40,9 +40,6 @@
// functions prototypes // functions prototypes
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg,
WPARAM wParam, LPARAM lParam);
UINT_PTR CALLBACK wxFindReplaceDialogHookProc(HWND hwnd, UINT_PTR CALLBACK wxFindReplaceDialogHookProc(HWND hwnd,
UINT uiMsg, UINT uiMsg,
WPARAM wParam, WPARAM wParam,
@ -67,10 +64,6 @@ public:
void InitFindWhat(const wxString& str); void InitFindWhat(const wxString& str);
void InitReplaceWith(const wxString& str); void InitReplaceWith(const wxString& str);
void SubclassDialog(HWND hwnd);
static UINT GetFindDialogMessage() { return ms_msgFindDialog; }
// only for passing to ::FindText or ::ReplaceText // only for passing to ::FindText or ::ReplaceText
FINDREPLACE *GetPtrFindReplace() { return &m_findReplace; } FINDREPLACE *GetPtrFindReplace() { return &m_findReplace; }
@ -79,13 +72,15 @@ public:
bool WasClosedByUser() const { return m_wasClosedByUser; } bool WasClosedByUser() const { return m_wasClosedByUser; }
private: private:
// called from window procedure for ms_msgFindDialog
static bool FindMessageHandler(wxWindow *win,
WXUINT nMsg,
WPARAM wParam,
LPARAM lParam);
// copy string str contents to ppStr and fill pLen with its length
void InitString(const wxString& str, LPTSTR *ppStr, WORD *pLen); void InitString(const wxString& str, LPTSTR *ppStr, WORD *pLen);
// the owner of the dialog
HWND m_hwndOwner;
// the previous window proc of our owner
WNDPROC m_oldParentWndProc;
// the find replace data used by the dialog // the find replace data used by the dialog
FINDREPLACE m_findReplace; FINDREPLACE m_findReplace;
@ -121,10 +116,13 @@ wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog *dialog,
{ {
wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)")); wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)"));
} }
}
m_hwndOwner = NULL; wxWindow::MSWRegisterMessageHandler
m_oldParentWndProc = NULL; (
ms_msgFindDialog,
&wxFindReplaceDialogImpl::FindMessageHandler
);
}
m_wasClosedByUser = false; m_wasClosedByUser = false;
@ -186,40 +184,21 @@ void wxFindReplaceDialogImpl::InitReplaceWith(const wxString& str)
&m_findReplace.wReplaceWithLen); &m_findReplace.wReplaceWithLen);
} }
void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd)
{
m_hwndOwner = hwnd;
// check that we don't subclass the parent twice: this would be a bad idea
// as then we'd have infinite recursion in wxFindReplaceWindowProc
wxCHECK_RET( wxGetWindowProc(hwnd) != &wxFindReplaceWindowProc,
_T("can't have more than one find dialog currently") );
// set the new one and save the old as user data to allow access to it
// from wxFindReplaceWindowProc
m_oldParentWndProc = wxSetWindowProc(hwnd, wxFindReplaceWindowProc);
wxSetWindowUserData(hwnd, (void *)m_oldParentWndProc);
}
wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl() wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
{ {
delete [] m_findReplace.lpstrFindWhat; delete [] m_findReplace.lpstrFindWhat;
delete [] m_findReplace.lpstrReplaceWith; delete [] m_findReplace.lpstrReplaceWith;
if ( m_hwndOwner )
{
// undo subclassing
wxSetWindowProc(m_hwndOwner, m_oldParentWndProc);
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Window Proc for handling RegisterWindowMessage(FINDMSGSTRING) // handler for FINDMSGSTRING message
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg, bool
WPARAM wParam, LPARAM lParam) wxFindReplaceDialogImpl::FindMessageHandler(wxWindow * WXUNUSED(win),
WXUINT WXUNUSED_UNLESS_DEBUG(nMsg),
WPARAM WXUNUSED(wParam),
LPARAM lParam)
{ {
#if wxUSE_UNICODE_MSLU #if wxUSE_UNICODE_MSLU
static unsigned long s_lastMsgFlags = 0; static unsigned long s_lastMsgFlags = 0;
@ -231,8 +210,8 @@ LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg,
static bool s_blockMsg = false; static bool s_blockMsg = false;
#endif // wxUSE_UNICODE_MSLU #endif // wxUSE_UNICODE_MSLU
if ( nMsg == wxFindReplaceDialogImpl::GetFindDialogMessage() ) wxASSERT_MSG( nMsg == ms_msgFindDialog, _T("unexpected message received") );
{
FINDREPLACE *pFR = (FINDREPLACE *)lParam; FINDREPLACE *pFR = (FINDREPLACE *)lParam;
#if wxUSE_UNICODE_MSLU #if wxUSE_UNICODE_MSLU
@ -312,19 +291,8 @@ LRESULT CALLBACK wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg,
#if wxUSE_UNICODE_MSLU #if wxUSE_UNICODE_MSLU
s_blockMsg = false; s_blockMsg = false;
#endif // wxUSE_UNICODE_MSLU #endif // wxUSE_UNICODE_MSLU
}
#if wxUSE_UNICODE_MSLU
else if ( !s_blockMsg )
s_lastMsgFlags = 0;
#endif // wxUSE_UNICODE_MSLU
WNDPROC wndProc = (WNDPROC)wxGetWindowUserData(hwnd); return true;
// sanity check
wxASSERT_MSG( wndProc != wxFindReplaceWindowProc,
_T("infinite recursion detected") );
return ::CallWindowProc(wndProc, hwnd, nMsg, wParam, lParam);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -478,9 +446,6 @@ bool wxFindReplaceDialog::Show(bool show)
return false; return false;
} }
// subclass parent window in order to get FINDMSGSTRING message
m_impl->SubclassDialog(GetHwndOf(m_parent));
if ( !::ShowWindow(hwnd, SW_SHOW) ) if ( !::ShowWindow(hwnd, SW_SHOW) )
{ {
wxLogLastError(_T("ShowWindow(find dialog)")); wxLogLastError(_T("ShowWindow(find dialog)"));

View File

@ -57,6 +57,7 @@
#include "wx/ownerdrw.h" #include "wx/ownerdrw.h"
#endif #endif
#include "wx/hashmap.h"
#include "wx/evtloop.h" #include "wx/evtloop.h"
#include "wx/power.h" #include "wx/power.h"
#include "wx/sysopt.h" #include "wx/sysopt.h"
@ -172,6 +173,13 @@ static struct MouseEventInfoDummy
} gs_lastMouseEvent; } gs_lastMouseEvent;
#endif // wxUSE_MOUSEEVENT_HACK #endif // wxUSE_MOUSEEVENT_HACK
// hash containing the registered handlers for the custom messages
WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
wxIntegerHash, wxIntegerEqual,
MSWMessageHandlers);
static MSWMessageHandlers gs_messageHandlers;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// private functions // private functions
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -3173,6 +3181,15 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
} }
break; break;
#endif // __WXWINCE__ #endif // __WXWINCE__
default:
// try a custom message handler
const MSWMessageHandlers::const_iterator
i = gs_messageHandlers.find(message);
if ( i != gs_messageHandlers.end() )
{
processed = (*i->second)(this, message, wParam, lParam);
}
} }
if ( !processed ) if ( !processed )
@ -5439,6 +5456,30 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
return GetEventHandler()->ProcessEvent(event); return GetEventHandler()->ProcessEvent(event);
} }
// ----------------------------------------------------------------------------
// custom message handlers
// ----------------------------------------------------------------------------
/* static */ bool
wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
{
wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
false, _T("registering handler for the same message twice") );
gs_messageHandlers[msg] = handler;
return true;
}
/* static */ void
wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
{
const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
_T("unregistering non-registered handler?") );
gs_messageHandlers.erase(i);
}
// =========================================================================== // ===========================================================================
// global functions // global functions
// =========================================================================== // ===========================================================================